Contract Name:
CustomToken
Contract Source Code:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import { LibDiamond } from "../libraries/LibDiamond.sol";
import '@solidstate/contracts/token/ERC721/enumerable/ERC721Enumerable.sol';
import "../libraries/MyNFTTokenLibrary.sol";
import { AppStorage, Trait } from "../libraries/LibAppStorage.sol";
import { ERC721Base } from '@solidstate/contracts/token/ERC721/base/ERC721Base.sol';
import { ERC721BaseStorage } from '@solidstate/contracts/token/ERC721/base/ERC721BaseStorage.sol';
import { ERC165 } from '@solidstate/contracts/introspection/ERC165.sol';
import "@openzeppelin/contracts/utils/Strings.sol";
contract CustomToken is ERC721Enumerable, ERC721Base {
using ERC721BaseStorage for ERC721BaseStorage.Layout;
using MyNFTTokenLibrary for uint8;
AppStorage private s;
// This implements ERC-165.
function supportsInterface(bytes4 _interfaceId) external override pure returns (bool) {
return true;
}
/**
* @dev Converts a digit from 0 - 10000 into its corresponding rarity based on the given rarity tier.
* @param _randinput The input from 0 - 10000 to use for rarity gen.
* @param _rarityTier The tier to use.
*/
function rarityGen(uint256 _randinput, uint8 _rarityTier)
internal
view
returns (string memory)
{
uint16 currentLowerBound = 0;
for (uint8 i = 0; i < s.TIERS[_rarityTier].length; i++) {
uint16 thisPercentage = s.TIERS[_rarityTier][i];
if (
_randinput >= currentLowerBound &&
_randinput < currentLowerBound + thisPercentage
) {
return s.LETTERS[i];
}
currentLowerBound = currentLowerBound + thisPercentage;
}
revert();
}
/**
* @dev Mint internal, this is to avoid code duplication.
*/
function mintInternal() internal {
uint256 _totalSupply = totalSupply();
require(_totalSupply < s.MAX_SUPPLY);
require(!MyNFTTokenLibrary.isContract(msg.sender));
uint256 thisTokenId = _totalSupply;
s.tokenIdToHash[thisTokenId] = hash(thisTokenId, msg.sender, 0);
s.hashToMinted[s.tokenIdToHash[thisTokenId]] = true;
_mint(msg.sender, thisTokenId);
}
/**
* @dev Mints new tokens.
*/
function mint() public {
return mintInternal();
}
/**
* @dev Generates a 7 digit hash from a tokenId, address, and random number.
* @param _t The token id to be used within the hash.
* @param _a The address to be used within the hash.
* @param _c The custom nonce to be used within the hash.
*/
function hash(
uint256 _t,
address _a,
uint256 _c
) internal returns (string memory) {
require(_c < 80);
// This will generate a 7 character string.
//The last 6 digits are random, the first is a, due to the nft not being burned.
string memory currentHash = "";
for (uint8 i = 0; i < 6; i++) {
s.SEED_NONCE++;
uint16 _randinput = uint16(
uint256(
keccak256(
abi.encodePacked(
block.timestamp,
block.coinbase,
block.difficulty,
_t,
_a,
_c,
s.SEED_NONCE
)
)
) % 10000
);
currentHash = string(
abi.encodePacked(currentHash, rarityGen(_randinput, i))
);
}
if (s.hashToMinted[currentHash]) return hash(_t, _a, _c + 1);
return currentHash;
}
// custom code...
/**
* @dev Returns the SVG and metadata for a token Id
* @param _tokenId The tokenId to return the SVG and metadata for.
*/
function tokenURI(uint256 _tokenId)
public
view
returns (string memory)
{
require(ERC721BaseStorage.layout().exists(_tokenId));
string memory thisName = s.name;
string memory tokenHash = s.tokenIdToHash[_tokenId];
string memory name = string(abi.encodePacked("", thisName, " #", MyNFTTokenLibrary.toString(_tokenId)));
string memory bio = string(abi.encodePacked("Stored 100% on-chain. ", s.name, " #", MyNFTTokenLibrary.toString(_tokenId)));
return
string(
abi.encodePacked(
"data:application/json;base64,",
MyNFTTokenLibrary.encode(
bytes(
string(
abi.encodePacked(
'{"name": "',
name,
'", "description": "',
bio,
'","image": "data:image/svg+xml;base64,',
MyNFTTokenLibrary.encode(
bytes(hashToSVG(tokenHash))
),
'","attributes":',
hashToMetadata(tokenHash),
"}"
)
)
)
)
)
);
}
/**
* @dev Hash to metadata function
*/
function hashToMetadata(string memory _hash)
internal
view
returns (string memory)
{
string memory metadataString = '';
for (uint8 i = 0; i < 6;) {
uint256 thisTraitIndex = letterToNumber(
MyNFTTokenLibrary.substring(_hash, i, i + 1)
);
metadataString = string(
abi.encodePacked(
metadataString,
'{"trait_type":"',
s.traitTypes[i][thisTraitIndex].traitType,
'","value":"',
s.traitTypes[i][thisTraitIndex].traitName,
'"}'
)
);
if (i != 5)
metadataString = string(abi.encodePacked(metadataString, ","));
unchecked {
++i;
}
}
return string(abi.encodePacked("[", metadataString, "]"));
}
/**
* @dev Hash to SVG function
*/
function hashToSVG(string memory _hash)
public
view
returns (string memory)
{
string memory svgString = "";
bool[24][24][24] memory placedPixels;
for (uint8 i = 0; i < 6; i++) {
uint8 thisTraitIndex = letterToNumber(MyNFTTokenLibrary.substring(_hash, i, i + 1));
for (
uint8 k = 0;
k < s.traitTypes[i][thisTraitIndex].pixelCount.length;
k++
) {
string memory da = "";
for (
uint8 p = 0;
p < s.traitTypes[i][thisTraitIndex].pixelCount.length;
p++
) {
if (p == k) {
da = string(abi.encodePacked(da, "inline;"));
} else {
da = string(abi.encodePacked(da, "none;"));
}
}
if (s.traitTypes[i][thisTraitIndex].pixelCount[k] > 0) {
svgString = string(
abi.encodePacked(
svgString,
"<g>",
"<animate id='", s.LETTERS[k], "' attributeName='display' values='", da, "' repeatCount='indefinite' dur='0.45s' begin='0s'/>"
)
);
}
for (
uint256 j = 0;
j < s.traitTypes[i][thisTraitIndex].pixelCount[k];
j++
) {
string memory thisPixel = MyNFTTokenLibrary.substring(
s.traitTypes[i][thisTraitIndex].pixels[k],
j * 4,
j * 4 + 4
);
uint8 x = letterToNumber(
MyNFTTokenLibrary.substring(thisPixel, 0, 1)
);
uint8 y = letterToNumber(
MyNFTTokenLibrary.substring(thisPixel, 1, 2)
);
if (placedPixels[k][x][y]) continue;
string memory color = MyNFTTokenLibrary.substring(thisPixel, 2, 4);
svgString = string(
abi.encodePacked(
svgString,
"<rect class='c",
color,
"' x='",
x.toString(),
"' y='",
y.toString(),
"'></rect>"
)
);
placedPixels[k][x][y] = true;
}
if (s.traitTypes[i][thisTraitIndex].pixelCount[k] > 0) {
svgString = string(
abi.encodePacked(
svgString,
"</g>"
)
);
}
}
}
svgString = string(
abi.encodePacked(
'<svg id="svg" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 24 24"> ',
svgString,
"<style>rect{width:1px;height:1px;}#svg{shape-rendering: crispedges;}.c00{fill:#000000}.c01{fill:#222034}.c02{fill:#45283c}.c03{fill:#663931}.c04{fill:#8f563b}.c05{fill:#df7126}.c06{fill:#d9a066}.c07{fill:#eec39a}.c08{fill:#fbf236}.c09{fill:#99e550}.c10{fill:#6abe30}.c11{fill:#37946e}.c12{fill:#4b692f}.c13{fill:#524b24}.c14{fill:#323c39}.c15{fill:#3f3f74}.c16{fill:#306082}.c17{fill:#5b6ee1}.c18{fill:#639bff}.c19{fill:#5fcde4}.c20{fill:#cbdbfc}.c21{fill:#ffffff}.c22{fill:#9badb7}.c23{fill:#847e87}.c24{fill:#696a6a}.c25{fill:#595652}.c26{fill:#76428a}.c27{fill:#ac3232}.c28{fill:#d95763}.c29{fill:#d77bba}.c30{fill:#8f974a}.c31{fill:#8a6f30}.c32{fill:#814848}.c33{fill:#9d4a4a}.c34{fill:#403640}.c35{fill:#868282}.c36{fill:#424058}.c37{fill:#2f315a}.c38{fill:#34378b}.c39{fill:#dcd530}.c40{fill:#fefff4}.c41{fill:#e3e1e1}.c42{fill:#634464}.c43{fill:#7d4881}.c44{fill:#b549bc}.c45{fill:#343cff}.c46{fill:#f6d953}.c47{fill:#bd8228}.c48{fill:#ebb337}</style>",
"</svg>"
)
);
return svgString;
}
/**
* @dev Helper function to reduce pixel size within contract
*/
function letterToNumber(string memory _inputLetter)
internal
view
returns (uint8)
{
for (uint8 i = 0; i < s.LETTERS.length;) {
if (
keccak256(abi.encodePacked((s.LETTERS[i]))) ==
keccak256(abi.encodePacked((_inputLetter)))
) return i;
unchecked { ++i; }
}
revert();
}
modifier onlyOwner() {
require(s._owner == msg.sender, "only owner");
_;
}
/**
* @dev Clears the traits.
// */
// function clearTraits() public onlyOwner {
// for (uint256 i = 0; i < 6; i++) {
// delete s.traitTypes[i];
// }
// }
/**
* @dev Add a trait type
* @param _traitTypeIndex The trait type index
* @param traits Array of traits to add
*/
function addTraitType(uint256 _traitTypeIndex, Trait[] memory traits)
public
onlyOwner
{
for (uint256 i = 0; i < traits.length; i++) {
s.traitTypes[_traitTypeIndex].push(
Trait(
traits[i].traitName,
traits[i].traitType,
traits[i].pixels,
traits[i].pixelCount
)
);
}
return;
}
/**
* @dev Returns the wallet of a given wallet. Mainly for ease for frontend devs.
* @param _wallet The wallet to get the tokens of.
*/
function walletOfOwner(address _wallet)
public
view
returns (uint256[] memory)
{
uint256 tokenCount = _balanceOf(_wallet);
uint256[] memory tokensId = new uint256[](tokenCount);
for (uint256 i; i < tokenCount; i++) {
tokensId[i] = tokenOfOwnerByIndex(_wallet, i);
}
return tokensId;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
import { IDiamondCut } from "../interfaces/IDiamondCut.sol";
library LibDiamond {
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
struct FacetAddressAndPosition {
address facetAddress;
uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
}
struct FacetFunctionSelectors {
bytes4[] functionSelectors;
uint256 facetAddressPosition; // position of facetAddress in facetAddresses array
}
struct DiamondStorage {
// maps function selector to the facet address and
// the position of the selector in the facetFunctionSelectors.selectors array
mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
// maps facet addresses to function selectors
mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
// facet addresses
address[] facetAddresses;
// Used to query if a contract implements an interface.
// Used to implement ERC-165.
mapping(bytes4 => bool) supportedInterfaces;
// owner of the contract
address contractOwner;
}
function diamondStorage() internal pure returns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot := position
}
}
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function setContractOwner(address _newOwner) internal {
DiamondStorage storage ds = diamondStorage();
address previousOwner = ds.contractOwner;
ds.contractOwner = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
function contractOwner() internal view returns (address contractOwner_) {
contractOwner_ = diamondStorage().contractOwner;
}
function enforceIsContractOwner() internal view {
require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
}
event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
// Internal function version of diamondCut
function diamondCut(
IDiamondCut.FacetCut[] memory _diamondCut,
address _init,
bytes memory _calldata
) internal {
for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
if (action == IDiamondCut.FacetCutAction.Add) {
addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
} else if (action == IDiamondCut.FacetCutAction.Replace) {
replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
} else if (action == IDiamondCut.FacetCutAction.Remove) {
removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
} else {
revert("LibDiamondCut: Incorrect FacetCutAction");
}
}
emit DiamondCut(_diamondCut, _init, _calldata);
initializeDiamondCut(_init, _calldata);
}
function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
DiamondStorage storage ds = diamondStorage();
require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
// add new facet address if it does not exist
if (selectorPosition == 0) {
addFacet(ds, _facetAddress);
}
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
addFunction(ds, selector, selectorPosition, _facetAddress);
selectorPosition++;
}
}
function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
DiamondStorage storage ds = diamondStorage();
require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
// add new facet address if it does not exist
if (selectorPosition == 0) {
addFacet(ds, _facetAddress);
}
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
removeFunction(ds, oldFacetAddress, selector);
addFunction(ds, selector, selectorPosition, _facetAddress);
selectorPosition++;
}
}
function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
DiamondStorage storage ds = diamondStorage();
// if function does not exist then do nothing and return
require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
removeFunction(ds, oldFacetAddress, selector);
}
}
function addFacet(DiamondStorage storage ds, address _facetAddress) internal {
enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length;
ds.facetAddresses.push(_facetAddress);
}
function addFunction(DiamondStorage storage ds, bytes4 _selector, uint96 _selectorPosition, address _facetAddress) internal {
ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition;
ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector);
ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
}
function removeFunction(DiamondStorage storage ds, address _facetAddress, bytes4 _selector) internal {
require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
// an immutable function is a function defined directly in a diamond
require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
// replace selector with last selector, then delete last selector
uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
// if not the same then replace _selector with lastSelector
if (selectorPosition != lastSelectorPosition) {
bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition);
}
// delete the last selector
ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
delete ds.selectorToFacetAndPosition[_selector];
// if no more selectors for facet address then delete the facet address
if (lastSelectorPosition == 0) {
// replace facet address with last facet address and delete last facet address
uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
if (facetAddressPosition != lastFacetAddressPosition) {
address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition;
}
ds.facetAddresses.pop();
delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
}
}
function initializeDiamondCut(address _init, bytes memory _calldata) internal {
if (_init == address(0)) {
require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
} else {
require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
if (_init != address(this)) {
enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
}
(bool success, bytes memory error) = _init.delegatecall(_calldata);
if (!success) {
if (error.length > 0) {
// bubble up the error
revert(string(error));
} else {
revert("LibDiamondCut: _init function reverted");
}
}
}
}
function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
uint256 contractSize;
assembly {
contractSize := extcodesize(_contract)
}
require(contractSize > 0, _errorMessage);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/EnumerableSet.sol';
import { ERC721BaseStorage } from '../base/ERC721BaseStorage.sol';
import { IERC721Enumerable } from './IERC721Enumerable.sol';
import { ERC721EnumerableInternal } from './ERC721EnumerableInternal.sol';
abstract contract ERC721Enumerable is
IERC721Enumerable,
ERC721EnumerableInternal
{
using EnumerableMap for EnumerableMap.UintToAddressMap;
using EnumerableSet for EnumerableSet.UintSet;
/**
* @inheritdoc IERC721Enumerable
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply();
}
/**
* @inheritdoc IERC721Enumerable
*/
function tokenOfOwnerByIndex(address owner, uint256 index)
public
view
override
returns (uint256)
{
return _tokenOfOwnerByIndex(owner, index);
}
/**
* @inheritdoc IERC721Enumerable
*/
function tokenByIndex(uint256 index)
public
view
override
returns (uint256)
{
return _tokenByIndex(index);
}
}
// Forked from Anonymice
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library MyNFTTokenLibrary {
string internal constant TABLE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
// load the table into memory
string memory table = TABLE;
// multiply by 4/3 rounded up
uint256 encodedLen = 4 * ((data.length + 2) / 3);
// add some extra buffer at the end required for the writing
string memory result = new string(encodedLen + 32);
assembly {
// set the actual output length
mstore(result, encodedLen)
// prepare the lookup table
let tablePtr := add(table, 1)
// input ptr
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
// result ptr, jump over length
let resultPtr := add(result, 32)
// run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
dataPtr := add(dataPtr, 3)
// read 3 bytes
let input := mload(dataPtr)
// write 4 characters
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(shr(6, input), 0x3F))))
)
resultPtr := add(resultPtr, 1)
mstore(
resultPtr,
shl(248, mload(add(tablePtr, and(input, 0x3F))))
)
resultPtr := add(resultPtr, 1)
}
// padding with '='
switch mod(mload(data), 3)
case 1 {
mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
}
case 2 {
mstore(sub(resultPtr, 1), shl(248, 0x3d))
}
}
return result;
}
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
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);
}
function parseInt(string memory _a)
internal
pure
returns (uint8 _parsedInt)
{
bytes memory bresult = bytes(_a);
uint8 mint = 0;
for (uint8 i = 0; i < bresult.length; i++) {
if (
(uint8(uint8(bresult[i])) >= 48) &&
(uint8(uint8(bresult[i])) <= 57)
) {
mint *= 10;
mint += uint8(bresult[i]) - 48;
}
}
return mint;
}
function substring(
string memory str,
uint256 startIndex,
uint256 endIndex
) internal pure returns (string memory) {
bytes memory strBytes = bytes(str);
bytes memory result = new bytes(endIndex - startIndex);
for (uint256 i = startIndex; i < endIndex; i++) {
result[i - startIndex] = strBytes[i];
}
return string(result);
}
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
pragma solidity ^0.8.0;
struct Trait {
string traitName;
string traitType;
string[] pixels;
uint256[] pixelCount;
}
struct AppStorage {
mapping(uint256 => Trait[]) traitTypes;
mapping(string => bool) hashToMinted;
mapping(uint256 => string) tokenIdToHash;
mapping(uint256 => string) tokenIdToName;
mapping(uint256 => string) tokenIdToBio;
mapping(uint256 => uint256) tokenIdToLevel;
mapping (string => bool) nameReserved;
uint256 LAST_MINT_TIME;
uint256 MAX_SUPPLY;
uint256 SEED_NONCE;
uint16[][20] TIERS;
string name;
string[] LETTERS;
address _owner;
}
library LibAppStorage {
function diamondStorage() internal pure returns (AppStorage storage ds) {
assembly {
ds.slot := 0
}
}
function abs(int256 x) internal pure returns (uint256) {
return uint256(x >= 0 ? x : -x);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { AddressUtils } from '../../../utils/AddressUtils.sol';
import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/EnumerableSet.sol';
import { IERC721 } from '../IERC721.sol';
import { IERC721Receiver } from '../IERC721Receiver.sol';
import { ERC721BaseStorage } from './ERC721BaseStorage.sol';
import { ERC721BaseInternal } from './ERC721BaseInternal.sol';
/**
* @notice Base ERC721 implementation, excluding optional extensions
*/
abstract contract ERC721Base is IERC721, ERC721BaseInternal {
using AddressUtils for address;
using EnumerableMap for EnumerableMap.UintToAddressMap;
using EnumerableSet for EnumerableSet.UintSet;
/**
* @inheritdoc IERC721
*/
function balanceOf(address account) public view override returns (uint256) {
return _balanceOf(account);
}
/**
* @inheritdoc IERC721
*/
function ownerOf(uint256 tokenId) public view override returns (address) {
return _ownerOf(tokenId);
}
/**
* @inheritdoc IERC721
*/
function getApproved(uint256 tokenId)
public
view
override
returns (address)
{
return _getApproved(tokenId);
}
/**
* @inheritdoc IERC721
*/
function isApprovedForAll(address account, address operator)
public
view
override
returns (bool)
{
return _isApprovedForAll(account, operator);
}
/**
* @inheritdoc IERC721
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable override {
_handleTransferMessageValue(from, to, tokenId, msg.value);
require(
_isApprovedOrOwner(msg.sender, tokenId),
'ERC721: transfer caller is not owner or approved'
);
_transfer(from, to, tokenId);
}
/**
* @inheritdoc IERC721
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @inheritdoc IERC721
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory data
) public payable override {
_handleTransferMessageValue(from, to, tokenId, msg.value);
require(
_isApprovedOrOwner(msg.sender, tokenId),
'ERC721: transfer caller is not owner or approved'
);
_safeTransfer(from, to, tokenId, data);
}
/**
* @inheritdoc IERC721
*/
function approve(address operator, uint256 tokenId)
public
payable
override
{
_handleApproveMessageValue(operator, tokenId, msg.value);
address owner = ownerOf(tokenId);
require(operator != owner, 'ERC721: approval to current owner');
require(
msg.sender == owner || isApprovedForAll(owner, msg.sender),
'ERC721: approve caller is not owner nor approved for all'
);
_approve(operator, tokenId);
}
/**
* @inheritdoc IERC721
*/
function setApprovalForAll(address operator, bool status) public override {
require(operator != msg.sender, 'ERC721: approve to caller');
ERC721BaseStorage.layout().operatorApprovals[msg.sender][
operator
] = status;
emit ApprovalForAll(msg.sender, operator, status);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/EnumerableSet.sol';
library ERC721BaseStorage {
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableMap for EnumerableMap.UintToAddressMap;
bytes32 internal constant STORAGE_SLOT =
keccak256('solidstate.contracts.storage.ERC721Base');
struct Layout {
EnumerableMap.UintToAddressMap tokenOwners;
mapping(address => EnumerableSet.UintSet) holderTokens;
mapping(uint256 => address) tokenApprovals;
mapping(address => mapping(address => bool)) operatorApprovals;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
function exists(Layout storage l, uint256 tokenId)
internal
view
returns (bool)
{
return l.tokenOwners.contains(tokenId);
}
function totalSupply(Layout storage l) internal view returns (uint256) {
return l.tokenOwners.length();
}
function tokenOfOwnerByIndex(
Layout storage l,
address owner,
uint256 index
) internal view returns (uint256) {
return l.holderTokens[owner].at(index);
}
function tokenByIndex(Layout storage l, uint256 index)
internal
view
returns (uint256)
{
(uint256 tokenId, ) = l.tokenOwners.at(index);
return tokenId;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC165 } from './IERC165.sol';
import { ERC165Storage } from './ERC165Storage.sol';
/**
* @title ERC165 implementation
*/
abstract contract ERC165 is IERC165 {
using ERC165Storage for ERC165Storage.Layout;
/**
* @inheritdoc IERC165
*/
function supportsInterface(bytes4 interfaceId)
public
view
override
returns (bool)
{
return ERC165Storage.layout().isSupportedInterface(interfaceId);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal 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);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
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] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
interface IDiamondCut {
enum FacetCutAction {Add, Replace, Remove}
// Add=0, Replace=1, Remove=2
struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}
/// @notice Add/replace/remove any number of functions and optionally execute
/// a function with delegatecall
/// @param _diamondCut Contains the facet addresses and function selectors
/// @param _init The address of the contract or facet to execute _calldata
/// @param _calldata A function call, including function selector and arguments
/// _calldata is executed with delegatecall on _init
function diamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytes calldata _calldata
) external;
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Map implementation with enumeration functions
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
*/
library EnumerableMap {
struct MapEntry {
bytes32 _key;
bytes32 _value;
}
struct Map {
MapEntry[] _entries;
// 1-indexed to allow 0 to signify nonexistence
mapping(bytes32 => uint256) _indexes;
}
struct AddressToAddressMap {
Map _inner;
}
struct UintToAddressMap {
Map _inner;
}
function at(AddressToAddressMap storage map, uint256 index)
internal
view
returns (address, address)
{
(bytes32 key, bytes32 value) = _at(map._inner, index);
address addressKey;
assembly {
addressKey := mload(add(key, 20))
}
return (addressKey, address(uint160(uint256(value))));
}
function at(UintToAddressMap storage map, uint256 index)
internal
view
returns (uint256, address)
{
(bytes32 key, bytes32 value) = _at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
function contains(AddressToAddressMap storage map, address key)
internal
view
returns (bool)
{
return _contains(map._inner, bytes32(uint256(uint160(key))));
}
function contains(UintToAddressMap storage map, uint256 key)
internal
view
returns (bool)
{
return _contains(map._inner, bytes32(key));
}
function length(AddressToAddressMap storage map)
internal
view
returns (uint256)
{
return _length(map._inner);
}
function length(UintToAddressMap storage map)
internal
view
returns (uint256)
{
return _length(map._inner);
}
function get(AddressToAddressMap storage map, address key)
internal
view
returns (address)
{
return
address(
uint160(
uint256(_get(map._inner, bytes32(uint256(uint160(key)))))
)
);
}
function get(UintToAddressMap storage map, uint256 key)
internal
view
returns (address)
{
return address(uint160(uint256(_get(map._inner, bytes32(key)))));
}
function set(
AddressToAddressMap storage map,
address key,
address value
) internal returns (bool) {
return
_set(
map._inner,
bytes32(uint256(uint160(key))),
bytes32(uint256(uint160(value)))
);
}
function set(
UintToAddressMap storage map,
uint256 key,
address value
) internal returns (bool) {
return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
function remove(AddressToAddressMap storage map, address key)
internal
returns (bool)
{
return _remove(map._inner, bytes32(uint256(uint160(key))));
}
function remove(UintToAddressMap storage map, uint256 key)
internal
returns (bool)
{
return _remove(map._inner, bytes32(key));
}
function _at(Map storage map, uint256 index)
private
view
returns (bytes32, bytes32)
{
require(
map._entries.length > index,
'EnumerableMap: index out of bounds'
);
MapEntry storage entry = map._entries[index];
return (entry._key, entry._value);
}
function _contains(Map storage map, bytes32 key)
private
view
returns (bool)
{
return map._indexes[key] != 0;
}
function _length(Map storage map) private view returns (uint256) {
return map._entries.length;
}
function _get(Map storage map, bytes32 key) private view returns (bytes32) {
uint256 keyIndex = map._indexes[key];
require(keyIndex != 0, 'EnumerableMap: nonexistent key');
return map._entries[keyIndex - 1]._value;
}
function _set(
Map storage map,
bytes32 key,
bytes32 value
) private returns (bool) {
uint256 keyIndex = map._indexes[key];
if (keyIndex == 0) {
map._entries.push(MapEntry({ _key: key, _value: value }));
map._indexes[key] = map._entries.length;
return true;
} else {
map._entries[keyIndex - 1]._value = value;
return false;
}
}
function _remove(Map storage map, bytes32 key) private returns (bool) {
uint256 keyIndex = map._indexes[key];
if (keyIndex != 0) {
uint256 index = keyIndex - 1;
MapEntry storage last = map._entries[map._entries.length - 1];
// move last entry to now-vacant index
map._entries[index] = last;
map._indexes[last._key] = index + 1;
// clear last index
map._entries.pop();
delete map._indexes[key];
return true;
} else {
return false;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Set implementation with enumeration functions
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
*/
library EnumerableSet {
struct Set {
bytes32[] _values;
// 1-indexed to allow 0 to signify nonexistence
mapping(bytes32 => uint256) _indexes;
}
struct Bytes32Set {
Set _inner;
}
struct AddressSet {
Set _inner;
}
struct UintSet {
Set _inner;
}
function at(Bytes32Set storage set, uint256 index)
internal
view
returns (bytes32)
{
return _at(set._inner, index);
}
function at(AddressSet storage set, uint256 index)
internal
view
returns (address)
{
return address(uint160(uint256(_at(set._inner, index))));
}
function at(UintSet storage set, uint256 index)
internal
view
returns (uint256)
{
return uint256(_at(set._inner, index));
}
function contains(Bytes32Set storage set, bytes32 value)
internal
view
returns (bool)
{
return _contains(set._inner, value);
}
function contains(AddressSet storage set, address value)
internal
view
returns (bool)
{
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function contains(UintSet storage set, uint256 value)
internal
view
returns (bool)
{
return _contains(set._inner, bytes32(value));
}
function indexOf(Bytes32Set storage set, bytes32 value)
internal
view
returns (uint256)
{
return _indexOf(set._inner, value);
}
function indexOf(AddressSet storage set, address value)
internal
view
returns (uint256)
{
return _indexOf(set._inner, bytes32(uint256(uint160(value))));
}
function indexOf(UintSet storage set, uint256 value)
internal
view
returns (uint256)
{
return _indexOf(set._inner, bytes32(value));
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function add(Bytes32Set storage set, bytes32 value)
internal
returns (bool)
{
return _add(set._inner, value);
}
function add(AddressSet storage set, address value)
internal
returns (bool)
{
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(Bytes32Set storage set, bytes32 value)
internal
returns (bool)
{
return _remove(set._inner, value);
}
function remove(AddressSet storage set, address value)
internal
returns (bool)
{
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function remove(UintSet storage set, uint256 value)
internal
returns (bool)
{
return _remove(set._inner, bytes32(value));
}
function _at(Set storage set, uint256 index)
private
view
returns (bytes32)
{
require(
set._values.length > index,
'EnumerableSet: index out of bounds'
);
return set._values[index];
}
function _contains(Set storage set, bytes32 value)
private
view
returns (bool)
{
return set._indexes[value] != 0;
}
function _indexOf(Set storage set, bytes32 value)
private
view
returns (uint256)
{
unchecked {
return set._indexes[value] - 1;
}
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 index = valueIndex - 1;
bytes32 last = set._values[set._values.length - 1];
// move last value to now-vacant index
set._values[index] = last;
set._indexes[last] = index + 1;
// clear last index
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC721Enumerable {
/**
* @notice get total token supply
* @return total supply
*/
function totalSupply() external view returns (uint256);
/**
* @notice get token of given owner at given internal storage index
* @param owner token holder to query
* @param index position in owner's token list to query
* @return tokenId id of retrieved token
*/
function tokenOfOwnerByIndex(address owner, uint256 index)
external
view
returns (uint256 tokenId);
/**
* @notice get token at given internal storage index
* @param index position in global token list to query
* @return tokenId id of retrieved token
*/
function tokenByIndex(uint256 index)
external
view
returns (uint256 tokenId);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ERC721BaseStorage } from '../base/ERC721BaseStorage.sol';
import { ERC721BaseInternal } from '../base/ERC721BaseInternal.sol';
abstract contract ERC721EnumerableInternal is ERC721BaseInternal {
using ERC721BaseStorage for ERC721BaseStorage.Layout;
/**
* @notice TODO
*/
function _totalSupply() internal view returns (uint256) {
return ERC721BaseStorage.layout().totalSupply();
}
/**
* @notice TODO
*/
function _tokenOfOwnerByIndex(address owner, uint256 index)
internal
view
returns (uint256)
{
return ERC721BaseStorage.layout().tokenOfOwnerByIndex(owner, index);
}
/**
* @notice TODO
*/
function _tokenByIndex(uint256 index) internal view returns (uint256) {
return ERC721BaseStorage.layout().tokenByIndex(index);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { AddressUtils } from '../../../utils/AddressUtils.sol';
import { EnumerableMap } from '../../../utils/EnumerableMap.sol';
import { EnumerableSet } from '../../../utils/EnumerableSet.sol';
import { IERC721Internal } from '../IERC721Internal.sol';
import { IERC721Receiver } from '../IERC721Receiver.sol';
import { ERC721BaseStorage } from './ERC721BaseStorage.sol';
/**
* @notice Base ERC721 internal functions
*/
abstract contract ERC721BaseInternal is IERC721Internal {
using ERC721BaseStorage for ERC721BaseStorage.Layout;
using AddressUtils for address;
using EnumerableMap for EnumerableMap.UintToAddressMap;
using EnumerableSet for EnumerableSet.UintSet;
function _balanceOf(address account) internal view returns (uint256) {
require(
account != address(0),
'ERC721: balance query for the zero address'
);
return ERC721BaseStorage.layout().holderTokens[account].length();
}
function _ownerOf(uint256 tokenId) internal view returns (address) {
address owner = ERC721BaseStorage.layout().tokenOwners.get(tokenId);
require(owner != address(0), 'ERC721: invalid owner');
return owner;
}
function _getApproved(uint256 tokenId) internal view returns (address) {
ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
require(
l.exists(tokenId),
'ERC721: approved query for nonexistent token'
);
return l.tokenApprovals[tokenId];
}
function _isApprovedForAll(address account, address operator)
internal
view
returns (bool)
{
return ERC721BaseStorage.layout().operatorApprovals[account][operator];
}
function _isApprovedOrOwner(address spender, uint256 tokenId)
internal
view
returns (bool)
{
require(
ERC721BaseStorage.layout().exists(tokenId),
'ERC721: query for nonexistent token'
);
address owner = _ownerOf(tokenId);
return (spender == owner ||
_getApproved(tokenId) == spender ||
_isApprovedForAll(owner, spender));
}
function _mint(address to, uint256 tokenId) internal {
require(to != address(0), 'ERC721: mint to the zero address');
ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
require(!l.exists(tokenId), 'ERC721: token already minted');
_beforeTokenTransfer(address(0), to, tokenId);
l.holderTokens[to].add(tokenId);
l.tokenOwners.set(tokenId, to);
emit Transfer(address(0), to, tokenId);
}
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, '');
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory data
) internal {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, data),
'ERC721: transfer to non ERC721Receiver implementer'
);
}
function _burn(uint256 tokenId) internal {
address owner = _ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
l.holderTokens[owner].remove(tokenId);
l.tokenOwners.remove(tokenId);
emit Transfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal {
require(
_ownerOf(tokenId) == from,
'ERC721: transfer of token that is not own'
);
require(to != address(0), 'ERC721: transfer to the zero address');
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
l.holderTokens[from].remove(tokenId);
l.holderTokens[to].add(tokenId);
l.tokenOwners.set(tokenId, to);
emit Transfer(from, to, tokenId);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory data
) internal {
_transfer(from, to, tokenId);
require(
_checkOnERC721Received(from, to, tokenId, data),
'ERC721: transfer to non ERC721Receiver implementer'
);
}
function _approve(address operator, uint256 tokenId) internal {
ERC721BaseStorage.layout().tokenApprovals[tokenId] = operator;
emit Approval(_ownerOf(tokenId), operator, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) internal returns (bool) {
if (!to.isContract()) {
return true;
}
bytes memory returnData = to.functionCall(
abi.encodeWithSelector(
IERC721Receiver(to).onERC721Received.selector,
msg.sender,
from,
tokenId,
data
),
'ERC721: transfer to non ERC721Receiver implementer'
);
bytes4 returnValue = abi.decode(returnData, (bytes4));
return returnValue == type(IERC721Receiver).interfaceId;
}
/**
* @notice ERC721 hook, called before externally called approvals for processing of included message value
* @param operator beneficiary of approval
* @param tokenId id of transferred token
* @param value message value
*/
function _handleApproveMessageValue(
address operator,
uint256 tokenId,
uint256 value
) internal virtual {}
/**
* @notice ERC721 hook, called before externally called transfers for processing of included message value
* @param from sender of token
* @param to receiver of token
* @param tokenId id of transferred token
* @param value message value
*/
function _handleTransferMessageValue(
address from,
address to,
uint256 tokenId,
uint256 value
) internal virtual {}
/**
* @notice ERC721 hook, called before all transfers including mint and burn
* @dev function should be overridden and new implementation must call super
* @param from sender of token
* @param to receiver of token
* @param tokenId id of transferred token
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library AddressUtils {
function toString(address account) internal pure returns (string memory) {
bytes32 value = bytes32(uint256(uint160(account)));
bytes memory alphabet = '0123456789abcdef';
bytes memory chars = new bytes(42);
chars[0] = '0';
chars[1] = 'x';
for (uint256 i = 0; i < 20; i++) {
chars[2 + i * 2] = alphabet[uint8(value[i + 12] >> 4)];
chars[3 + i * 2] = alphabet[uint8(value[i + 12] & 0x0f)];
}
return string(chars);
}
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable account, uint256 amount) internal {
(bool success, ) = account.call{ value: amount }('');
require(success, 'AddressUtils: failed to send value');
}
function functionCall(address target, bytes memory data)
internal
returns (bytes memory)
{
return
functionCall(target, data, 'AddressUtils: failed low-level call');
}
function functionCall(
address target,
bytes memory data,
string memory error
) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, error);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return
functionCallWithValue(
target,
data,
value,
'AddressUtils: failed low-level call with value'
);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory error
) internal returns (bytes memory) {
require(
address(this).balance >= value,
'AddressUtils: insufficient balance for call'
);
return _functionCallWithValue(target, data, value, error);
}
function _functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory error
) private returns (bytes memory) {
require(
isContract(target),
'AddressUtils: function call to non-contract'
);
(bool success, bytes memory returnData) = target.call{ value: value }(
data
);
if (success) {
return returnData;
} else if (returnData.length > 0) {
assembly {
let returnData_size := mload(returnData)
revert(add(32, returnData), returnData_size)
}
} else {
revert(error);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @notice Partial ERC721 interface needed by internal functions
*/
interface IERC721Internal {
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Approval(
address indexed owner,
address indexed operator,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC165 } from '../../introspection/IERC165.sol';
import { IERC721Internal } from './IERC721Internal.sol';
/**
* @notice ERC721 interface
* @dev see https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721 is IERC721Internal, IERC165 {
/**
* @notice query the balance of given address
* @return balance quantity of tokens held
*/
function balanceOf(address account) external view returns (uint256 balance);
/**
* @notice query the owner of given token
* @param tokenId token to query
* @return owner token owner
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @notice transfer token between given addresses, checking for ERC721Receiver implementation if applicable
* @param from sender of token
* @param to receiver of token
* @param tokenId token id
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @notice transfer token between given addresses, checking for ERC721Receiver implementation if applicable
* @param from sender of token
* @param to receiver of token
* @param tokenId token id
* @param data data payload
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @notice transfer token between given addresses, without checking for ERC721Receiver implementation if applicable
* @param from sender of token
* @param to receiver of token
* @param tokenId token id
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @notice grant approval to given account to spend token
* @param operator address to be approved
* @param tokenId token to approve
*/
function approve(address operator, uint256 tokenId) external payable;
/**
* @notice get approval status for given token
* @param tokenId token to query
* @return operator address approved to spend token
*/
function getApproved(uint256 tokenId)
external
view
returns (address operator);
/**
* @notice grant approval to or revoke approval from given account to spend all tokens held by sender
* @param operator address to be approved
* @param status approval status
*/
function setApprovalForAll(address operator, bool status) external;
/**
* @notice query approval status of given operator with respect to given address
* @param account address to query for approval granted
* @param operator address to query for approval received
* @return status whether operator is approved to spend tokens held by account
*/
function isApprovedForAll(address account, address operator)
external
view
returns (bool status);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ERC165 interface registration interface
* @dev see https://eips.ethereum.org/EIPS/eip-165
*/
interface IERC165 {
/**
* @notice query whether contract has registered support for given interface
* @param interfaceId interface id
* @return bool whether interface is supported
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library ERC165Storage {
struct Layout {
mapping(bytes4 => bool) supportedInterfaces;
}
bytes32 internal constant STORAGE_SLOT =
keccak256('solidstate.contracts.storage.ERC165');
function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
function isSupportedInterface(Layout storage l, bytes4 interfaceId)
internal
view
returns (bool)
{
return l.supportedInterfaces[interfaceId];
}
function setSupportedInterface(
Layout storage l,
bytes4 interfaceId,
bool status
) internal {
require(interfaceId != 0xffffffff, 'ERC165: invalid interface id');
l.supportedInterfaces[interfaceId] = status;
}
}