You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
5.1 KiB
Solidity
128 lines
5.1 KiB
Solidity
// SPDX-License-Identifier: UNLICENSED
|
|
pragma solidity ^0.8.13;
|
|
|
|
import {ERC721} from "solmate/tokens/ERC721.sol";
|
|
import {Owned} from "solmate/auth/Owned.sol";
|
|
import {LibString} from "solmate/utils/LibString.sol";
|
|
import {Punkhunt} from "./Punkhunt.sol";
|
|
|
|
/**
|
|
@title Duck
|
|
@author lzamenace.eth
|
|
@notice This contract contains ERC-721 Duck tokens (DUCK) which are used as
|
|
utility tokens for the Punkhunt NFT project and chain based game.
|
|
@dev All contract functions regarding token burning and minting are limited to
|
|
the Punkhunt interface where the logic and validation resides.
|
|
*/
|
|
contract Duck is ERC721, Owned {
|
|
using LibString for uint256;
|
|
|
|
/// Track mints per wallet to enforce maximum
|
|
mapping(address => uint256) public tokensMintedByWallet;
|
|
/// Maximum amount of survivors repunkhunting
|
|
uint256 public constant MAX_SURVIVOR_COUNT = 1;
|
|
/// Maximum amount of mints per wallet
|
|
uint256 public constant MAX_MINT_AMOUNT = 50;
|
|
/// Amount of Ducks killed (tokens burned)
|
|
uint256 public burned;
|
|
/// Amount of Ducks minted
|
|
uint256 public minted;
|
|
/// Base URI for Duck image
|
|
string public baseURI;
|
|
/// Whether or not minting is active (timed edition)
|
|
bool public mintingActive;
|
|
/// Contract address of the deployed Punkhunt contract interface to the game
|
|
Punkhunt public punkhunt;
|
|
|
|
constructor() ERC721("Duck", "DUCK") Owned(msg.sender) {}
|
|
|
|
// =========================================================================
|
|
// Admin
|
|
// =========================================================================
|
|
|
|
/// Set metadata URI for Duck PFPs and explosions
|
|
/// @param _baseURI IPFS hash or URL to retrieve JSON metadata for living Duck tokens
|
|
function setBaseURI(string calldata _baseURI) external onlyOwner {
|
|
baseURI = _baseURI;
|
|
}
|
|
|
|
/// Set punkhunt contract address for executing functions
|
|
/// @param _address Contract address of the deployed Punkhunt contract
|
|
function setPunkhuntContract(address _address) external onlyOwner {
|
|
punkhunt = Punkhunt(_address);
|
|
}
|
|
|
|
/// Toggle minting of DUCK (open edition)
|
|
function toggleMinting() external onlyOwner {
|
|
mintingActive = !mintingActive;
|
|
}
|
|
|
|
// =========================================================================
|
|
// Modifiers
|
|
// =========================================================================
|
|
|
|
/// Limit function execution to deployed Punkhunt contract
|
|
modifier onlyPunkhunt {
|
|
require(msg.sender == address(punkhunt), "invalid msg sender");
|
|
_;
|
|
}
|
|
|
|
// =========================================================================
|
|
// Tokens
|
|
// =========================================================================
|
|
|
|
/// Helper function to get supply minted
|
|
/// @return supply Number of Ducks alive
|
|
function totalSupply() public view returns (uint256) {
|
|
return minted - burned;
|
|
}
|
|
|
|
/// Mint tokens from punkhunt contract
|
|
/// @param _to Address to mint DUCK tokens to
|
|
/// @param _amount Amount of DUCK tokens to mint
|
|
function mint(address _to, uint256 _amount) external onlyPunkhunt {
|
|
require(mintingActive, "minting not active");
|
|
require(tokensMintedByWallet[_to] + _amount <= MAX_MINT_AMOUNT, "cannot exceed maximum per wallet");
|
|
for (uint256 i; i < _amount; i++) {
|
|
minted++;
|
|
_safeMint(_to, minted);
|
|
}
|
|
tokensMintedByWallet[_to] += _amount;
|
|
}
|
|
|
|
/// Toggle token state from living to dead
|
|
/// @param _tokenId Token ID of DUCK to toggle living -> dead and increment kill count
|
|
function die(uint256 _tokenId) external onlyPunkhunt {
|
|
require(_tokenId <= minted, "invalid token id");
|
|
if (ownerOf(_tokenId) != address(0)) {
|
|
burned++;
|
|
_burn(_tokenId);
|
|
}
|
|
}
|
|
|
|
/// Retrieve owner of given token ID
|
|
/// @param _tokenId Token ID to check owner of
|
|
/// @return owner Address of owner
|
|
/// @dev Overridden from Solmate contract to allow zero address returns
|
|
function ownerOf(uint256 _tokenId) public view override returns (address owner) {
|
|
return _ownerOf[_tokenId];
|
|
}
|
|
|
|
// Return URI to retrieve JSON metadata from - points to images and descriptions
|
|
/// @param _tokenId Token ID of DUCK to fetch URI for
|
|
/// @return string IPFS or HTTP URI to retrieve JSON metadata from
|
|
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
|
|
if (ownerOf(_tokenId) == address(0)) {
|
|
return string(abi.encodePacked(baseURI, "dead.json"));
|
|
} else {
|
|
return string(abi.encodePacked(baseURI, "alive.json"));
|
|
}
|
|
}
|
|
|
|
/// Checks if contract supports a given interface
|
|
/// @param interfaceId The interface ID to check if contract supports
|
|
/// @return bool Boolean value if contract supports interface ID or not
|
|
function supportsInterface(bytes4 interfaceId) public view virtual override (ERC721) returns (bool) {
|
|
return super.supportsInterface(interfaceId);
|
|
}
|
|
} |