Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/**
* Utility library of inline functions on addresses
*/
library Address {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param account address to check
* @return whether the target address is a contract
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./Addresses.sol";
import "./Strings.sol";
import "./ERC721Receiver.sol";
import "./IERC721.sol";
abstract contract ERC721BasicToken is IERC721 {
using Address for address;
using Strings for uint256;
bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd;
bytes4 private constant InterfaceId_ERC721Exists = 0x4f558e79;
bytes4 private constant ERC721_RECEIVED = 0xf0b9e5ba;
bytes4 private constant InterfaceId_ERC721Enumerable = 0x780e9d63;
bytes4 private constant InterfaceId_ERC721Metadata = 0x5b5e139f;
bytes4 private constant InterfaceId_ERC165 = 0x01ffc9a7;
string internal name_;
string internal symbol_;
string public baseTokenURI;
// Array with all token ids, used for enumeration
uint256[] internal allTokens;
// Mapping of interface id to whether or not it's supported
mapping(bytes4 => bool) internal supportedInterfaces;
// Mapping from owner to list of owned token IDs
mapping(address => uint256[]) internal ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) internal ownedTokensIndex;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) internal allTokensIndex;
// Mapping from token ID to owner
mapping(uint256 => address) internal tokenOwner;
// Mapping from token ID to approved address
mapping(uint256 => address) internal tokenApprovals;
// Mapping from owner to number of owned token
mapping(address => uint256) internal ownedTokensCount;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) internal operatorApprovals;
/**
* @dev Guarantees msg.sender is owner of the given token
* @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender
*/
modifier onlyOwnerOf(uint256 _tokenId) {
require(ownerOf(_tokenId) == msg.sender, "Only asset owner is allowed");
_;
}
/**
* @dev Checks msg.sender can transfer a token, by being owner, approved, or operator
* @param _tokenId uint256 ID of the token to validate
*/
modifier canTransfer(uint256 _tokenId) {
require(isApprovedOrOwner(msg.sender, _tokenId), "Can not transfer");
_;
}
constructor(
string memory _name,
string memory _symbol,
string memory _baseTokenUri
) {
name_ = _name;
symbol_ = _symbol;
baseTokenURI = _baseTokenUri;
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721Enumerable);
_registerInterface(InterfaceId_ERC721Metadata);
_registerInterface(InterfaceId_ERC721);
_registerInterface(InterfaceId_ERC721Exists);
_registerInterface(InterfaceId_ERC165);
}
/**
* @dev Gets the token name
* @return string representing the token name
*/
function name() external view returns (string memory) {
return name_;
}
/**
* @dev Gets the token symbol
* @return string representing the token symbol
*/
function symbol() external view returns (string memory) {
return symbol_;
}
/**
* @dev Returns an URI for a given token ID
* Throws if the token ID does not exist. May return an empty string.
* @param _tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 _tokenId)
public
view
virtual
returns (string memory)
{
require(exists(_tokenId), "Asset does not exist");
return string(abi.encodePacked(baseTokenURI, _tokenId.toString()));
}
/**
* @dev Gets the balance of the specified address
* @param _owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address _owner) public view returns (uint256) {
require(_owner != address(0), "Zero address not allowed");
return ownedTokensCount[_owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param _tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0), "Zero address not allowed");
return owner;
}
/**
* @dev Returns whether the specified token exists
* @param _tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
*/
function exists(uint256 _tokenId) public view returns (bool) {
address owner = tokenOwner[_tokenId];
return owner != address(0);
}
/**
* @dev Approves another address to transfer the given token ID
* The zero address indicates there is no approved address.
* There can only be one approved address per token at a given time.
* Can only be called by the token owner or an approved operator.
* @param _to address to be approved for the given token ID
* @param _tokenId uint256 ID of the token to be approved
*/
function _approve(address _to, uint256 _tokenId) internal {
address owner = ownerOf(_tokenId);
require(_to != owner, "Can not approve to self");
require(
msg.sender == owner || isApprovedForAll(owner, msg.sender),
"Not allowed to update approvals"
);
tokenApprovals[_tokenId] = _to;
emit Approval(owner, _to, _tokenId);
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* @param _tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* An operator is allowed to transfer all tokens of the sender on their behalf
* @param _to operator address to set the approval
* @param _approved representing the status of the approval to be set
*/
function _setApprovalForAll(address _to, bool _approved) internal {
require(_to != msg.sender, "Can not approve to self");
operatorApprovals[msg.sender][_to] = _approved;
emit ApprovalForAll(msg.sender, _to, _approved);
}
/**
* @dev Tells whether an operator is approved by a given owner
* @param _owner owner address which you want to query the approval of
* @param _operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(address _owner, address _operator)
public
view
returns (bool)
{
return operatorApprovals[_owner][_operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function _transferFrom(
address _from,
address _to,
uint256 _tokenId
) internal canTransfer(_tokenId) {
require(_from != address(0), "Zero address not allowed");
require(_to != address(0), "Zero address not allowed");
clearApproval(_from, _tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);
emit Transfer(_from, _to, _tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
*
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function _safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) internal canTransfer(_tokenId) {
// solium-disable-next-line arg-overflow
_safeTransferFrom(_from, _to, _tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function _safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes memory _data
) internal canTransfer(_tokenId) {
_transferFrom(_from, _to, _tokenId);
// solium-disable-next-line arg-overflow
require(
checkAndCallSafeTransfer(_from, _to, _tokenId, _data),
"Safe Transfer failed"
);
}
/**
* @dev Returns whether the given spender can transfer a given token ID
* @param _spender address of the spender to query
* @param _tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function isApprovedOrOwner(address _spender, uint256 _tokenId)
internal
view
returns (bool)
{
address owner = ownerOf(_tokenId);
// Disable solium check because of
// https://github.com/duaraghav8/Solium/issues/175
// solium-disable-next-line operator-whitespace
return (_spender == owner ||
getApproved(_tokenId) == _spender ||
isApprovedForAll(owner, _spender));
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param _to The address that will own the minted token
* @param _tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address _to, uint256 _tokenId) internal {
require(_to != address(0), "Zero address not allowed");
addTokenTo(_to, _tokenId);
allTokensIndex[_tokenId] = allTokens.length;
allTokens.push(_tokenId);
emit Transfer(address(0), _to, _tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param _tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address _owner, uint256 _tokenId)
internal
canTransfer(_tokenId)
{
clearApproval(_owner, _tokenId);
removeTokenFrom(_owner, _tokenId);
// Reorg all tokens array
uint256 tokenIndex = allTokensIndex[_tokenId];
uint256 lastTokenIndex = allTokens.length - 1;
uint256 lastToken = allTokens[lastTokenIndex];
allTokens[tokenIndex] = lastToken;
delete allTokens[lastTokenIndex];
//allTokens[lastTokenIndex] = 0;
// allTokens.length--; // @TODO
allTokensIndex[_tokenId] = 0;
allTokensIndex[lastToken] = tokenIndex;
emit Transfer(_owner, address(0), _tokenId);
}
/**
* @dev Internal function to clear current approval of a given token ID
* Reverts if the given address is not indeed the owner of the token
* @param _owner owner of the token
* @param _tokenId uint256 ID of the token to be transferred
*/
function clearApproval(address _owner, uint256 _tokenId) internal {
require(
ownerOf(_tokenId) == _owner,
"Asset does not belong to given owmer"
);
if (tokenApprovals[_tokenId] != address(0)) {
tokenApprovals[_tokenId] = address(0);
emit Approval(_owner, address(0), _tokenId);
}
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @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 addTokenTo(address _to, uint256 _tokenId) internal {
require(tokenOwner[_tokenId] == address(0), "Asset already exists");
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] = ownedTokensCount[_to] + 1;
uint256 length = ownedTokens[_to].length;
ownedTokens[_to].push(_tokenId);
ownedTokensIndex[_tokenId] = length;
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @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 removeTokenFrom(address _from, uint256 _tokenId) internal {
require(
ownerOf(_tokenId) == _from,
"Asset does not belong to given owmer"
);
ownedTokensCount[_from] = ownedTokensCount[_from] - 1;
tokenOwner[_tokenId] = address(0);
uint256 tokenIndex = ownedTokensIndex[_tokenId];
uint256 lastTokenIndex = ownedTokens[_from].length - 1;
uint256 lastToken = ownedTokens[_from][lastTokenIndex];
ownedTokens[_from][tokenIndex] = lastToken;
ownedTokens[_from][lastTokenIndex] = 0;
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
// be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
// the lastToken to the first position, and then dropping the element placed in the last position of the list
//ownedTokens[_from].length--; @TODO
ownedTokensIndex[_tokenId] = 0;
ownedTokensIndex[lastToken] = tokenIndex;
}
/**
* @dev Internal function to invoke `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 whether the call correctly returned the expected magic value
*/
function checkAndCallSafeTransfer(
address _from,
address _to,
uint256 _tokenId,
bytes memory _data
) internal returns (bool) {
if (!_to.isContract()) {
return true;
}
bytes4 retval = ERC721Receiver(_to).onERC721Received(
_from,
_tokenId,
_data
);
return (retval == ERC721_RECEIVED);
}
/**
* @dev Gets the token ID at a given index of the tokens list of the requested owner
* @param _owner address owning the tokens list to be accessed
* @param _index uint256 representing the index to be accessed of the requested tokens list
* @return uint256 token ID at the given index of the tokens list owned by the requested address
*/
function tokenOfOwnerByIndex(address _owner, uint256 _index)
public
view
returns (uint256)
{
require(_index < balanceOf(_owner), "Invalid index");
return ownedTokens[_owner][_index];
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256) {
return allTokens.length;
}
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* Reverts if the index is greater or equal to the total number of tokens
* @param _index uint256 representing the index to be accessed of the tokens list
* @return uint256 token ID at the given index of the tokens list
*/
function tokenByIndex(uint256 _index) public view returns (uint256) {
require(_index < totalSupply(), "Invalid index");
return allTokens[_index];
}
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool)
{
return supportedInterfaces[_interfaceId];
}
function _registerInterface(bytes4 _interfaceId) internal {
require(_interfaceId != 0xffffffff);
supportedInterfaces[_interfaceId] = true;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./BaseERC721.sol";
contract ERC721 is ERC721BasicToken {
mapping(uint256 => string) internal _tokenUri;
event TokenURIUpdated(uint256 tokenId, string _url);
event BaseTokenURIUpdated(string _baseUrl);
constructor(
string memory _name,
string memory _symbol,
string memory _baseTokenUri
) ERC721BasicToken(_name, _symbol, _baseTokenUri) {
emit BaseTokenURIUpdated(_baseTokenUri);
}
function approve(address _to, uint256 _tokenId) public {
super._approve(_to, _tokenId);
}
function setApprovalForAll(address _to, bool _approved) public {
super._setApprovalForAll(_to, _approved);
}
function transferFrom(
address _from,
address _to,
uint256 _tokenId
) public virtual {
super._transferFrom(_from, _to, _tokenId);
}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) public virtual {
super._safeTransferFrom(_from, _to, _tokenId, "0x");
}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes memory _data
) public virtual {
super._safeTransferFrom(_from, _to, _tokenId, _data);
}
function _updateTokenUri(uint256 _tokenId, string memory _url) internal {
_tokenUri[_tokenId] = _url;
emit TokenURIUpdated(_tokenId, _url);
}
function _updateBaseTokenUri(string memory _baseTokenUri) internal {
baseTokenURI = _baseTokenUri;
emit BaseTokenURIUpdated(_baseTokenUri);
}
function mint(
address _to,
uint256 _tokenId,
string memory _url
) internal {
_updateTokenUri(_tokenId, _url);
super._mint(_to, _tokenId);
}
function burn(uint256 _tokenId) public virtual {
super._burn(ownerOf(_tokenId), _tokenId);
}
function tokenURI(uint256 _tokenId)
public
view
override
returns (string memory)
{
require(exists(_tokenId), "Asset does not exist");
return string(abi.encodePacked(baseTokenURI, _tokenUri[_tokenId]));
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/**
* @title ERC721 token receiver interface
* @author Prashant Prabhakar Singh [[email protected]]
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
abstract contract ERC721Receiver {
/**
* @dev Magic value to be returned upon successful reception of an NFT
* Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`,
* which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
*/
bytes4 internal constant ERC721_RECEIVED = 0xf0b9e5ba;
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safetransfer`. This function MAY throw to revert and reject the
* transfer. This function MUST use 50,000 gas or less. Return of other
* than the magic value MUST result in the transaction being reverted.
* Note: the contract address is always the message sender.
* @param _from The sending address
* @param _tokenId The NFT identifier which is being transfered
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
*/
function onERC721Received(
address _from,
uint256 _tokenId,
bytes memory _data
) public virtual returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @author Prashant Prabhakar Singh [[email protected]]
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
interface IERC721 {
event Transfer(
address indexed _from,
address indexed _to,
uint256 indexed _tokenId
);
event Approval(
address indexed _owner,
address indexed _approved,
uint256 indexed _tokenId
);
event ApprovalForAll(
address indexed _owner,
address indexed _operator,
bool _approved
);
function balanceOf(address _owner) external view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) external view returns (address _owner);
function exists(uint256 _tokenId) external view returns (bool _exists);
function approve(address _to, uint256 _tokenId) external;
function getApproved(uint256 _tokenId)
external
view
returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator)
external
view
returns (bool);
function transferFrom(
address _from,
address _to,
uint256 _tokenId
) external;
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) external;
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes memory _data
) external;
function name() external view returns (string memory _name);
function symbol() external view returns (string memory _symbol);
function tokenURI(uint256 _tokenId) external view returns (string memory);
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index)
external
view
returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) external view returns (uint256);
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import "./ERC721.sol";
import "./Ownership.sol";
contract MintPass is ERC721, Ownership {
// represents how many times a mint pass is redeemed.
mapping(uint256 => uint8) private redeemedTimes;
// contracts that can update mint pass uses, like when minting art, art nft will updated `redeemedTimes`
mapping(address => bool) public isWhitelisted;
// nonce to prevent replay attack on admin signature
mapping(uint256 => bool) public isSignerNonceUsed;
bool public mintStoppted; // when enabled no futher mint pass can be minted.
uint256 public maxSupply; // max supply of mint pass
bool public isPaused = false; // pause the contractn when something goes "really" wrong
uint8 constant UINT8_MAX = 255;
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
}
event MintPassUpdated(
uint256 tokenId,
uint8 redeemedTimes,
address updatedBy
);
event Paused(bool _isPaused);
modifier canAcceptMintPass(address user) {
require(balanceOf(user) == 0, "Only 1 mint pass allowed per user");
_;
}
modifier mintAllowed() {
require(!mintStoppted, "Minting stopped");
_;
}
modifier notPaused() {
require(!isPaused, "Contract paused");
_;
}
constructor(string memory _baseTokenUri)
ERC721("Thunderbirds: IRC Mint Pass", "TBMP", _baseTokenUri)
{
maxSupply = 1000;
}
function mint(
address user,
Signature memory adminSignature,
uint256 signerNonce
) public canAcceptMintPass(user) mintAllowed notPaused {
require(totalSupply() < maxSupply, "Max token minted");
require(
!isSignerNonceUsed[signerNonce],
"Duplicate nonce in signature"
);
bytes32 hash = keccak256(
abi.encodePacked(
bytes4(keccak256("mint")),
address(this),
signerNonce,
getChainID(),
user
)
);
address signer = getSigner(hash, adminSignature);
require(isDeputyOwner[signer], "Invalid signature/message");
isSignerNonceUsed[signerNonce] = true;
string memory url = "QmXyV2HUP7hv8Xjx3X6ZLUUMHkxsdRuQhZ9DwpzZqH16jD";
super.mint(user, totalSupply() + 1, url);
}
function batchMintByAdmin(address[] memory users) public mintAllowed onlyDeputyOrOwner {
require(totalSupply() + users.length < maxSupply, "Max token minted");
string memory url = "QmXyV2HUP7hv8Xjx3X6ZLUUMHkxsdRuQhZ9DwpzZqH16jD";
for(uint8 i=0; i<users.length; i++) {
require(balanceOf(users[i]) == 0, "Only 1 mint pass allowed per user");
super.mint(users[i], totalSupply() + 1, url);
}
}
function updateRedeemedTimes(uint256 tokenId, uint8 _redeemedTimes)
public
notPaused
{
require(isWhitelisted[msg.sender], "Caller not whitelisted");
redeemedTimes[tokenId] = _redeemedTimes;
emit MintPassUpdated(tokenId, _redeemedTimes, msg.sender);
}
function transferFrom(
address _from,
address _to,
uint256 _tokenId
) public override canAcceptMintPass(_to) notPaused {
super._transferFrom(_from, _to, _tokenId);
}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) public override canAcceptMintPass(_to) notPaused {
super._safeTransferFrom(_from, _to, _tokenId, "0x");
}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes memory _data
) public override canAcceptMintPass(_to) notPaused {
super._safeTransferFrom(_from, _to, _tokenId, _data);
}
function burn(uint256 _tokenId) public override notPaused {
super.burn(_tokenId);
}
function updateTokenUri(uint256 _tokenId, string memory _url)
public
onlyDeputyOrOwner
{
super._updateTokenUri(_tokenId, _url);
}
function updateBaseTokenUri(string memory _baseTokenUri) public onlyOwner {
super._updateBaseTokenUri(_baseTokenUri);
}
function whitelistContract(address contractAddress) public onlyOwner {
isWhitelisted[contractAddress] = true;
}
function removeFromWhitelist(address contractAddress) public onlyOwner {
isWhitelisted[contractAddress] = false;
}
function disableMinting(bool shoudlStop) public onlyOwner {
mintStoppted = shoudlStop;
}
function pauseContract(bool _isPaused) public onlyOwner returns (bool) {
isPaused = _isPaused;
emit Paused(_isPaused);
return true;
}
function getSigner(bytes32 message, Signature memory sig)
public
pure
returns (address)
{
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, message));
address signer = ecrecover(prefixedHash, sig.v, sig.r, sig.s);
return signer;
}
function getRedeemedTimes(uint256 tokenId) public view returns(uint8) {
if(!exists(tokenId)) return UINT8_MAX;
return redeemedTimes[tokenId];
}
function getChainID() internal view returns (uint256) {
uint256 id;
assembly {
id := chainid()
}
return id;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
contract Ownership {
address public owner;
address[] public deputyOwners;
mapping(address => bool) public isDeputyOwner;
event OwnershipUpdated(address oldOwner, address newOwner);
event DeputyOwnerUpdated(address _do, bool _isAdded);
constructor() {
owner = msg.sender;
addDeputyOwner(msg.sender);
}
modifier onlyOwner() {
require(msg.sender == owner, "Caller is not owner");
_;
}
modifier onlyDeputyOrOwner() {
require(
msg.sender == owner || isDeputyOwner[msg.sender],
"Caller is not owner or deputy"
);
_;
}
/**
* @dev Transfer the ownership to some other address.
* new owner can not be a zero address.
* Only owner can call this function
* @param _newOwner Address to which ownership is being transferred
*/
function updateOwner(address _newOwner) public onlyOwner {
require(_newOwner != address(0x0), "Invalid address");
owner = _newOwner;
emit OwnershipUpdated(msg.sender, owner);
}
/**
* @dev Add new deputy owner.
* Only Owner can call this function
* New Deputy should not be zero address
* New Deputy should not be be already exisitng
* emit DeputyOwnerUdpatd event
* @param _newDO Address of new deputy owner
*/
function addDeputyOwner(address _newDO) public onlyOwner {
require(!isDeputyOwner[_newDO], "Deputy Owner already exists");
deputyOwners.push(_newDO);
isDeputyOwner[_newDO] = true;
emit DeputyOwnerUpdated(_newDO, true);
}
/**
* @dev Remove an existing deputy owner.
* Only Owner can call this function
* Given address should be a deputy owner
* emit DeputyOwnerUdpatd event
* @param _existingDO Address of existing deputy owner
*/
function removeDeputyOwner(address _existingDO) public onlyOwner {
require(isDeputyOwner[_existingDO], "Deputy Owner does not exits");
uint256 existingId;
for (uint256 i = 0; i < deputyOwners.length; i++) {
if (deputyOwners[i] == _existingDO) existingId = i;
}
// swap this with last element
deputyOwners[existingId] = deputyOwners[deputyOwners.length - 1];
delete deputyOwners[deputyOwners.length - 1];
isDeputyOwner[_existingDO] = false;
emit DeputyOwnerUpdated(_existingDO, false);
}
/**
* @dev Renounce the ownership.
* This will leave the contract without any owner.
* Only owner can call this function
* @param _validationCode A code to prevent accidental calling of this function
*/
function renounceOwnership(uint256 _validationCode) public onlyOwner {
require(_validationCode == 123456789, "Invalid code");
owner = address(0);
emit OwnershipUpdated(msg.sender, owner);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
/**
* @dev String operations.
*/
library Strings {
/**
* @dev Converts a `uint256` to its ASCII `string` representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// 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);
}
}