Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 504 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim Free Moo | 16214897 | 700 days ago | IN | 0 ETH | 0.00075204 | ||||
Mint Spy From Mo... | 16208479 | 701 days ago | IN | 0 ETH | 0.00375461 | ||||
Claim Free Moo | 16208472 | 701 days ago | IN | 0 ETH | 0.001329 | ||||
Mint Knife From ... | 16203678 | 702 days ago | IN | 0 ETH | 0.00266782 | ||||
Mint Spy From Mo... | 16203676 | 702 days ago | IN | 0 ETH | 0.00268647 | ||||
Mint Spy From Mo... | 16203673 | 702 days ago | IN | 0 ETH | 0.00228203 | ||||
Mint Spy From Mo... | 16203671 | 702 days ago | IN | 0 ETH | 0.00244551 | ||||
Mint Spy From Mo... | 16203669 | 702 days ago | IN | 0 ETH | 0.00244121 | ||||
Kill Spy | 16202417 | 702 days ago | IN | 0 ETH | 0.00238281 | ||||
Mint Knife From ... | 16202402 | 702 days ago | IN | 0 ETH | 0.00240335 | ||||
Mint Spy From Mo... | 16201692 | 702 days ago | IN | 0 ETH | 0.002474 | ||||
Mint Spy From Mo... | 16201680 | 702 days ago | IN | 0 ETH | 0.00274786 | ||||
Mint Spy From Mo... | 16201677 | 702 days ago | IN | 0 ETH | 0.00247238 | ||||
Claim Free Moo | 16201674 | 702 days ago | IN | 0 ETH | 0.00089842 | ||||
Mint Spy From Mo... | 16201334 | 702 days ago | IN | 0 ETH | 0.00282564 | ||||
Mint Spy From Mo... | 16201329 | 702 days ago | IN | 0 ETH | 0.00279051 | ||||
Mint Spy From Mo... | 16201130 | 702 days ago | IN | 0 ETH | 0.00268693 | ||||
Mint Spy From Mo... | 16201129 | 702 days ago | IN | 0 ETH | 0.00474946 | ||||
Mint Spy From Mo... | 16201126 | 702 days ago | IN | 0 ETH | 0.00452065 | ||||
Mint Spy From Mo... | 16201124 | 702 days ago | IN | 0 ETH | 0.00252974 | ||||
Mint Spy From Mo... | 16201121 | 702 days ago | IN | 0 ETH | 0.0025812 | ||||
Claim Free Moo | 16201104 | 702 days ago | IN | 0 ETH | 0.0008741 | ||||
Mint Spy From Mo... | 16201007 | 702 days ago | IN | 0 ETH | 0.00291621 | ||||
Mint Spy From Mo... | 16200996 | 702 days ago | IN | 0 ETH | 0.00387005 | ||||
Mint Spy From Mo... | 16200963 | 702 days ago | IN | 0 ETH | 0.00288803 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
16200134 | 702 days ago | 0.1 ETH | ||||
16199959 | 702 days ago | 0.1 ETH | ||||
16199476 | 702 days ago | 0.1 ETH | ||||
16199407 | 702 days ago | 0.1 ETH | ||||
16199203 | 702 days ago | 0.1 ETH | ||||
16199193 | 702 days ago | 0.3 ETH | ||||
16199169 | 702 days ago | 0.1 ETH | ||||
16199154 | 702 days ago | 0.1 ETH | ||||
16199122 | 702 days ago | 0.1 ETH | ||||
16199121 | 702 days ago | 0.05 ETH | ||||
16199118 | 702 days ago | 0.1 ETH | ||||
16199026 | 702 days ago | 0.1 ETH | ||||
16198990 | 702 days ago | 0.1 ETH | ||||
16198921 | 702 days ago | 0.1 ETH | ||||
16198898 | 702 days ago | 0.1 ETH | ||||
16198879 | 702 days ago | 0.1 ETH | ||||
16198800 | 702 days ago | 0.1 ETH | ||||
16198764 | 702 days ago | 0.1 ETH | ||||
16198725 | 702 days ago | 0.1 ETH | ||||
16198708 | 702 days ago | 0.1 ETH | ||||
16198693 | 702 days ago | 0.1 ETH | ||||
16198677 | 702 days ago | 0.1 ETH | ||||
16198663 | 702 days ago | 0.1 ETH | ||||
16198662 | 702 days ago | 0.1 ETH | ||||
16198627 | 702 days ago | 0.1 ETH |
Loading...
Loading
Contract Name:
KnifeGame
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {ERC20} from "@openzeppelin/token/ERC20/ERC20.sol"; import {ERC721Holder} from "@openzeppelin/token/ERC721/utils/ERC721Holder.sol"; import {toWadUnsafe, toDaysWadUnsafe} from "solmate/utils/SignedWadMath.sol"; import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; import {LibGOO} from "goo-issuance/LibGOO.sol"; import {LVRGDA} from "./LVRGDA.sol"; import {KnifeNFT, SpyNFT, GooBalanceUpdateType} from "./NFT.sol"; /// @title Knife Game Logic /// @author Libevm <[email protected]> /// @notice A funny game contract KnifeGame is ERC721Holder { using FixedPointMathLib for uint256; /*////////////////////////////////////////////////////////////// ADDRESSES //////////////////////////////////////////////////////////////*/ /// @notice The address of the SPY NFT contract SpyNFT public immutable spyNFT; /// @notice The address of the Knives NFT contract KnifeNFT public immutable knifeNFT; /// @notice Prices curves for the NFTs LVRGDA public spyLVRGDA; LVRGDA public knifeLVRGDA; /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /// @notice Safe multisig knifegamexyz.eth address public constant MULTISIG = 0x503C42470951B7c163730fD8b67EA66FECd8c774; /// @notice knife-game-treasury address public constant SHOUTS_FUNDS_RECIPIENT = 0xDb42214E11bF1d49df83D311c3d88AaCDE666243; /// @notice Burn address address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; /// @notice How much $$ per user uint256 public constant INITIAL_PURCHASE_SPY_ETH_PRICE = 0.1 ether; /*////////////////////////////////////////////////////////////// GAME VARIABLES //////////////////////////////////////////////////////////////*/ /// @notice Timestamp for the start of minting. uint256 public immutable gameStart; /// @notice Number of spies minted from moo. uint128 public spiesMintedFromMoo; /// @notice Number of knives minted from moo. uint128 public knivesMintedFromMoo; /// @notice Number of purchases per day (after game) mapping(address => mapping(uint256 => uint256)) public userPurchasesOnDay; /// @notice Have the users purchased pre-game mapping(address => bool) public hasUserPrepurchased; /// @notice Have the users claimed free MOO tokens pre-game mapping(address => bool) public hasUserClaimedFreeMooTokens; /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ error TooEarly(); error TooLate(); error TooPoor(); error DumbMove(); error NotOwner(); error NoWhales(); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Shouted(address indexed sender, string message); event SpyMinted(address indexed recipient, uint256 indexed id); event SpyPurchased(address indexed recipient, uint256 indexed id, uint256 price); event SpyKilled(address indexed hitman, address indexed victim, uint256 knifeId, uint256 spyId); event KnifePurchased(address indexed recipient, uint256 indexed id, uint256 price); /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(uint256 _gameStart, address _spyNft, address _knifeNFT) { // Time gameStart = _gameStart; // NFTs spyNFT = SpyNFT(_spyNft); knifeNFT = KnifeNFT(_knifeNFT); // Price curves spyLVRGDA = new LVRGDA( 6.9e18, // Target price 0.5e18, // Price decay percent toWadUnsafe(19000), 0.3e18 // Time scale. ); knifeLVRGDA = new LVRGDA( 8.0085e18, // Target price 0.6e18, // Price decay percent toWadUnsafe(40000), 0.22e18 // Time scale. ); } /*////////////////////////////////////////////////////////////// Permissioned //////////////////////////////////////////////////////////////*/ function updateSpyVRGDA(int256 _targetPrice, int256 _priceDecayPercent, uint256 _maxAmount, int256 _timeScale) public { // Only multisig can change if (msg.sender != MULTISIG) revert NotOwner(); // Can't change after game starts if (block.timestamp >= gameStart) revert TooLate(); spyLVRGDA = new LVRGDA( _targetPrice, _priceDecayPercent, toWadUnsafe(_maxAmount), _timeScale ); } function updateKnifeVRGDA(int256 _targetPrice, int256 _priceDecayPercent, uint256 _maxAmount, int256 _timeScale) public { // Only multisig can change if (msg.sender != MULTISIG) revert NotOwner(); // Can't change after game starts if (block.timestamp > gameStart) revert TooLate(); knifeLVRGDA = new LVRGDA( _targetPrice, _priceDecayPercent, toWadUnsafe(_maxAmount), _timeScale ); } /*////////////////////////////////////////////////////////////// Minting Logic //////////////////////////////////////////////////////////////*/ function claimFreeMoo() external { // Only claimable after game starts if (block.timestamp < gameStart) revert TooEarly(); // Only users who have pre purchased can claim if (!hasUserPrepurchased[msg.sender]) revert DumbMove(); // Cannot claim twice if (hasUserClaimedFreeMooTokens[msg.sender]) revert DumbMove(); hasUserClaimedFreeMooTokens[msg.sender] = true; // 10 free moo! spyNFT.updateUserGooBalance(msg.sender, 10e18, GooBalanceUpdateType.INCREASE); } /// @notice Buys a spy with ETH, pricing exponentially increases once game starts function purchaseSpy() external payable returns (uint256 spyId) { // Don't be cheap if (msg.value < spyPriceETH(msg.sender)) revert TooPoor(); // Only can purchase 1 spy pre game start if (block.timestamp < gameStart) { // Revert if user has purchased if (hasUserPrepurchased[msg.sender]) revert NoWhales(); // Set purchased hasUserPrepurchased[msg.sender] = true; } else if (block.timestamp >= gameStart) { // Add purchase count userPurchasesOnDay[msg.sender][uint256(toDaysWadUnsafe(block.timestamp - gameStart) / 1e18)]++; } MULTISIG.call{value: msg.value}(""); spyId = spyNFT.mint(msg.sender, block.timestamp > gameStart ? block.timestamp : gameStart); unchecked { emit SpyMinted(msg.sender, spyId); } } /// @notice Mints a Spy using Moolah function mintSpyFromMoolah(uint256 _maxPrice) external returns (uint256 spyId) { // If game has not begun, revert if (block.timestamp < gameStart) revert TooEarly(); // No need to check if we're at MAX_MINTABLE // spyPrice() will revert once we reach it due to its // logistic nature. It will also revert prior to the mint start uint256 currentPrice = spyPrice(); // If the current price is above the user's specified max, revert if (currentPrice > _maxPrice) revert TooPoor(); // Decrement the user's goo by the ERC20 balance spyNFT.updateUserGooBalance(msg.sender, currentPrice, GooBalanceUpdateType.DECREASE); spyId = spyNFT.mint(msg.sender, block.timestamp > gameStart ? block.timestamp : gameStart); unchecked { ++spiesMintedFromMoo; // Overflow should be impossible due to the supply cap emit SpyPurchased(msg.sender, spyId, currentPrice); } } /// @notice Mints a Knife using Moolah function mintKnifeFromMoolah(uint256 _maxPrice) external returns (uint256 knifeId) { // If game has not begun, revert if (block.timestamp < gameStart) revert TooEarly(); // No need to check if we're at MAX_MINTABLE // spyPrice() will revert once we reach it due to its // logistic nature. It will also revert prior to the mint start uint256 currentPrice = knifePrice(); // If the current price is above the user's specified max, revert if (currentPrice > _maxPrice) revert TooPoor(); // Decrement the user's goo by the virtual balance or ERC20 balance spyNFT.updateUserGooBalance(msg.sender, currentPrice, GooBalanceUpdateType.DECREASE); knifeId = knifeNFT.mint(msg.sender); unchecked { ++knivesMintedFromMoo; // Overflow should be impossible due to the supply cap emit KnifePurchased(msg.sender, knifeId, currentPrice); } } /*////////////////////////////////////////////////////////////// Pricing Logic //////////////////////////////////////////////////////////////*/ /// @notice Spy pricing in terms of ETH /// @dev Allows people to buy Spies after the game has started /// but disincentivies them to do so as it gets exponentially more expensive once the game starts /// @return Current price of a spy in terms of ETH for a particular user function spyPriceETH(address _user) public view returns (uint256) { // If the game hasn't started, its a flat rate if (block.timestamp < gameStart) return INITIAL_PURCHASE_SPY_ETH_PRICE; // How many days since game started, and how many spies have user *purchased* on this day uint256 daysSinceGameStarted = uint256(toDaysWadUnsafe(block.timestamp - gameStart) / 1e18); uint256 userPurchased = userPurchasesOnDay[_user][daysSinceGameStarted]; // Magic algorithm uint256 priceIncrease = 0; for (uint256 i = 0; i < userPurchased; i++) { if (priceIncrease == 0) { priceIncrease = INITIAL_PURCHASE_SPY_ETH_PRICE; } priceIncrease = priceIncrease * 2; } return INITIAL_PURCHASE_SPY_ETH_PRICE + priceIncrease; } /// @notice Spy pricing in terms of moolah. /// @dev Will revert if called before minting starts /// or after all gobblers have been minted via VRGDA. /// @return Current price of a gobbler in terms of goo. function spyPrice() public view returns (uint256) { // We need checked math here to cause underflow // before minting has begun, preventing mints. uint256 timeSinceStart = block.timestamp - gameStart; return spyLVRGDA.getVRGDAPrice(toDaysWadUnsafe(timeSinceStart), spiesMintedFromMoo); } /// @notice Knife pricing in terms of moolah. /// @dev Will revert if called before minting starts /// or after all gobblers have been minted via VRGDA. /// @return Current price of a gobbler in terms of goo. function knifePrice() public view returns (uint256) { // We need checked math here to cause underflow // before minting has begun, preventing mints. uint256 timeSinceStart = block.timestamp - (gameStart + 12 hours); return knifeLVRGDA.getVRGDAPrice(toDaysWadUnsafe(timeSinceStart), knivesMintedFromMoo); } /*////////////////////////////////////////////////////////////// Add/Remove GOO Logic //////////////////////////////////////////////////////////////*/ // /// @notice Add goo to your emission balance, // /// burning the corresponding ERC20 balance. // /// @param _mooAmount The amount of moo to add. // function addMoo(uint256 _mooAmount) external { // // Burn goo being added to gobbler. // moo.burn(msg.sender, _mooAmount); // // Increase msg.sender's virtual goo balance. // spyNFT.updateUserGooBalance(msg.sender, _mooAmount, GooBalanceUpdateType.INCREASE); // } // /// @notice Remove goo from your emission balance, and // /// add the corresponding amount to your ERC20 balance. // /// @param _mooAmount The amount of moo to remove. // function removeMoo(uint256 _mooAmount) external { // // Decrease msg.sender's virtual goo balance. // spyNFT.updateUserGooBalance(msg.sender, _mooAmount, GooBalanceUpdateType.DECREASE); // // Mint the corresponding amount of ERC20 goo. // moo.mint(msg.sender, _mooAmount); // } /*////////////////////////////////////////////////////////////// Game Logic //////////////////////////////////////////////////////////////*/ function killSpy(uint256 _knifeId, uint256 _spyId) public { // Make sure user owns the knife if (knifeNFT.ownerOf(_knifeId) != msg.sender) revert NotOwner(); // Cannot kill burn address if (spyNFT.ownerOf(_spyId) == BURN_ADDRESS) revert DumbMove(); // Literally retarded if (knifeNFT.ownerOf(_knifeId) == spyNFT.ownerOf(_spyId)) { revert DumbMove(); } knifeNFT.sudoTransferFrom(msg.sender, BURN_ADDRESS, _knifeId); address victim = spyNFT.ownerOf(_spyId); spyNFT.sudoTransferFrom(victim, BURN_ADDRESS, _spyId); emit SpyKilled(msg.sender, victim, _knifeId, _spyId); } // For world chat functionality function shout(string calldata message) external payable { if (msg.value < 0.05e18) revert TooPoor(); SHOUTS_FUNDS_RECIPIENT.call{value: msg.value}(""); if (bytes(message).length > 256) { emit Shouted(msg.sender, string(message[:256])); } else { emit Shouted(msg.sender, message); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {wadLn, unsafeDiv, unsafeWadDiv} from "solmate/utils/SignedWadMath.sol"; import {VRGDA} from "./VRGDA.sol"; /// @title Logistic Variable Rate Gradual Dutch Auction /// @author transmissions11 <[email protected]> /// @author FrankieIsLost <[email protected]> /// @notice VRGDA with a logistic issuance curve. abstract contract LogisticVRGDA is VRGDA { /*////////////////////////////////////////////////////////////// PRICING PARAMETERS //////////////////////////////////////////////////////////////*/ /// @dev The maximum number of tokens of tokens to sell + 1. We add /// 1 because the logistic function will never fully reach its limit. /// @dev Represented as an 18 decimal fixed point number. int256 internal immutable logisticLimit; /// @dev The maximum number of tokens of tokens to sell + 1 multiplied /// by 2. We could compute it on the fly each time but this saves gas. /// @dev Represented as a 36 decimal fixed point number. int256 internal immutable logisticLimitDoubled; /// @dev Time scale controls the steepness of the logistic curve, /// which affects how quickly we will reach the curve's asymptote. /// @dev Represented as an 18 decimal fixed point number. int256 internal immutable timeScale; /// @notice Sets pricing parameters for the VRGDA. /// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18. /// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18. /// @param _maxSellable The maximum number of tokens to sell, scaled by 1e18. /// @param _timeScale The steepness of the logistic curve, scaled by 1e18. constructor( int256 _targetPrice, int256 _priceDecayPercent, int256 _maxSellable, int256 _timeScale ) VRGDA(_targetPrice, _priceDecayPercent) { // Add 1 wad to make the limit inclusive of _maxSellable. logisticLimit = _maxSellable + 1e18; // Scale by 2e18 to both double it and give it 36 decimals. logisticLimitDoubled = logisticLimit * 2e18; timeScale = _timeScale; } /*////////////////////////////////////////////////////////////// PRICING LOGIC //////////////////////////////////////////////////////////////*/ /// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by. /// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for. /// @return The target time the tokens should be sold by, scaled by 1e18, where the time is /// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins. function getTargetSaleTime(int256 sold) public view virtual override returns (int256) { unchecked { return -unsafeWadDiv(wadLn(unsafeDiv(logisticLimitDoubled, sold + logisticLimit) - 1e18), timeScale); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {wadExp, wadLn, wadMul, unsafeWadMul, toWadUnsafe} from "solmate/utils/SignedWadMath.sol"; /// @title Variable Rate Gradual Dutch Auction /// @author transmissions11 <[email protected]> /// @author FrankieIsLost <[email protected]> /// @notice Sell tokens roughly according to an issuance schedule. abstract contract VRGDA { /*////////////////////////////////////////////////////////////// VRGDA PARAMETERS //////////////////////////////////////////////////////////////*/ /// @notice Target price for a token, to be scaled according to sales pace. /// @dev Represented as an 18 decimal fixed point number. int256 public immutable targetPrice; /// @dev Precomputed constant that allows us to rewrite a pow() as an exp(). /// @dev Represented as an 18 decimal fixed point number. int256 internal immutable decayConstant; /// @notice Sets target price and per time unit price decay for the VRGDA. /// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18. /// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18. constructor(int256 _targetPrice, int256 _priceDecayPercent) { targetPrice = _targetPrice; decayConstant = wadLn(1e18 - _priceDecayPercent); // The decay constant must be negative for VRGDAs to work. require(decayConstant < 0, "NON_NEGATIVE_DECAY_CONSTANT"); } /*////////////////////////////////////////////////////////////// PRICING LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Calculate the price of a token according to the VRGDA formula. /// @param timeSinceStart Time passed since the VRGDA began, scaled by 1e18. /// @param sold The total number of tokens that have been sold so far. /// @return The price of a token according to VRGDA, scaled by 1e18. function getVRGDAPrice(int256 timeSinceStart, uint256 sold) public view virtual returns (uint256) { unchecked { // prettier-ignore return uint256(wadMul(targetPrice, wadExp(unsafeWadMul(decayConstant, // Theoretically calling toWadUnsafe with sold can silently overflow but under // any reasonable circumstance it will never be large enough. We use sold + 1 as // the VRGDA formula's n param represents the nth token and sold is the n-1th token. timeSinceStart - getTargetSaleTime(toWadUnsafe(sold + 1)) )))); } } /// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by. /// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for. /// @return The target time the tokens should be sold by, scaled by 1e18, where the time is /// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins. function getTargetSaleTime(int256 sold) public view virtual returns (int256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; /// @title GOO (Gradual Ownership Optimization) Issuance /// @author transmissions11 <[email protected]> /// @author FrankieIsLost <[email protected]> /// @notice Implementation of the GOO Issuance mechanism. library LibGOO { using FixedPointMathLib for uint256; /// @notice Compute goo balance based on emission multiple, last balance, and time elapsed. /// @param emissionMultiple The multiple on emissions to consider when computing the balance. /// @param lastBalanceWad The last checkpointed balance to apply the emission multiple over time to, scaled by 1e18. /// @param timeElapsedWad The time elapsed since the last checkpoint, scaled by 1e18. function computeGOOBalance( uint256 emissionMultiple, uint256 lastBalanceWad, uint256 timeElapsedWad ) internal pure returns (uint256) { unchecked { // We use wad math here because timeElapsedWad is, as the name indicates, a wad. uint256 timeElapsedSquaredWad = timeElapsedWad.mulWadDown(timeElapsedWad); // prettier-ignore return lastBalanceWad + // The last recorded balance. // Don't need to do wad multiplication since we're // multiplying by a plain integer with no decimals. // Shift right by 2 is equivalent to division by 4. ((emissionMultiple * timeElapsedSquaredWad) >> 2) + timeElapsedWad.mulWadDown( // Terms are wads, so must mulWad. // No wad multiplication for emissionMultiple * lastBalance // because emissionMultiple is a plain integer with no decimals. // We multiply the sqrt's radicand by 1e18 because it expects ints. (emissionMultiple * lastBalanceWad * 1e18).sqrt() ); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol) pragma solidity ^0.8.0; import "../ERC721.sol"; import "./IERC721Enumerable.sol"; /** * @dev This implements an optional extension of {ERC721} defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and 'to' cannot be the zero address at the same time. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address, address, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = 1; // compute log10(value), and add it to length uint256 valueCopy = value; if (valueCopy >= 10**64) { valueCopy /= 10**64; length += 64; } if (valueCopy >= 10**32) { valueCopy /= 10**32; length += 32; } if (valueCopy >= 10**16) { valueCopy /= 10**16; length += 16; } if (valueCopy >= 10**8) { valueCopy /= 10**8; length += 8; } if (valueCopy >= 10**4) { valueCopy /= 10**4; length += 4; } if (valueCopy >= 10**2) { valueCopy /= 10**2; length += 2; } if (valueCopy >= 10**1) { length += 1; } // now, length is log10(value) + 1 string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = 1; // compute log256(value), and add it to length uint256 valueCopy = value; if (valueCopy >= 1 << 128) { valueCopy >>= 128; length += 16; } if (valueCopy >= 1 << 64) { valueCopy >>= 64; length += 8; } if (valueCopy >= 1 << 32) { valueCopy >>= 32; length += 4; } if (valueCopy >= 1 << 16) { valueCopy >>= 16; length += 2; } if (valueCopy >= 1 << 8) { valueCopy >>= 8; length += 1; } // now, length is log256(value) + 1 return toHexString(value, length); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Signed 18 decimal fixed point (wad) arithmetic library. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol) /// @author Modified from Remco Bloemen (https://xn--2-umb.com/22/exp-ln/index.html) /// @dev Will not revert on overflow, only use where overflow is not possible. function toWadUnsafe(uint256 x) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 1e18. r := mul(x, 1000000000000000000) } } /// @dev Takes an integer amount of seconds and converts it to a wad amount of days. /// @dev Will not revert on overflow, only use where overflow is not possible. /// @dev Not meant for negative second amounts, it assumes x is positive. function toDaysWadUnsafe(uint256 x) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 1e18 and then divide it by 86400. r := div(mul(x, 1000000000000000000), 86400) } } /// @dev Takes a wad amount of days and converts it to an integer amount of seconds. /// @dev Will not revert on overflow, only use where overflow is not possible. /// @dev Not meant for negative day amounts, it assumes x is positive. function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 86400 and then divide it by 1e18. r := div(mul(x, 86400), 1000000000000000000) } } /// @dev Will not revert on overflow, only use where overflow is not possible. function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by y and divide by 1e18. r := sdiv(mul(x, y), 1000000000000000000) } } /// @dev Will return 0 instead of reverting if y is zero and will /// not revert on overflow, only use where overflow is not possible. function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 1e18 and divide it by y. r := sdiv(mul(x, 1000000000000000000), y) } } function wadMul(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Store x * y in r for now. r := mul(x, y) // Equivalent to require(x == 0 || (x * y) / x == y) if iszero(or(iszero(x), eq(sdiv(r, x), y))) { revert(0, 0) } // Scale the result down by 1e18. r := sdiv(r, 1000000000000000000) } } function wadDiv(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Store x * 1e18 in r for now. r := mul(x, 1000000000000000000) // Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x)) if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) { revert(0, 0) } // Divide r by y. r := sdiv(r, y) } } function wadExp(int256 x) pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return 0; // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5**18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); } } function wadLn(int256 x) pure returns (int256 r) { unchecked { require(x > 0, "UNDEFINED"); // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, shl(1, lt(0x3, shr(r, x)))) r := or(r, lt(0x1, shr(r, x))) } // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) int256 k = r - 96; x <<= uint256(159 - k); x = int256(uint256(x) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /// @dev Will return 0 instead of reverting if y is zero. function unsafeDiv(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. r := sdiv(x, y) } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {LogisticVRGDA} from "VRGDAs/LogisticVRGDA.sol"; // LogisticVRGDA is an abstract contract, need to wrap it like so contract LVRGDA is LogisticVRGDA { /// @notice Sets pricing parameters for the VRGDA. /// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18. /// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18. /// @param _maxSellable The maximum number of tokens to sell, scaled by 1e18. /// @param _timeScale The steepness of the logistic curve, scaled by 1e18. constructor(int256 _targetPrice, int256 _priceDecayPercent, int256 _maxSellable, int256 _timeScale) LogisticVRGDA(_targetPrice, _priceDecayPercent, _maxSellable, _timeScale) {} }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import {IERC721, ERC721, ERC721Enumerable} from "@openzeppelin/token/ERC721/extensions/ERC721Enumerable.sol"; import {Ownable} from "@openzeppelin/access/Ownable.sol"; import {toWadUnsafe, toDaysWadUnsafe} from "solmate/utils/SignedWadMath.sol"; import {LibGOO} from "goo-issuance/LibGOO.sol"; /// @dev An enum for representing whether to /// increase or decrease a user's goo balance. enum GooBalanceUpdateType { INCREASE, DECREASE } /// @notice Struct holding data relevant to each user's account. struct UserData { // User's goo balance at time of last checkpointing. uint128 lastBalance; // Timestamp of the last goo balance checkpoint. uint64 lastTimestamp; } contract OwnedEnumerableNFT is ERC721Enumerable, Ownable { constructor(string memory name, string memory symbol) ERC721(name, symbol) Ownable() {} function mint(address recipient) public virtual onlyOwner returns (uint256 id) { id = totalSupply(); _safeMint(recipient, id); } function burn(uint256 id) public onlyOwner { _burn(id); } } // SPY NFT will produce Goo contract SpyNFT is OwnedEnumerableNFT { /*////////////////////////////////////////////////////////////// Variables //////////////////////////////////////////////////////////////*/ /// Random emission multiple to massage the curve into place uint256 public constant EMISSION_MULTIPLE = 69; /// Keeps track of virtual GOO Balance mapping(address => UserData) public getUserData; /*////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ event GooBalanceUpdated(address indexed user, uint256 newGooBalance); /*////////////////////////////////////////////////////////////// Errors //////////////////////////////////////////////////////////////*/ error TooEarly(); /*////////////////////////////////////////////////////////////// Constructor //////////////////////////////////////////////////////////////*/ constructor() OwnedEnumerableNFT("Spy", "SPIES") {} /*////////////////////////////////////////////////////////////// Goo Functionality (Read only) //////////////////////////////////////////////////////////////*/ /// @notice Calculate a user's virtual goo balance. /// @param user The user to query balance for. function gooBalance(address user) public view returns (uint256) { // Compute the user's virtual goo balance using LibGOO. // prettier-ignore return LibGOO.computeGOOBalance( EMISSION_MULTIPLE * balanceOf(user), getUserData[user].lastBalance, uint256(toDaysWadUnsafe(block.timestamp - getUserData[user].lastTimestamp)) ); } /*////////////////////////////////////////////////////////////// Goo Functionality (Permissioned) //////////////////////////////////////////////////////////////*/ /// @notice Update a user's virtual goo balance. /// @param user The user whose virtual goo balance we should update. /// @param gooAmount The amount of goo to update the user's virtual balance by. /// @param updateType Whether to increase or decrease the user's balance by gooAmount. function updateUserGooBalance(address user, uint256 gooAmount, GooBalanceUpdateType updateType) public onlyOwner { // Will revert due to underflow if we're decreasing by more than the user's current balance. // Don't need to do checked addition in the increase case, but we do it anyway for convenience. uint256 updatedBalance = updateType == GooBalanceUpdateType.INCREASE ? gooBalance(user) + gooAmount : gooBalance(user) - gooAmount; // Snapshot the user's new goo balance with the current timestamp. getUserData[user].lastBalance = uint128(updatedBalance); getUserData[user].lastTimestamp = uint64(block.timestamp); emit GooBalanceUpdated(user, updatedBalance); } /// @notice Superuser transferFrom function sudoTransferFrom(address from, address to, uint256 tokenId) public onlyOwner { unchecked { // We update their last balance before updating their emission multiple to avoid // penalizing them by retroactively applying their new (lower) balanceOf getUserData[from].lastBalance = uint128(gooBalance(from)); getUserData[from].lastTimestamp = uint64(block.timestamp); // We update their last balance before updating their emission multiple to avoid // overpaying them by retroactively applying their new (higher) balanceOf getUserData[to].lastBalance = uint128(gooBalance(to)); getUserData[to].lastTimestamp = uint64(block.timestamp); } // State changes happen *after* gooBalance is update _transfer(from, to, tokenId); } /*////////////////////////////////////////////////////////////// ERC721 Functionality //////////////////////////////////////////////////////////////*/ function mint(address recipient, uint256 timestamp) public onlyOwner returns (uint256 id) { // Prevent bugs if (timestamp < block.timestamp) { revert TooEarly(); } // If we can't get the gooBalance, then minting hasn't start yet // If we can get the gooBal then we good try this.gooBalance(recipient) returns (uint256 existingGooBal) { getUserData[recipient].lastBalance = uint128(existingGooBal); } catch {} getUserData[recipient].lastTimestamp = uint64(timestamp); id = totalSupply(); _safeMint(recipient, id); } function transferFrom(address from, address to, uint256 tokenId) public override (ERC721, IERC721) { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); unchecked { // We update their last balance before updating their emission multiple to avoid // penalizing them by retroactively applying their new (lower) balanceOf getUserData[from].lastBalance = uint128(gooBalance(from)); getUserData[from].lastTimestamp = uint64(block.timestamp); // We update their last balance before updating their emission multiple to avoid // overpaying them by retroactively applying their new (higher) balanceOf getUserData[to].lastBalance = uint128(gooBalance(to)); getUserData[to].lastTimestamp = uint64(block.timestamp); } // State changes happen *after* gooBalance is update _transfer(from, to, tokenId); } function tokenURI(uint256 tokenId) public pure override returns (string memory) { string[4] memory parts; parts[0] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">'; parts[1] = "SPY #"; parts[2] = SVGUtils.toString(tokenId); parts[3] = "</text></svg>"; string memory output = string(abi.encodePacked(parts[0], parts[1], parts[2], parts[3])); string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "Spy #', SVGUtils.toString(tokenId), '", "description": "A Spy in the Knife Game Universe.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}' ) ) ) ); output = string(abi.encodePacked("data:application/json;base64,", json)); return output; } } contract KnifeNFT is OwnedEnumerableNFT { constructor() OwnedEnumerableNFT("Knife", "KNIVES") {} function sudoTransferFrom(address from, address to, uint256 tokenId) public onlyOwner { _transfer(from, to, tokenId); } function tokenURI(uint256 tokenId) public pure override returns (string memory) { string[4] memory parts; parts[0] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">'; parts[1] = "Knife #"; parts[2] = SVGUtils.toString(tokenId); parts[3] = "</text></svg>"; string memory output = string(abi.encodePacked(parts[0], parts[1], parts[2], parts[3])); string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "Knife #', SVGUtils.toString(tokenId), '", "description": "A Knife the Knife Game Universe.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}' ) ) ) ); output = string(abi.encodePacked("data:application/json;base64,", json)); return output; } } /// [MIT License] /// @title Base64 /// @notice Provides a function for encoding some bytes in base64 /// @author Brecht Devos <[email protected]> library Base64 { bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /// @notice Encodes some bytes to the base64 representation function encode(bytes memory data) internal pure returns (string memory) { uint256 len = data.length; if (len == 0) return ""; // multiply by 4/3 rounded up uint256 encodedLen = 4 * ((len + 2) / 3); // Add some extra buffer at the end bytes memory result = new bytes(encodedLen + 32); bytes memory table = TABLE; assembly { let tablePtr := add(table, 1) let resultPtr := add(result, 32) for { let i := 0 } lt(i, len) {} { i := add(i, 3) let input := and(mload(add(data, i)), 0xffffff) let out := mload(add(tablePtr, and(shr(18, input), 0x3F))) out := shl(8, out) out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF)) out := shl(8, out) out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF)) out := shl(8, out) out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF)) out := shl(224, out) mstore(resultPtr, out) resultPtr := add(resultPtr, 4) } switch mod(len, 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } mstore(result, encodedLen) } return string(result); } } library SVGUtils { function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT license // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 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); } }
{ "remappings": [ "@openzeppelin/=lib/openzeppelin-contracts/contracts/", "VRGDAs/=lib/VRGDAs/src/", "chainlink/=lib/chainlink/contracts/src/", "ds-test/=lib/VRGDAs/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "goo-issuance/=lib/goo-issuance/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"_gameStart","type":"uint256"},{"internalType":"address","name":"_spyNft","type":"address"},{"internalType":"address","name":"_knifeNFT","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DumbMove","type":"error"},{"inputs":[],"name":"NoWhales","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"TooEarly","type":"error"},{"inputs":[],"name":"TooLate","type":"error"},{"inputs":[],"name":"TooPoor","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"KnifePurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"Shouted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hitman","type":"address"},{"indexed":true,"internalType":"address","name":"victim","type":"address"},{"indexed":false,"internalType":"uint256","name":"knifeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"spyId","type":"uint256"}],"name":"SpyKilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"SpyMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"SpyPurchased","type":"event"},{"inputs":[],"name":"BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_PURCHASE_SPY_ETH_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTISIG","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHOUTS_FUNDS_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimFreeMoo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gameStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasUserClaimedFreeMooTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasUserPrepurchased","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_knifeId","type":"uint256"},{"internalType":"uint256","name":"_spyId","type":"uint256"}],"name":"killSpy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"knifeLVRGDA","outputs":[{"internalType":"contract LVRGDA","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"knifeNFT","outputs":[{"internalType":"contract KnifeNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"knifePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"knivesMintedFromMoo","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPrice","type":"uint256"}],"name":"mintKnifeFromMoolah","outputs":[{"internalType":"uint256","name":"knifeId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPrice","type":"uint256"}],"name":"mintSpyFromMoolah","outputs":[{"internalType":"uint256","name":"spyId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"purchaseSpy","outputs":[{"internalType":"uint256","name":"spyId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"message","type":"string"}],"name":"shout","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"spiesMintedFromMoo","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spyLVRGDA","outputs":[{"internalType":"contract LVRGDA","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spyNFT","outputs":[{"internalType":"contract SpyNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spyPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"spyPriceETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"_targetPrice","type":"int256"},{"internalType":"int256","name":"_priceDecayPercent","type":"int256"},{"internalType":"uint256","name":"_maxAmount","type":"uint256"},{"internalType":"int256","name":"_timeScale","type":"int256"}],"name":"updateKnifeVRGDA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"_targetPrice","type":"int256"},{"internalType":"int256","name":"_priceDecayPercent","type":"int256"},{"internalType":"uint256","name":"_maxAmount","type":"uint256"},{"internalType":"int256","name":"_timeScale","type":"int256"}],"name":"updateSpyVRGDA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPurchasesOnDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b506040516200356538038062003565833981016040819052620000349162000195565b60c08390526001600160a01b03828116608052811660a052675fc1b971363200006706f05b59d3b20000690405fdf7e5af85e00000670429d069189e000060405162000080906200016a565b938452602084019290925260408301526060820152608001604051809103906000f080158015620000b5573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b0392909216919091179055676f23e851b3b74000670853a0d2313c0000690878678326eac900000067030d98d59a9600006040516200010a906200016a565b938452602084019290925260408301526060820152608001604051809103906000f0801580156200013f573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b039290921691909117905550620001d6915050565b610aea8062002a7b83390190565b80516001600160a01b03811681146200019057600080fd5b919050565b600080600060608486031215620001ab57600080fd5b83519250620001bd6020850162000178565b9150620001cd6040850162000178565b90509250925092565b60805160a05160c0516127aa620002d16000396000818161035d015281816105fd015281816106d2015281816108520152818161093d015281816109b801528181610a0101528181610aff01528181610b2701528181610bf701528181610d2301528181610d4b01528181610f7501528181610fc00152818161152b015281816115dc01526116970152600081816101ba0152818161109b015281816112970152818161135101526117a40152600081816104740152818161079d01528181610acf01528181610c8101528181610cf301528181611153015281816111ff015281816113cf01528181611477015261172101526127aa6000f3fe608060405260043610620001a15760003560e01c80637e04e55f11620000e2578063c3a48baa1162000095578063d5ed95c1116200006c578063d5ed95c11462000561578063dd416943146200058b578063de28179e14620005a9578063fccc281314620005cb57600080fd5b8063c3a48baa14620004f5578063ce9b0ec01462000517578063d5493aa7146200053c57600080fd5b80637e04e55f14620003f95780638b56f487146200041e57806395e9143f1462000460578063a9ad5e6f1462000496578063b357986214620004bb578063c11339a414620004dd57600080fd5b8063277ddbaa116200015857806336b60630116200012f57806336b60630146200037f5780634c27b6ca146200038957806355ab5fbd14620003bd578063625d205514620003e257600080fd5b8063277ddbaa14620002e8578063317be1b714620003245780633218b99d146200034957600080fd5b806307e05f9714620001a6578063150b7a0214620001f95780631a40084d14620002385780631bb47402146200025f57806323f02f8714620002a45780632530b14514620002be575b600080fd5b348015620001b357600080fd5b50620001dc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200020657600080fd5b506200021e62000218366004620018b8565b620005e3565b6040516001600160e01b03199091168152602001620001f0565b3480156200024557600080fd5b5062000250620005f4565b604051908152602001620001f0565b3480156200026c57600080fd5b50620002936200027e366004620019a6565b60046020526000908152604090205460ff1681565b6040519015158152602001620001f0565b348015620002b157600080fd5b50620002bc620006d0565b005b348015620002cb57600080fd5b50620001dc73503c42470951b7c163730fd8b67ea66fecd8c77481565b348015620002f557600080fd5b506200025062000307366004620019cd565b600360209081526000928352604080842090915290825290205481565b3480156200033157600080fd5b50620002bc62000343366004620019fc565b6200081b565b3480156200035657600080fd5b50620002507f000000000000000000000000000000000000000000000000000000000000000081565b620002506200090a565b3480156200039657600080fd5b5062000293620003a8366004620019a6565b60056020526000908152604090205460ff1681565b348015620003ca57600080fd5b5062000250620003dc36600462001a2f565b62000bf3565b620002bc620003f336600462001a49565b62000e50565b3480156200040657600080fd5b506200025062000418366004620019a6565b62000f71565b3480156200042b57600080fd5b506002546200044790600160801b90046001600160801b031681565b6040516001600160801b039091168152602001620001f0565b3480156200046d57600080fd5b50620001dc7f000000000000000000000000000000000000000000000000000000000000000081565b348015620004a357600080fd5b50620002bc620004b536600462001ac0565b6200107b565b348015620004c857600080fd5b50600054620001dc906001600160a01b031681565b348015620004ea57600080fd5b506200025062001522565b3480156200050257600080fd5b5060025462000447906001600160801b031681565b3480156200052457600080fd5b50620002bc62000536366004620019fc565b620015a5565b3480156200054957600080fd5b50620002506200055b36600462001a2f565b62001693565b3480156200056e57600080fd5b50620001dc73db42214e11bf1d49df83d311c3d88aacde66624381565b3480156200059857600080fd5b506200025067016345785d8a000081565b348015620005b657600080fd5b50600154620001dc906001600160a01b031681565b348015620005d857600080fd5b50620001dc61dead81565b630a85bd0160e11b5b949350505050565b600080620006257f000000000000000000000000000000000000000000000000000000000000000061a8c062001af9565b62000631904262001b14565b60015460025460405163f466d4ab60e01b815262015180670de0b6b3a76400008502046004820152600160801b9091046001600160801b031660248201529192506001600160a01b03169063f466d4ab906044015b602060405180830381865afa158015620006a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006ca919062001b2e565b91505090565b7f0000000000000000000000000000000000000000000000000000000000000000421015620007125760405163085de62560e01b815260040160405180910390fd5b3360009081526004602052604090205460ff1662000743576040516389a007b560e01b815260040160405180910390fd5b3360009081526005602052604090205460ff161562000775576040516389a007b560e01b815260040160405180910390fd5b33600081815260056020526040808220805460ff191660011790555163f66e9ac360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169263f66e9ac392620007e592678ac7230489e80000919060040162001b6b565b600060405180830381600087803b1580156200080057600080fd5b505af115801562000815573d6000803e3d6000fd5b50505050565b3373503c42470951b7c163730fd8b67ea66fecd8c7741462000850576040516330cd747160e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000421115620008925760405163ecdd1c2960e01b815260040160405180910390fd5b8383670de0b6b3a7640000840283604051620008ae906200187b565b938452602084019290925260408301526060820152608001604051809103906000f080158015620008e3573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b039290921691909117905550505050565b6000620009173362000f71565b3410156200093b576040516001627a6f0d60e11b0319815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000421015620009b6573360009081526004602052604090205460ff1615620009965760405163915e5b0360e01b815260040160405180910390fd5b336000908152600460205260409020805460ff1916600117905562000a6f565b7f0000000000000000000000000000000000000000000000000000000000000000421062000a6f5733600090815260036020526040812090670de0b6b3a764000062000a3c62000a277f00000000000000000000000000000000000000000000000000000000000000004262001b14565b62015180670de0b6b3a7640000919091020490565b62000a48919062001b91565b8152602001908152602001600020600081548092919062000a699062001bd1565b91905055505b60405173503c42470951b7c163730fd8b67ea66fecd8c774903490600081818185875af1925050503d806000811462000ac5576040519150601f19603f3d011682016040523d82523d6000602084013e62000aca565b606091505b5050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f19337f0000000000000000000000000000000000000000000000000000000000000000421162000b4c577f000000000000000000000000000000000000000000000000000000000000000062000b4e565b425b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801562000b9a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bc0919062001b2e565b604051909150819033907ff82e2590f1955aa286931546a6a9af6e567a515ce1a63338570144879ff3edbd90600090a390565b60007f000000000000000000000000000000000000000000000000000000000000000042101562000c375760405163085de62560e01b815260040160405180910390fd5b600062000c4362001522565b90508281111562000c6a576040516001627a6f0d60e11b0319815260040160405180910390fd5b60405163f66e9ac360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f66e9ac39062000cbd903390859060019060040162001b6b565b600060405180830381600087803b15801562000cd857600080fd5b505af115801562000ced573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f19337f0000000000000000000000000000000000000000000000000000000000000000421162000d70577f000000000000000000000000000000000000000000000000000000000000000062000d72565b425b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801562000dbe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000de4919062001b2e565b600280546001600160801b03808216600101166fffffffffffffffffffffffffffffffff19909116179055604051828152909250829033907f08d83b082b867b304d2f59332800a333b519e7236f0bf5b500090aab59a6ac11906020015b60405180910390a350919050565b66b1a2bc2ec5000034101562000e7c576040516001627a6f0d60e11b0319815260040160405180910390fd5b60405173db42214e11bf1d49df83d311c3d88aacde666243903490600081818185875af1925050503d806000811462000ed2576040519150601f19603f3d011682016040523d82523d6000602084013e62000ed7565b606091505b50505061010081111562000f3457337f2a61c0d7ddc4a70821f0286174956bf3d0d434e921873e1c34a3896e96bb6f4562000f186101006000858762001bed565b60405162000f2892919062001c19565b60405180910390a25050565b336001600160a01b03167f2a61c0d7ddc4a70821f0286174956bf3d0d434e921873e1c34a3896e96bb6f45838360405162000f2892919062001c19565b60007f000000000000000000000000000000000000000000000000000000000000000042101562000fab575067016345785d8a0000919050565b6000670de0b6b3a764000062000fe662000a277f00000000000000000000000000000000000000000000000000000000000000004262001b14565b62000ff2919062001b91565b6001600160a01b0384166000908152600360209081526040808320848452909152812054919250805b828110156200105d5781600003620010395767016345785d8a000091505b6200104682600262001c48565b915080620010548162001bd1565b9150506200101b565b50620010728167016345785d8a000062001af9565b95945050505050565b6040516331a9108f60e11b81526004810183905233906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015620010e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001109919062001c6a565b6001600160a01b03161462001131576040516330cd747160e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810182905261dead906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa1580156200119b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011c1919062001c6a565b6001600160a01b031603620011e9576040516389a007b560e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156200124f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001275919062001c6a565b6040516331a9108f60e11b8152600481018490526001600160a01b03918216917f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015620012df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001305919062001c6a565b6001600160a01b0316036200132d576040516389a007b560e01b815260040160405180910390fd5b60405163106ea60160e11b815233600482015261dead6024820152604481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906320dd4c0290606401600060405180830381600087803b1580156200139e57600080fd5b505af1158015620013b3573d6000803e3d6000fd5b50506040516331a9108f60e11b815260048101849052600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169150636352211e90602401602060405180830381865afa15801562001420573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001446919062001c6a565b60405163106ea60160e11b81526001600160a01b03808316600483015261dead6024830152604482018590529192507f0000000000000000000000000000000000000000000000000000000000000000909116906320dd4c0290606401600060405180830381600087803b158015620014be57600080fd5b505af1158015620014d3573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03851693503392507f45e465566601be3e6eb4963d1b7cefe8cba5f8fda38b9107329955fea6ce9467910160405180910390a3505050565b600080620015517f00000000000000000000000000000000000000000000000000000000000000004262001b14565b60005460025460405163f466d4ab60e01b815262015180670de0b6b3a764000085020460048201526001600160801b0390911660248201529192506001600160a01b03169063f466d4ab9060440162000686565b3373503c42470951b7c163730fd8b67ea66fecd8c77414620015da576040516330cd747160e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000042106200161b5760405163ecdd1c2960e01b815260040160405180910390fd5b8383670de0b6b3a764000084028360405162001637906200187b565b938452602084019290925260408301526060820152608001604051809103906000f0801580156200166c573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691909117905550505050565b60007f0000000000000000000000000000000000000000000000000000000000000000421015620016d75760405163085de62560e01b815260040160405180910390fd5b6000620016e3620005f4565b9050828111156200170a576040516001627a6f0d60e11b0319815260040160405180910390fd5b60405163f66e9ac360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f66e9ac3906200175d903390859060019060040162001b6b565b600060405180830381600087803b1580156200177857600080fd5b505af11580156200178d573d6000803e3d6000fd5b50506040516335313c2160e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169250636a62784291506024016020604051808303816000875af1158015620017f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200181e919062001b2e565b600280546001600160801b8083046001600160801b03908116929092018216029116179055604051828152909250829033907f63ea169cbcbcf8d736b710d6ef4ff9da8ececc2cc5f5403f2b12b47d5f965e009060200162000e42565b610aea8062001c8b83390190565b6001600160a01b03811681146200189f57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215620018cf57600080fd5b8435620018dc8162001889565b93506020850135620018ee8162001889565b925060408501359150606085013567ffffffffffffffff808211156200191357600080fd5b818701915087601f8301126200192857600080fd5b8135818111156200193d576200193d620018a2565b604051601f8201601f19908116603f01168101908382118183101715620019685762001968620018a2565b816040528281528a60208487010111156200198257600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600060208284031215620019b957600080fd5b8135620019c68162001889565b9392505050565b60008060408385031215620019e157600080fd5b8235620019ee8162001889565b946020939093013593505050565b6000806000806080858703121562001a1357600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121562001a4257600080fd5b5035919050565b6000806020838503121562001a5d57600080fd5b823567ffffffffffffffff8082111562001a7657600080fd5b818501915085601f83011262001a8b57600080fd5b81358181111562001a9b57600080fd5b86602082850101111562001aae57600080fd5b60209290920196919550909350505050565b6000806040838503121562001ad457600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b6000821982111562001b0f5762001b0f62001ae3565b500190565b60008282101562001b295762001b2962001ae3565b500390565b60006020828403121562001b4157600080fd5b5051919050565b6002811062001b6757634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b03841681526020810183905260608101620005ec604083018462001b48565b60008262001baf57634e487b7160e01b600052601260045260246000fd5b600160ff1b82146000198414161562001bcc5762001bcc62001ae3565b500590565b60006001820162001be65762001be662001ae3565b5060010190565b6000808585111562001bfe57600080fd5b8386111562001c0c57600080fd5b5050820193919092039150565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600081600019048311821515161562001c655762001c6562001ae3565b500290565b60006020828403121562001c7d57600080fd5b8151620019c6816200188956fe61012060405234801561001157600080fd5b50604051610aea380380610aea83398101604081905261003091610315565b608084905283838383838361005561005082670de0b6b3a7640000610361565b6100ee565b60a08190526000136100ae5760405162461bcd60e51b815260206004820152601b60248201527f4e4f4e5f4e454741544956455f44454341595f434f4e5354414e54000000000060448201526064015b60405180910390fd5b506100c3905082670de0b6b3a76400006103a0565b60c08190526100da90671bc16d674ec800006103e1565b60e052610100525061046695505050505050565b600080821361012b5760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b60448201526064016100a5565b5060606001600160801b03821160071b82811c6001600160401b031060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd19010260016c0504a838426634cdd8738f543560611b03190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000806000806080858703121561032b57600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b85018412161561037f5761037f61034b565b6001600160ff1b038401831381161561039a5761039a61034b565b50500390565b600080821280156001600160ff1b03849003851316156103c2576103c261034b565b600160ff1b83900384128116156103db576103db61034b565b50500190565b60006001600160ff1b03818413828413808216868404861116156104075761040761034b565b600160ff1b60008712828116878305891216156104265761042661034b565b600087129250878205871284841616156104425761044261034b565b878505871281841616156104585761045861034b565b505050929093029392505050565b60805160a05160c05160e0516101005161063c6104ae60003960006101030152600060db0152600060b80152600061016a01526000818160700152610143015261063c6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636d9d33b714610046578063dc38679c1461006b578063f466d4ab14610092575b600080fd5b6100596100543660046105cb565b6100a5565b60405190815260200160405180910390f35b6100597f000000000000000000000000000000000000000000000000000000000000000081565b6100596100a03660046105e4565b61013c565b6000610133610101670de0b6b3a76400007f000000000000000000000000000000000000000000000000000000000000000085017f000000000000000000000000000000000000000000000000000000000000000005036101c1565b7f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000919091020590565b60000392915050565b60006101ba7f00000000000000000000000000000000000000000000000000000000000000006101b56101b07f000000000000000000000000000000000000000000000000000000000000000061019f670de0b6b3a764000060018901026100a5565b8803670de0b6b3a764000091020590565b6103fd565b6105a6565b9392505050565b60008082136102035760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b60448201526064015b60405180910390fd5b5060606fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd190102780a09507084cc699bb0e71ea869ffffffffffffffffffffffff190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000680248ce36a70cb26b3e19821361041857506000919050565b680755bf798b4a1bf1e5821261045f5760405162461bcd60e51b815260206004820152600c60248201526b4558505f4f564552464c4f5760a01b60448201526064016101fa565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b81810282158382058314176105ba57600080fd5b670de0b6b3a7640000900592915050565b6000602082840312156105dd57600080fd5b5035919050565b600080604083850312156105f757600080fd5b5050803592602090910135915056fea264697066735822122010c83a85b8d8e86302596862a1f72e5f5b60d76071e7d361ec6defc3caff648a64736f6c634300080e0033a26469706673582212200f505a5698287e5b75c668492b3b1145a49a48fe5d92c8e691e08f85736c18ee64736f6c634300080e003361012060405234801561001157600080fd5b50604051610aea380380610aea83398101604081905261003091610315565b608084905283838383838361005561005082670de0b6b3a7640000610361565b6100ee565b60a08190526000136100ae5760405162461bcd60e51b815260206004820152601b60248201527f4e4f4e5f4e454741544956455f44454341595f434f4e5354414e54000000000060448201526064015b60405180910390fd5b506100c3905082670de0b6b3a76400006103a0565b60c08190526100da90671bc16d674ec800006103e1565b60e052610100525061046695505050505050565b600080821361012b5760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b60448201526064016100a5565b5060606001600160801b03821160071b82811c6001600160401b031060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd19010260016c0504a838426634cdd8738f543560611b03190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000806000806080858703121561032b57600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b85018412161561037f5761037f61034b565b6001600160ff1b038401831381161561039a5761039a61034b565b50500390565b600080821280156001600160ff1b03849003851316156103c2576103c261034b565b600160ff1b83900384128116156103db576103db61034b565b50500190565b60006001600160ff1b03818413828413808216868404861116156104075761040761034b565b600160ff1b60008712828116878305891216156104265761042661034b565b600087129250878205871284841616156104425761044261034b565b878505871281841616156104585761045861034b565b505050929093029392505050565b60805160a05160c05160e0516101005161063c6104ae60003960006101030152600060db0152600060b80152600061016a01526000818160700152610143015261063c6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636d9d33b714610046578063dc38679c1461006b578063f466d4ab14610092575b600080fd5b6100596100543660046105cb565b6100a5565b60405190815260200160405180910390f35b6100597f000000000000000000000000000000000000000000000000000000000000000081565b6100596100a03660046105e4565b61013c565b6000610133610101670de0b6b3a76400007f000000000000000000000000000000000000000000000000000000000000000085017f000000000000000000000000000000000000000000000000000000000000000005036101c1565b7f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000919091020590565b60000392915050565b60006101ba7f00000000000000000000000000000000000000000000000000000000000000006101b56101b07f000000000000000000000000000000000000000000000000000000000000000061019f670de0b6b3a764000060018901026100a5565b8803670de0b6b3a764000091020590565b6103fd565b6105a6565b9392505050565b60008082136102035760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b60448201526064015b60405180910390fd5b5060606fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd190102780a09507084cc699bb0e71ea869ffffffffffffffffffffffff190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000680248ce36a70cb26b3e19821361041857506000919050565b680755bf798b4a1bf1e5821261045f5760405162461bcd60e51b815260206004820152600c60248201526b4558505f4f564552464c4f5760a01b60448201526064016101fa565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b81810282158382058314176105ba57600080fd5b670de0b6b3a7640000900592915050565b6000602082840312156105dd57600080fd5b5035919050565b600080604083850312156105f757600080fd5b5050803592602090910135915056fea264697066735822122010c83a85b8d8e86302596862a1f72e5f5b60d76071e7d361ec6defc3caff648a64736f6c634300080e003300000000000000000000000000000000000000000000000000000000639ca41000000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91660000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f1
Deployed Bytecode
0x608060405260043610620001a15760003560e01c80637e04e55f11620000e2578063c3a48baa1162000095578063d5ed95c1116200006c578063d5ed95c11462000561578063dd416943146200058b578063de28179e14620005a9578063fccc281314620005cb57600080fd5b8063c3a48baa14620004f5578063ce9b0ec01462000517578063d5493aa7146200053c57600080fd5b80637e04e55f14620003f95780638b56f487146200041e57806395e9143f1462000460578063a9ad5e6f1462000496578063b357986214620004bb578063c11339a414620004dd57600080fd5b8063277ddbaa116200015857806336b60630116200012f57806336b60630146200037f5780634c27b6ca146200038957806355ab5fbd14620003bd578063625d205514620003e257600080fd5b8063277ddbaa14620002e8578063317be1b714620003245780633218b99d146200034957600080fd5b806307e05f9714620001a6578063150b7a0214620001f95780631a40084d14620002385780631bb47402146200025f57806323f02f8714620002a45780632530b14514620002be575b600080fd5b348015620001b357600080fd5b50620001dc7f0000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f181565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200020657600080fd5b506200021e62000218366004620018b8565b620005e3565b6040516001600160e01b03199091168152602001620001f0565b3480156200024557600080fd5b5062000250620005f4565b604051908152602001620001f0565b3480156200026c57600080fd5b50620002936200027e366004620019a6565b60046020526000908152604090205460ff1681565b6040519015158152602001620001f0565b348015620002b157600080fd5b50620002bc620006d0565b005b348015620002cb57600080fd5b50620001dc73503c42470951b7c163730fd8b67ea66fecd8c77481565b348015620002f557600080fd5b506200025062000307366004620019cd565b600360209081526000928352604080842090915290825290205481565b3480156200033157600080fd5b50620002bc62000343366004620019fc565b6200081b565b3480156200035657600080fd5b50620002507f00000000000000000000000000000000000000000000000000000000639ca41081565b620002506200090a565b3480156200039657600080fd5b5062000293620003a8366004620019a6565b60056020526000908152604090205460ff1681565b348015620003ca57600080fd5b5062000250620003dc36600462001a2f565b62000bf3565b620002bc620003f336600462001a49565b62000e50565b3480156200040657600080fd5b506200025062000418366004620019a6565b62000f71565b3480156200042b57600080fd5b506002546200044790600160801b90046001600160801b031681565b6040516001600160801b039091168152602001620001f0565b3480156200046d57600080fd5b50620001dc7f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a916681565b348015620004a357600080fd5b50620002bc620004b536600462001ac0565b6200107b565b348015620004c857600080fd5b50600054620001dc906001600160a01b031681565b348015620004ea57600080fd5b506200025062001522565b3480156200050257600080fd5b5060025462000447906001600160801b031681565b3480156200052457600080fd5b50620002bc62000536366004620019fc565b620015a5565b3480156200054957600080fd5b50620002506200055b36600462001a2f565b62001693565b3480156200056e57600080fd5b50620001dc73db42214e11bf1d49df83d311c3d88aacde66624381565b3480156200059857600080fd5b506200025067016345785d8a000081565b348015620005b657600080fd5b50600154620001dc906001600160a01b031681565b348015620005d857600080fd5b50620001dc61dead81565b630a85bd0160e11b5b949350505050565b600080620006257f00000000000000000000000000000000000000000000000000000000639ca41061a8c062001af9565b62000631904262001b14565b60015460025460405163f466d4ab60e01b815262015180670de0b6b3a76400008502046004820152600160801b9091046001600160801b031660248201529192506001600160a01b03169063f466d4ab906044015b602060405180830381865afa158015620006a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006ca919062001b2e565b91505090565b7f00000000000000000000000000000000000000000000000000000000639ca410421015620007125760405163085de62560e01b815260040160405180910390fd5b3360009081526004602052604090205460ff1662000743576040516389a007b560e01b815260040160405180910390fd5b3360009081526005602052604090205460ff161562000775576040516389a007b560e01b815260040160405180910390fd5b33600081815260056020526040808220805460ff191660011790555163f66e9ac360e01b81527f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91666001600160a01b03169263f66e9ac392620007e592678ac7230489e80000919060040162001b6b565b600060405180830381600087803b1580156200080057600080fd5b505af115801562000815573d6000803e3d6000fd5b50505050565b3373503c42470951b7c163730fd8b67ea66fecd8c7741462000850576040516330cd747160e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000639ca410421115620008925760405163ecdd1c2960e01b815260040160405180910390fd5b8383670de0b6b3a7640000840283604051620008ae906200187b565b938452602084019290925260408301526060820152608001604051809103906000f080158015620008e3573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b039290921691909117905550505050565b6000620009173362000f71565b3410156200093b576040516001627a6f0d60e11b0319815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000639ca410421015620009b6573360009081526004602052604090205460ff1615620009965760405163915e5b0360e01b815260040160405180910390fd5b336000908152600460205260409020805460ff1916600117905562000a6f565b7f00000000000000000000000000000000000000000000000000000000639ca410421062000a6f5733600090815260036020526040812090670de0b6b3a764000062000a3c62000a277f00000000000000000000000000000000000000000000000000000000639ca4104262001b14565b62015180670de0b6b3a7640000919091020490565b62000a48919062001b91565b8152602001908152602001600020600081548092919062000a699062001bd1565b91905055505b60405173503c42470951b7c163730fd8b67ea66fecd8c774903490600081818185875af1925050503d806000811462000ac5576040519150601f19603f3d011682016040523d82523d6000602084013e62000aca565b606091505b5050507f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91666001600160a01b03166340c10f19337f00000000000000000000000000000000000000000000000000000000639ca410421162000b4c577f00000000000000000000000000000000000000000000000000000000639ca41062000b4e565b425b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801562000b9a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bc0919062001b2e565b604051909150819033907ff82e2590f1955aa286931546a6a9af6e567a515ce1a63338570144879ff3edbd90600090a390565b60007f00000000000000000000000000000000000000000000000000000000639ca41042101562000c375760405163085de62560e01b815260040160405180910390fd5b600062000c4362001522565b90508281111562000c6a576040516001627a6f0d60e11b0319815260040160405180910390fd5b60405163f66e9ac360e01b81526001600160a01b037f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a9166169063f66e9ac39062000cbd903390859060019060040162001b6b565b600060405180830381600087803b15801562000cd857600080fd5b505af115801562000ced573d6000803e3d6000fd5b505050507f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91666001600160a01b03166340c10f19337f00000000000000000000000000000000000000000000000000000000639ca410421162000d70577f00000000000000000000000000000000000000000000000000000000639ca41062000d72565b425b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801562000dbe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000de4919062001b2e565b600280546001600160801b03808216600101166fffffffffffffffffffffffffffffffff19909116179055604051828152909250829033907f08d83b082b867b304d2f59332800a333b519e7236f0bf5b500090aab59a6ac11906020015b60405180910390a350919050565b66b1a2bc2ec5000034101562000e7c576040516001627a6f0d60e11b0319815260040160405180910390fd5b60405173db42214e11bf1d49df83d311c3d88aacde666243903490600081818185875af1925050503d806000811462000ed2576040519150601f19603f3d011682016040523d82523d6000602084013e62000ed7565b606091505b50505061010081111562000f3457337f2a61c0d7ddc4a70821f0286174956bf3d0d434e921873e1c34a3896e96bb6f4562000f186101006000858762001bed565b60405162000f2892919062001c19565b60405180910390a25050565b336001600160a01b03167f2a61c0d7ddc4a70821f0286174956bf3d0d434e921873e1c34a3896e96bb6f45838360405162000f2892919062001c19565b60007f00000000000000000000000000000000000000000000000000000000639ca41042101562000fab575067016345785d8a0000919050565b6000670de0b6b3a764000062000fe662000a277f00000000000000000000000000000000000000000000000000000000639ca4104262001b14565b62000ff2919062001b91565b6001600160a01b0384166000908152600360209081526040808320848452909152812054919250805b828110156200105d5781600003620010395767016345785d8a000091505b6200104682600262001c48565b915080620010548162001bd1565b9150506200101b565b50620010728167016345785d8a000062001af9565b95945050505050565b6040516331a9108f60e11b81526004810183905233906001600160a01b037f0000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f11690636352211e90602401602060405180830381865afa158015620010e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001109919062001c6a565b6001600160a01b03161462001131576040516330cd747160e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810182905261dead906001600160a01b037f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91661690636352211e90602401602060405180830381865afa1580156200119b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011c1919062001c6a565b6001600160a01b031603620011e9576040516389a007b560e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018290527f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91666001600160a01b031690636352211e90602401602060405180830381865afa1580156200124f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001275919062001c6a565b6040516331a9108f60e11b8152600481018490526001600160a01b03918216917f0000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f11690636352211e90602401602060405180830381865afa158015620012df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001305919062001c6a565b6001600160a01b0316036200132d576040516389a007b560e01b815260040160405180910390fd5b60405163106ea60160e11b815233600482015261dead6024820152604481018390527f0000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f16001600160a01b0316906320dd4c0290606401600060405180830381600087803b1580156200139e57600080fd5b505af1158015620013b3573d6000803e3d6000fd5b50506040516331a9108f60e11b815260048101849052600092507f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91666001600160a01b03169150636352211e90602401602060405180830381865afa15801562001420573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001446919062001c6a565b60405163106ea60160e11b81526001600160a01b03808316600483015261dead6024830152604482018590529192507f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a9166909116906320dd4c0290606401600060405180830381600087803b158015620014be57600080fd5b505af1158015620014d3573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03851693503392507f45e465566601be3e6eb4963d1b7cefe8cba5f8fda38b9107329955fea6ce9467910160405180910390a3505050565b600080620015517f00000000000000000000000000000000000000000000000000000000639ca4104262001b14565b60005460025460405163f466d4ab60e01b815262015180670de0b6b3a764000085020460048201526001600160801b0390911660248201529192506001600160a01b03169063f466d4ab9060440162000686565b3373503c42470951b7c163730fd8b67ea66fecd8c77414620015da576040516330cd747160e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000639ca41042106200161b5760405163ecdd1c2960e01b815260040160405180910390fd5b8383670de0b6b3a764000084028360405162001637906200187b565b938452602084019290925260408301526060820152608001604051809103906000f0801580156200166c573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691909117905550505050565b60007f00000000000000000000000000000000000000000000000000000000639ca410421015620016d75760405163085de62560e01b815260040160405180910390fd5b6000620016e3620005f4565b9050828111156200170a576040516001627a6f0d60e11b0319815260040160405180910390fd5b60405163f66e9ac360e01b81526001600160a01b037f00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a9166169063f66e9ac3906200175d903390859060019060040162001b6b565b600060405180830381600087803b1580156200177857600080fd5b505af11580156200178d573d6000803e3d6000fd5b50506040516335313c2160e11b81523360048201527f0000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f16001600160a01b03169250636a62784291506024016020604051808303816000875af1158015620017f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200181e919062001b2e565b600280546001600160801b8083046001600160801b03908116929092018216029116179055604051828152909250829033907f63ea169cbcbcf8d736b710d6ef4ff9da8ececc2cc5f5403f2b12b47d5f965e009060200162000e42565b610aea8062001c8b83390190565b6001600160a01b03811681146200189f57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215620018cf57600080fd5b8435620018dc8162001889565b93506020850135620018ee8162001889565b925060408501359150606085013567ffffffffffffffff808211156200191357600080fd5b818701915087601f8301126200192857600080fd5b8135818111156200193d576200193d620018a2565b604051601f8201601f19908116603f01168101908382118183101715620019685762001968620018a2565b816040528281528a60208487010111156200198257600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600060208284031215620019b957600080fd5b8135620019c68162001889565b9392505050565b60008060408385031215620019e157600080fd5b8235620019ee8162001889565b946020939093013593505050565b6000806000806080858703121562001a1357600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121562001a4257600080fd5b5035919050565b6000806020838503121562001a5d57600080fd5b823567ffffffffffffffff8082111562001a7657600080fd5b818501915085601f83011262001a8b57600080fd5b81358181111562001a9b57600080fd5b86602082850101111562001aae57600080fd5b60209290920196919550909350505050565b6000806040838503121562001ad457600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b6000821982111562001b0f5762001b0f62001ae3565b500190565b60008282101562001b295762001b2962001ae3565b500390565b60006020828403121562001b4157600080fd5b5051919050565b6002811062001b6757634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b03841681526020810183905260608101620005ec604083018462001b48565b60008262001baf57634e487b7160e01b600052601260045260246000fd5b600160ff1b82146000198414161562001bcc5762001bcc62001ae3565b500590565b60006001820162001be65762001be662001ae3565b5060010190565b6000808585111562001bfe57600080fd5b8386111562001c0c57600080fd5b5050820193919092039150565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600081600019048311821515161562001c655762001c6562001ae3565b500290565b60006020828403121562001c7d57600080fd5b8151620019c6816200188956fe61012060405234801561001157600080fd5b50604051610aea380380610aea83398101604081905261003091610315565b608084905283838383838361005561005082670de0b6b3a7640000610361565b6100ee565b60a08190526000136100ae5760405162461bcd60e51b815260206004820152601b60248201527f4e4f4e5f4e454741544956455f44454341595f434f4e5354414e54000000000060448201526064015b60405180910390fd5b506100c3905082670de0b6b3a76400006103a0565b60c08190526100da90671bc16d674ec800006103e1565b60e052610100525061046695505050505050565b600080821361012b5760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b60448201526064016100a5565b5060606001600160801b03821160071b82811c6001600160401b031060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd19010260016c0504a838426634cdd8738f543560611b03190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000806000806080858703121561032b57600080fd5b505082516020840151604085015160609095015191969095509092509050565b634e487b7160e01b600052601160045260246000fd5b60008083128015600160ff1b85018412161561037f5761037f61034b565b6001600160ff1b038401831381161561039a5761039a61034b565b50500390565b600080821280156001600160ff1b03849003851316156103c2576103c261034b565b600160ff1b83900384128116156103db576103db61034b565b50500190565b60006001600160ff1b03818413828413808216868404861116156104075761040761034b565b600160ff1b60008712828116878305891216156104265761042661034b565b600087129250878205871284841616156104425761044261034b565b878505871281841616156104585761045861034b565b505050929093029392505050565b60805160a05160c05160e0516101005161063c6104ae60003960006101030152600060db0152600060b80152600061016a01526000818160700152610143015261063c6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80636d9d33b714610046578063dc38679c1461006b578063f466d4ab14610092575b600080fd5b6100596100543660046105cb565b6100a5565b60405190815260200160405180910390f35b6100597f000000000000000000000000000000000000000000000000000000000000000081565b6100596100a03660046105e4565b61013c565b6000610133610101670de0b6b3a76400007f000000000000000000000000000000000000000000000000000000000000000085017f000000000000000000000000000000000000000000000000000000000000000005036101c1565b7f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000919091020590565b60000392915050565b60006101ba7f00000000000000000000000000000000000000000000000000000000000000006101b56101b07f000000000000000000000000000000000000000000000000000000000000000061019f670de0b6b3a764000060018901026100a5565b8803670de0b6b3a764000091020590565b6103fd565b6105a6565b9392505050565b60008082136102035760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b60448201526064015b60405180910390fd5b5060606fffffffffffffffffffffffffffffffff821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd190102780a09507084cc699bb0e71ea869ffffffffffffffffffffffff190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000680248ce36a70cb26b3e19821361041857506000919050565b680755bf798b4a1bf1e5821261045f5760405162461bcd60e51b815260206004820152600c60248201526b4558505f4f564552464c4f5760a01b60448201526064016101fa565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b81810282158382058314176105ba57600080fd5b670de0b6b3a7640000900592915050565b6000602082840312156105dd57600080fd5b5035919050565b600080604083850312156105f757600080fd5b5050803592602090910135915056fea264697066735822122010c83a85b8d8e86302596862a1f72e5f5b60d76071e7d361ec6defc3caff648a64736f6c634300080e0033a26469706673582212200f505a5698287e5b75c668492b3b1145a49a48fe5d92c8e691e08f85736c18ee64736f6c634300080e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000639ca41000000000000000000000000088bd205658ea66e4c96ee61686439e160c4a91660000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f1
-----Decoded View---------------
Arg [0] : _gameStart (uint256): 1671210000
Arg [1] : _spyNft (address): 0x88BD205658Ea66E4c96ee61686439E160C4a9166
Arg [2] : _knifeNFT (address): 0x7ea0f05e3dDC1A866bcaa2aEa278aDF763a837f1
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000639ca410
Arg [1] : 00000000000000000000000088bd205658ea66e4c96ee61686439e160c4a9166
Arg [2] : 0000000000000000000000007ea0f05e3ddc1a866bcaa2aea278adf763a837f1
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
POL | 100.00% | $0.425921 | 0.05 | $0.021296 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.