// SPDX-License-Identifier: MITpragmasolidity 0.8.16;/**
* Utility library of inline functions on addresses
*/libraryAddress{
/**
* 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
*/functionisContract(address account) internalviewreturns (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-assemblyassembly {
codehash :=extcodehash(account)
}
return (codehash != accountHash && codehash !=0x0);
}
}
Contract Source Code
File 2 of 8: BaseERC721.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.16;import"./Addresses.sol";
import"./Strings.sol";
import"./ERC721Receiver.sol";
import"./IERC721.sol";
abstractcontractERC721BasicTokenisIERC721{
usingAddressforaddress;
usingStringsforuint256;
bytes4privateconstant InterfaceId_ERC721 =0x80ac58cd;
bytes4privateconstant InterfaceId_ERC721Exists =0x4f558e79;
bytes4privateconstant ERC721_RECEIVED =0xf0b9e5ba;
bytes4privateconstant InterfaceId_ERC721Enumerable =0x780e9d63;
bytes4privateconstant InterfaceId_ERC721Metadata =0x5b5e139f;
bytes4privateconstant InterfaceId_ERC165 =0x01ffc9a7;
stringinternal name_;
stringinternal symbol_;
stringpublic baseTokenURI;
// Array with all token ids, used for enumerationuint256[] internal allTokens;
// Mapping of interface id to whether or not it's supportedmapping(bytes4=>bool) internal supportedInterfaces;
// Mapping from owner to list of owned token IDsmapping(address=>mapping(uint256=>uint256)) internal ownedTokens;
// Mapping from token ID to index of the owner tokens listmapping(uint256=>uint256) internal ownedTokensIndex;
// Mapping from token id to position in the allTokens arraymapping(uint256=>uint256) internal allTokensIndex;
// Mapping from token ID to ownermapping(uint256=>address) internal tokenOwner;
// Mapping from token ID to approved addressmapping(uint256=>address) internal tokenApprovals;
// Mapping from owner to number of owned tokenmapping(address=>uint256) internal ownedTokensCount;
// Mapping from owner to operator approvalsmapping(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
*/modifieronlyOwnerOf(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
*/modifiercanTransfer(uint256 _tokenId) {
require(isApprovedOrOwner(msg.sender, _tokenId), "Can not transfer");
_;
}
constructor(stringmemory _name,
stringmemory _symbol,
stringmemory _baseTokenUri
) {
name_ = _name;
symbol_ = _symbol;
baseTokenURI = _baseTokenUri;
// register the supported interfaces to confirm 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
*/functionname() externalviewreturns (stringmemory) {
return name_;
}
/**
* @dev Gets the token symbol
* @return string representing the token symbol
*/functionsymbol() externalviewreturns (stringmemory) {
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
*/functiontokenURI(uint256 _tokenId)
publicviewvirtualreturns (stringmemory)
{
require(exists(_tokenId), "Asset does not exist");
returnstring(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
*/functionbalanceOf(address _owner) publicviewreturns (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
*/functionownerOf(uint256 _tokenId) publicviewreturns (address) {
address owner = tokenOwner[_tokenId];
require(owner !=address(0), "Token does not exists");
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
*/functionexists(uint256 _tokenId) publicviewreturns (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
*/functiongetApproved(uint256 _tokenId) publicviewreturns (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
*/functionisApprovedForAll(address _owner, address _operator)
publicviewreturns (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
) internalcanTransfer(_tokenId) {
_transfer(_from, _to, _tokenId);
}
// This function assumes we have verified that _from is allowed to make transactionfunction_transferOnBehalf(address _from,
address _to,
uint256 _tokenId
) internal{
require(isApprovedOrOwner(_from, _tokenId), "Can not transfer");
_transfer(_from, _to, _tokenId);
}
function_transfer(address _from,
address _to,
uint256 _tokenId
) private{
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{
// 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,
bytesmemory _data
) internal{
_transferFrom(_from, _to, _tokenId);
// solium-disable-next-line arg-overflowrequire(
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
*/functionisApprovedOrOwner(address _spender, uint256 _tokenId)
internalviewreturns (bool)
{
address owner = ownerOf(_tokenId);
// Disable solium check because of// https://github.com/duaraghav8/Solium/issues/175// solium-disable-next-line operator-whitespacereturn (_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");
require(!exists(_tokenId), "Asset already exists");
addTokenTo(_to, _tokenId);
allTokensIndex[_tokenId] = allTokens.length;
allTokens.push(_tokenId);
emit Transfer(address(0), _to, _tokenId);
}
functionremoveFromAllTokens(uint256 tokenId) private{
uint256 lastTokenIndex = allTokens.length-1;
uint256 tokenIndex = allTokensIndex[tokenId];
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 arraydelete allTokensIndex[tokenId];
allTokens.pop();
}
/**
* @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)
internalcanTransfer(_tokenId)
{
clearApproval(_owner, _tokenId);
removeTokenFrom(_owner, _tokenId);
removeFromAllTokens(_tokenId);
tokenOwner[_tokenId] =address(0);
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
*/functionclearApproval(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
*/functionaddTokenTo(address _to, uint256 _tokenId) internal{
uint256 length = balanceOf(_to);
ownedTokens[_to][length] = _tokenId;
ownedTokensIndex[_tokenId] = length;
ownedTokensCount[_to] = ownedTokensCount[_to] +1; // increment balance of `_to` by 1
tokenOwner[_tokenId] = _to; // assign `_to` as owner of token
}
/**
* @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
*/functionremoveTokenFrom(address _from, uint256 _tokenId) internal{
uint256 lastTokenIndex = ownedTokensCount[_from] -1;
uint256 tokenIndex = ownedTokensIndex[_tokenId];
// when we want to delete last token, the swap operation in unnecessaryif(lastTokenIndex != tokenIndex) {
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 arraydelete ownedTokensIndex[_tokenId];
delete ownedTokens[_from][lastTokenIndex];
ownedTokensCount[_from] = ownedTokensCount[_from]-1; // decrease balance of _from by 1
}
/**
* @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
*/functioncheckAndCallSafeTransfer(address _from,
address _to,
uint256 _tokenId,
bytesmemory _data
) internalreturns (bool) {
if (!_to.isContract()) {
returntrue;
}
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
*/functiontokenOfOwnerByIndex(address _owner, uint256 _index)
publicviewreturns (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
*/functiontotalSupply() publicviewreturns (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
*/functiontokenByIndex(uint256 _index) publicviewreturns (uint256) {
require(_index < totalSupply(), "Invalid index");
return allTokens[_index];
}
functionsupportsInterface(bytes4 _interfaceId)
externalviewreturns (bool)
{
return supportedInterfaces[_interfaceId];
}
function_registerInterface(bytes4 _interfaceId) internal{
require(_interfaceId !=0xffffffff);
supportedInterfaces[_interfaceId] =true;
}
}
// SPDX-License-Identifier: MITpragmasolidity 0.8.16;/**
* @title ERC721 token receiver interface
* @author Prashant Prabhakar Singh [prashantprabhakar123@gmail.com]
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/abstractcontractERC721Receiver{
/**
* @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`
*/bytes4internalconstant 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)"))`
*/functiononERC721Received(address _from,
uint256 _tokenId,
bytesmemory _data
) publicvirtualreturns (bytes4);
}
// SPDX-License-Identifier: MITpragmasolidity 0.8.16;contractOwnership{
addresspublic owner;
address[] public deputyOwners;
mapping(address=>bool) public isDeputyOwner;
eventOwnershipUpdated(address oldOwner, address newOwner);
eventDeputyOwnerUpdated(address _do, bool _isAdded);
constructor() {
owner =msg.sender;
addDeputyOwner(msg.sender);
}
modifieronlyOwner() {
require(msg.sender== owner, "Caller is not owner");
_;
}
modifieronlyDeputyOrOwner() {
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
*/functionupdateOwner(address _newOwner) publiconlyOwner{
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
*/functionaddDeputyOwner(address _newDO) publiconlyOwner{
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
*/functionremoveDeputyOwner(address _existingDO) publiconlyOwner{
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
*/functionrenounceOwnership(uint256 _validationCode) publiconlyOwner{
require(_validationCode ==123456789, "Invalid code");
owner =address(0);
emit OwnershipUpdated(msg.sender, owner);
}
}
Contract Source Code
File 7 of 8: Strings.sol
// SPDX-License-Identifier: MITpragmasolidity 0.8.16;/**
* @dev String operations.
*/libraryStrings{
/**
* @dev Converts a `uint256` to its ASCII `string` representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
}