I am using the Opensea Creatures repository (https://github.com/ProjectOpenSea/opensea-creatures.git) to make a Factory and create my ERC721 tokens. I have added the function _setTokenURI (newTokenId, metadataURI); in ERC721Tradable.sol to add the URI when doing mint but it gives me the following error:
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.
the files involved are these:
CreatureFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "openzeppelin-solidity/contracts/access/Ownable.sol";
import "openzeppelin-solidity/contracts/utils/Strings.sol";
import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import "./IFactoryERC721.sol";
import "./Creature.sol";
contract CreatureFactory is FactoryERC721, Ownable {
using Strings for string;
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
address public proxyRegistryAddress;
address public nftAddress;
address public lootBoxNftAddress;
string public baseURI = "https://terrorverso.herokuapp.com/api/token/";
/*
* Enforce the existence of only 100 OpenSea creatures.
*/
uint256 CREATURE_SUPPLY = 100;
/*
* Three different options for minting Creatures (basic, premium, and gold).
*/
uint256 NUM_OPTIONS = 3;
uint256 SINGLE_CREATURE_OPTION = 0;
uint256 MULTIPLE_CREATURE_OPTION = 1;
uint256 LOOTBOX_OPTION = 2;
uint256 NUM_CREATURES_IN_MULTIPLE_CREATURE_OPTION = 4;
constructor(address _proxyRegistryAddress, address _nftAddress) {
proxyRegistryAddress = _proxyRegistryAddress;
nftAddress = _nftAddress;
fireTransferEvents(address(0), owner());
}
function name() override external pure returns (string memory) {
return "Factory";
}
function symbol() override external pure returns (string memory) {
return "FACT";
}
function supportsFactoryInterface() override public pure returns (bool) {
return true;
}
function numOptions() override public view returns (uint256) {
return NUM_OPTIONS;
}
function transferOwnership(address newOwner) override public onlyOwner {
address _prevOwner = owner();
super.transferOwnership(newOwner);
fireTransferEvents(_prevOwner, newOwner);
}
function fireTransferEvents(address _from, address _to) private {
for (uint256 i = 0; i < NUM_OPTIONS; i++) {
emit Transfer(_from, _to, i);
}
}
function mint(uint256 _optionId, address _toAddress, string memory metadataURI) override public {
// Must be sent from the owner proxy or owner.
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
assert( address(proxyRegistry.proxies(owner())) == _msgSender() || owner() == _msgSender() || _msgSender() == lootBoxNftAddress );
require(canMint(_optionId));
Creature openSeaCreature = Creature(nftAddress);
if (_optionId == SINGLE_CREATURE_OPTION) {
openSeaCreature.mintTo(_toAddress,metadataURI);
} else if (_optionId == MULTIPLE_CREATURE_OPTION) {
for (
uint256 i = 0;
i < NUM_CREATURES_IN_MULTIPLE_CREATURE_OPTION;
i++
) {
openSeaCreature.mintTo(_toAddress,metadataURI);
}
}
}
function canMint(uint256 _optionId) override public view returns (bool) {
if (_optionId >= NUM_OPTIONS) {
return false;
}
Creature openSeaCreature = Creature(nftAddress);
uint256 creatureSupply = openSeaCreature.totalSupply();
uint256 numItemsAllocated = 0;
if (_optionId == SINGLE_CREATURE_OPTION) {
numItemsAllocated = 1;
} else if (_optionId == MULTIPLE_CREATURE_OPTION) {
numItemsAllocated = NUM_CREATURES_IN_MULTIPLE_CREATURE_OPTION;
}
return creatureSupply < (CREATURE_SUPPLY - numItemsAllocated);
}
function tokenURI(uint256 _optionId) override external view returns (string memory) {
return string(abi.encodePacked(baseURI, Strings.toString(_optionId)));
}
/**
* Hack to get things to work automatically on OpenSea.
* Use transferFrom so the frontend doesn't have to worry about different method names.
*/
function transferFrom(
address _from,
address _to,
uint256 _tokenId,
string memory metadataURI
) public {
mint(_tokenId, _to, metadataURI);
}
/**
* Hack to get things to work automatically on OpenSea.
* Use isApprovedForAll so the frontend doesn't have to worry about different method names.
*/
function isApprovedForAll(address _owner, address _operator)
public
view
returns (bool)
{
if (owner() == _owner && _owner == _operator) {
return true;
}
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
if (
owner() == _owner &&
address(proxyRegistry.proxies(_owner)) == _operator
) {
return true;
}
return false;
}
/**
* Hack to get things to work automatically on OpenSea.
* Use isApprovedForAll so the frontend doesn't have to worry about different method names.
*/
function ownerOf(uint256 _tokenId) public view returns (address _owner) {
return owner();
}
}
ERC721Tradable.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import "openzeppelin-solidity/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "openzeppelin-solidity/contracts/access/Ownable.sol";
import "openzeppelin-solidity/contracts/utils/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/utils/Strings.sol";
import "openzeppelin-solidity/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./common/meta-transactions/ContentMixin.sol";
import "./common/meta-transactions/NativeMetaTransaction.sol";
contract OwnableDelegateProxy {}
contract ProxyRegistry {
mapping(address => OwnableDelegateProxy) public proxies;
}
/**
* #title ERC721Tradable
* ERC721Tradable - ERC721 contract that whitelists a trading address, and has minting functionality.
*/
abstract contract ERC721Tradable is ContextMixin, ERC721Enumerable, NativeMetaTransaction, Ownable, ERC721URIStorage {
using SafeMath for uint256;
address proxyRegistryAddress;
uint256 private _currentTokenId = 0;
constructor(
string memory _name,
string memory _symbol,
address _proxyRegistryAddress
) ERC721(_name, _symbol) {
proxyRegistryAddress = _proxyRegistryAddress;
_initializeEIP712(_name);
}
/**
* #dev Mints a token to an address with a tokenURI.
* #param _to address of the future owner of the token
*/
function mintTo(address _to, string memory metadataURI) public onlyOwner {
uint256 newTokenId = _getNextTokenId();
_mint(_to, newTokenId);
_setTokenURI(newTokenId, metadataURI);
_incrementTokenId();
}
/**
* #dev calculates the next token ID based on value of _currentTokenId
* #return uint256 for the next token ID
*/
function _getNextTokenId() private view returns (uint256) {
return _currentTokenId.add(1);
}
/**
* #dev increments the value of _currentTokenId
*/
function _incrementTokenId() private {
_currentTokenId++;
}
function baseTokenURI() virtual public pure returns (string memory);
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
/**
* Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-less listings.
*/
function isApprovedForAll(address owner, address operator)
override
public
view
returns (bool)
{
// Whitelist OpenSea proxy contract for easy trading.
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
if (address(proxyRegistry.proxies(owner)) == operator) {
return true;
}
return super.isApprovedForAll(owner, operator);
}
/**
* This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea.
*/
function _msgSender()
internal
override
view
returns (address sender)
{
return ContextMixin.msgSender();
}
}
and Creature.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ERC721Tradable.sol";
/**
* #title Creature
* Creature - a contract for my non-fungible creatures.
*/
contract Creature is ERC721Tradable{
constructor(address _proxyRegistryAddress)
ERC721Tradable("ExampleNFT", "EXA", _proxyRegistryAddress)
{}
function baseTokenURI() override public pure returns (string memory) {
return "https://example.com/api/token/";
}
function contractURI() public pure returns (string memory) {
return "https://creatures-api.opensea.io/contract/opensea-creatures";
}
}
Related
I thibk the error is occurring because the contract "ERC721Burnable" is trying to inherit from two other contracts "Context" and "ERC721", but "Context" is not defined in the code you provided. So, the definition of a base contract must precede the definition of a derived contract.
How can I make sure that the definition of the "Context" contract is included before the definition of the "ERC721Burnable" contract. Additionally, How can I make sure that "Context" is defined in the same file or imported from a different file.
Bellow is the code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/common/ERC2981.sol";
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/security/Pausable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/utils/math/SafeMath.sol";
contract AliveNatureNFT is ERC721, ERC721Enumerable, ERC721URIStorage, ERC2981, Pausable, ERC721Burnable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
// percentage split for commission and liquidity pool
uint96 public commissionPercentage;
uint96 public liquidityPercentage;
// address of the commission recipient
address public commissionRecipient;
// address of the liquidity pool
address public liquidityPoolRecipient;
// Owner address
address public ownerNFT;
//Base URI
string private url;
struct ProjectData {
string name;
uint256 projectTokenId;
string methodology;
string region;
string emissionType;
string uri;
address creator;
}
struct RetireData {
uint256 retireTokenId;
address beneficiary;
string retirementMessage;
uint256 timeStamp;
uint256 amount;
}
mapping (uint256 => ProjectData) private _projectData;
mapping (uint256 => RetireData) private _retireData;
modifier onlyOwner(address _sender) {
require(_sender == ownerNFT, "Only the owner can call this function");
_;
}
modifier onlyAdmin (address _sender) {
require(_sender == commissionRecipient, "Only the heir can call this function");
_;
}
constructor(
uint96 _liquidityPercentage, address _liquidityPoolRecipient,
string memory _MyToken, string memory _Symbol, string memory _url, address _ownerNFT
) ERC721(_MyToken, _Symbol) {
commissionPercentage = 100;
liquidityPercentage = _liquidityPercentage;
commissionRecipient = 0xE3506A38C80D8bA1ef219ADF55E31E18FB88EbF4;
liquidityPoolRecipient = _liquidityPoolRecipient;
ownerNFT = _ownerNFT;
_setDefaultRoyalty(commissionRecipient, commissionPercentage);
url = _url;
}
function _baseURI() internal view override returns (string memory) {
return url;
}
function pause(address _sender) external onlyAdmin(_sender) {
_pause();
}
function unpause(address _sender) external onlyAdmin(_sender) {
_unpause();
}
function safeMint(address _to, string memory _uri, string memory _name,
string memory _methodology, string memory _region, string memory _emissionType, address _sender) public whenNotPaused onlyOwner(_sender) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(_to, tokenId);
_setTokenURI(tokenId, _uri);
// Create a new ProjectData struct and store it in the contract's storage
_projectData[tokenId] = ProjectData({
projectTokenId : tokenId,
uri : _uri,
name : _name,
methodology : _methodology,
region : _region,
emissionType : _emissionType,
creator : _sender
});
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
internal
whenNotPaused
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId, batchSize);
if (from != address(0)) {
address owner = ownerOf(tokenId);
require(owner == msg.sender, "Only the owner of NFT can transfer or burn it");
}
}
function _burn(uint256 tokenId) internal whenNotPaused override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function burnToken(uint256 tokenId, string memory _retirementMessage, uint256 _amount, address _sender) public whenNotPaused onlyOwner(_sender) {
address owner = ownerOf(tokenId);
require(owner == msg.sender, "Only the owner of NFT can burn it");
_burn(tokenId);
// Create a new ProjectData struct and store it in the contract's storage
_retireData[tokenId] = RetireData({
retireTokenId : tokenId,
beneficiary : msg.sender,
retirementMessage : _retirementMessage,
timeStamp : block.timestamp,
amount : _amount
});
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
// The following functions are overrides required by Solidity.
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC2981, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
I'm trying to group everything in a flattened contract to have the complete ABI
When running npx truffle compile, i get the above error message.
I am trying to transition an NFT smart contract into upgradeable form and have imported the relevant source codes. It deploys to testnet fine, but when replacing the constructor with "function Initialize() initializer pubic {" i get the above error message.
Can someone help?
I also get an "Identifier not found or not unique" by my "mapping(address=>bool) private _operatorEnabled;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/security/Pausable.sol";
import "#openzeppelin/contracts/access/AccessControl.sol";
contract ERC721CarbonAsset is ERC721URIStorage, Pausable, AccessControl {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
// Base URI
string private _baseUri;
address _forwarder;
mapping(uint256 => string) private _digests;
mapping(uint256 => string) private _infoRoots;
// Addresses under operator control
mapping(address => bool) private _operatorEnabled;
function initialize() initializer public {
// constructor() public ERC721("", "") Pausable() {
_baseUri = "";
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(PAUSER_ROLE, msg.sender);
_setupRole(MINTER_ROLE, msg.sender);
_setupRole(BURNER_ROLE, msg.sender);
_setupRole(OPERATOR_ROLE, msg.sender);
}
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
/**
* #dev See {ERC20-_beforeTokenTransfer}.
* Taken from ERC20Pausable
*
* Requirements:
*
* - the contract must not be paused.
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
require(!paused(), "ERC721Pausable: token transfer while paused");
}
function mint(address to, uint256 tokenId, string memory tokenUri, string memory digest) public onlyRole(MINTER_ROLE) {
_mint(to, tokenId);
_setTokenURI(tokenId, tokenUri);
_digests[tokenId] = digest;
}
function burn(uint256 tokenId) public onlyRole(BURNER_ROLE) {
_burn(tokenId);
}
function setBaseURI(string memory uri) external onlyRole(OPERATOR_ROLE) {
_baseUri = uri;
}
/**
* #dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/
function _baseURI() internal view virtual override returns (string memory) {
return _baseUri;
}
function infoRoot(uint256 tokenId) external view virtual returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory _infoRoot = _infoRoots[tokenId];
// If there is no infoRoot set, return an empty string.
if (bytes(_infoRoot).length == 0) {
return "";
}
return _infoRoot;
}
function setInfoRoot(uint256 tokenId, string memory _infoRoot) external onlyRole(OPERATOR_ROLE) whenNotPaused() {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_infoRoots[tokenId] = _infoRoot;
}
function digest(uint256 tokenId) external view virtual returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory digest = _digests[tokenId];
// If there is no digest set, return an empty string.
if (bytes(digest).length == 0) {
return "";
}
return digest;
}
function setDigest(uint256 tokenId, string memory digest) external onlyRole(OPERATOR_ROLE) whenNotPaused() {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_digests[tokenId] = digest;
}
// Operator initiatiated token transfer
function operatorTransfer(address recipient, uint256 tokenId) external onlyRole(OPERATOR_ROLE) whenNotPaused() returns (bool) {
address owner = ownerOf(tokenId);
require(isOperatorControlled(owner), "ERC721: sender not under operator control");
// Reset appoval
_approve(msg.sender, tokenId);
transferFrom(owner, recipient, tokenId);
return true;
}
// Address owner can enable their address for operator control
// Default state is operator disabled
function enableOperatorControl() external whenNotPaused() returns (bool) {
require(msgSender() != address(0), "ERC20: owner is a zero address");
require(!isOperatorControlled(msgSender()), "ERC20: owner already under operator control");
_operatorEnabled[msgSender()] = true;
return true;
}
// Operator role can remove operator control from an address
function disableOperatorControl(address owner) external onlyRole(OPERATOR_ROLE) whenNotPaused() returns (bool) {
require(owner != address(0), "ERC721: owner is a zero address");
require(isOperatorControlled(owner), "ERC721: owner not under operator control");
_operatorEnabled[owner] = false;
return true;
}
function isOperatorControlled(address owner) public view returns (bool) {
require(owner != address(0), "ERC721: owner is a zero address");
return _operatorEnabled[owner];
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
function msgSender() internal view returns(address sender) {
if(msg.sender == _forwarder) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
} else {
sender = msg.sender;
}
return sender;
}
function setForwarder(address forwarder) external onlyRole(OPERATOR_ROLE) returns (bool) {
_forwarder = forwarder;
return true;
}
function getForwarder() external view returns (address) {
return _forwarder;
}
}
I tried to change the initializer function around a bit, inline with onlyInitializing functionality https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/releases/tag/v4.4.1
But that also returned a similar error regarding identifier not found or not unique
There were a few problems with the code:
there needs to be a constructor function that sets the token name and symbol (inherited from ERC721 contract)
the initialize function should not also have the word "initializer" in the function declaration
The code will work if with just the above, but there are warnings regarding the overlapping of your function named "digest" with the name "digest" of various input parameters and variables defined within a few functions. Easiest way to solve this is to change the function name
updated code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/security/Pausable.sol";
import "#openzeppelin/contracts/access/AccessControl.sol";
contract ERC721CarbonAsset is ERC721URIStorage, Pausable, AccessControl {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
// Base URI
string private _baseUri;
address _forwarder;
mapping(uint256 => string) private _digests;
mapping(uint256 => string) private _infoRoots;
// Addresses under operator control
mapping(address => bool) private _operatorEnabled;
constructor() ERC721("BasicNFT", "BNFT") {}
function initialize() public {
// constructor() public ERC721("", "") Pausable() {
_baseUri = "";
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(PAUSER_ROLE, msg.sender);
_setupRole(MINTER_ROLE, msg.sender);
_setupRole(BURNER_ROLE, msg.sender);
_setupRole(OPERATOR_ROLE, msg.sender);
}
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
/**
* #dev See {ERC20-_beforeTokenTransfer}.
* Taken from ERC20Pausable
*
* Requirements:
*
* - the contract must not be paused.
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
require(!paused(), "ERC721Pausable: token transfer while paused");
}
function mint(address to, uint256 tokenId, string memory tokenUri, string memory digest) public onlyRole(MINTER_ROLE) {
_mint(to, tokenId);
_setTokenURI(tokenId, tokenUri);
_digests[tokenId] = digest;
}
function burn(uint256 tokenId) public onlyRole(BURNER_ROLE) {
_burn(tokenId);
}
function setBaseURI(string memory uri) external onlyRole(OPERATOR_ROLE) {
_baseUri = uri;
}
/**
* #dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/
function _baseURI() internal view virtual override returns (string memory) {
return _baseUri;
}
function infoRoot(uint256 tokenId) external view virtual returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory _infoRoot = _infoRoots[tokenId];
// If there is no infoRoot set, return an empty string.
if (bytes(_infoRoot).length == 0) {
return "";
}
return _infoRoot;
}
function setInfoRoot(uint256 tokenId, string memory _infoRoot) external onlyRole(OPERATOR_ROLE) whenNotPaused() {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_infoRoots[tokenId] = _infoRoot;
}
function digestDifferentName(uint256 tokenId) external view virtual returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory digest = _digests[tokenId];
// If there is no digest set, return an empty string.
if (bytes(digest).length == 0) {
return "";
}
return digest;
}
function setDigest(uint256 tokenId, string memory digest) external onlyRole(OPERATOR_ROLE) whenNotPaused() {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_digests[tokenId] = digest;
}
// Operator initiatiated token transfer
function operatorTransfer(address recipient, uint256 tokenId) external onlyRole(OPERATOR_ROLE) whenNotPaused() returns (bool) {
address owner = ownerOf(tokenId);
require(isOperatorControlled(owner), "ERC721: sender not under operator control");
// Reset appoval
_approve(msg.sender, tokenId);
transferFrom(owner, recipient, tokenId);
return true;
}
// Address owner can enable their address for operator control
// Default state is operator disabled
function enableOperatorControl() external whenNotPaused() returns (bool) {
require(msgSender() != address(0), "ERC20: owner is a zero address");
require(!isOperatorControlled(msgSender()), "ERC20: owner already under operator control");
_operatorEnabled[msgSender()] = true;
return true;
}
// Operator role can remove operator control from an address
function disableOperatorControl(address owner) external onlyRole(OPERATOR_ROLE) whenNotPaused() returns (bool) {
require(owner != address(0), "ERC721: owner is a zero address");
require(isOperatorControlled(owner), "ERC721: owner not under operator control");
_operatorEnabled[owner] = false;
return true;
}
function isOperatorControlled(address owner) public view returns (bool) {
require(owner != address(0), "ERC721: owner is a zero address");
return _operatorEnabled[owner];
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
function msgSender() internal view returns(address sender) {
if(msg.sender == _forwarder) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
} else {
sender = msg.sender;
}
return sender;
}
function setForwarder(address forwarder) external onlyRole(OPERATOR_ROLE) returns (bool) {
_forwarder = forwarder;
return true;
}
function getForwarder() external view returns (address) {
return _forwarder;
}
}
As a general rule of thumb, upgradeable contracts cannot contain Constructors.
See https://docs.openzeppelin.com/learn/upgrading-smart-contracts
I have added "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
and inherited from this in the contract declaration, which now doesn't return the initial error message.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/security/Pausable.sol";
import "#openzeppelin/contracts/access/AccessControl.sol";
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
abstract contract ERC721CarbonAsset is ERC721URIStorage, Pausable, AccessControl, Initializable {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
// Base URI
string private _baseUri;
address _forwarder;
mapping(uint256 => string) private _digests;
mapping(uint256 => string) private _infoRoots;
// Addresses under operator control
mapping(address => bool) private _operatorEnabled;
function initialize() initializer public {
// constructor() public ERC721("", "") Pausable() {
_baseUri = "";
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(PAUSER_ROLE, msg.sender);
_setupRole(MINTER_ROLE, msg.sender);
_setupRole(BURNER_ROLE, msg.sender);
_setupRole(OPERATOR_ROLE, msg.sender);
}
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
/**
* #dev See {ERC20-_beforeTokenTransfer}.
* Taken from ERC20Pausable
*
* Requirements:
*
* - the contract must not be paused.
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
require(!paused(), "ERC721Pausable: token transfer while paused");
}
function mint(address to, uint256 tokenId, string memory tokenUri, string memory digest) public onlyRole(MINTER_ROLE) {
_mint(to, tokenId);
_setTokenURI(tokenId, tokenUri);
_digests[tokenId] = digest;
}
function burn(uint256 tokenId) public onlyRole(BURNER_ROLE) {
_burn(tokenId);
}
function setBaseURI(string memory uri) external onlyRole(OPERATOR_ROLE) {
_baseUri = uri;
}
/**
* #dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/
function _baseURI() internal view virtual override returns (string memory) {
return _baseUri;
}
function infoRoot(uint256 tokenId) external view virtual returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory _infoRoot = _infoRoots[tokenId];
// If there is no infoRoot set, return an empty string.
if (bytes(_infoRoot).length == 0) {
return "";
}
return _infoRoot;
}
function setInfoRoot(uint256 tokenId, string memory _infoRoot) external onlyRole(OPERATOR_ROLE) whenNotPaused() {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_infoRoots[tokenId] = _infoRoot;
}
function digest(uint256 tokenId) external view virtual returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory digest = _digests[tokenId];
// If there is no digest set, return an empty string.
if (bytes(digest).length == 0) {
return "";
}
return digest;
}
function setDigest(uint256 tokenId, string memory digest) external onlyRole(OPERATOR_ROLE) whenNotPaused() {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_digests[tokenId] = digest;
}
// Operator initiatiated token transfer
function operatorTransfer(address recipient, uint256 tokenId) external onlyRole(OPERATOR_ROLE) whenNotPaused() returns (bool) {
address owner = ownerOf(tokenId);
require(isOperatorControlled(owner), "ERC721: sender not under operator control");
// Reset appoval
_approve(msg.sender, tokenId);
transferFrom(owner, recipient, tokenId);
return true;
}
// Address owner can enable their address for operator control
// Default state is operator disabled
function enableOperatorControl() external whenNotPaused() returns (bool) {
require(msgSender() != address(0), "ERC20: owner is a zero address");
require(!isOperatorControlled(msgSender()), "ERC20: owner already under operator control");
_operatorEnabled[msgSender()] = true;
return true;
}
// Operator role can remove operator control from an address
function disableOperatorControl(address owner) external onlyRole(OPERATOR_ROLE) whenNotPaused() returns (bool) {
require(owner != address(0), "ERC721: owner is a zero address");
require(isOperatorControlled(owner), "ERC721: owner not under operator control");
_operatorEnabled[owner] = false;
return true;
}
function isOperatorControlled(address owner) public view returns (bool) {
require(owner != address(0), "ERC721: owner is a zero address");
return _operatorEnabled[owner];
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
function msgSender() internal view returns(address sender) {
if(msg.sender == _forwarder) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
} else {
sender = msg.sender;
}
return sender;
}
function setForwarder(address forwarder) external onlyRole(OPERATOR_ROLE) returns (bool) {
_forwarder = forwarder;
return true;
}
function getForwarder() external view returns (address) {
return _forwarder;
}
}
I am using the OpenZeppelin's ERC721 Library, is there was a way to get the count of the number of times a token has been minted.
Is there a built-in mapping or function to check that?
You can use the Enumerable extension. The totalSupply() function returns the currently existing amount of tokens (minted minus burned), which in some cases might not the same thing as the total amount of minted tokens.
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
/*
* `totalSupply()` (defined in ERC721Enumerable) returns 1
* even though 2 tokens were minted, but 1 was also burned
*/
contract MyCollection is ERC721Enumerable, ERC721Burnable {
constructor() ERC721("CollectionName", "Symbol") {
_mint(msg.sender, 1);
_burn(1);
_mint(msg.sender, 2);
}
// multiple parents define the same function
// overriding here just to point at the expected parent class
// related to the combination of `Burnable` and `Enumerable` in the same contract - not to `Enumerable` alone
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
return ERC721Enumerable._beforeTokenTransfer(from, to, tokenId);
}
// same reason for overriding as above
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
return ERC721Enumerable.supportsInterface(interfaceId);
}
}
Or you can override the _beforeTokenTransfer() hook and create a custom counter that takes into account only minting and ignores burning.
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
/*
* `mintCounter` returns 2, ignores the burned tokens
*/
contract MyCollection is ERC721Enumerable, ERC721Burnable {
uint256 public mintCounter;
constructor() ERC721("CollectionName", "Symbol") {
_mint(msg.sender, 1);
_burn(1);
_mint(msg.sender, 2);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
if (from == address(0)) {
mintCounter++;
}
return ERC721Enumerable._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
return ERC721Enumerable.supportsInterface(interfaceId);
}
}
Greeting,
Could you tell me how to add price for every item in collection hosted by OpenSea ?
So, I have working code, It created:
1.Collection name (from construct before deploy)
2.NFT symbol (from construct before deploy)
3.URI to ipfs (from construct before deploy ex: ipfs://QmQtP8RNjvcVtKqcPwukgckWF74ojBjzahVzE3qCCnqv4f/
My smart contract example:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Context.sol";
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/utils/math/SafeMath.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract NFT is ERC721Enumerable, Ownable {
using Strings for uint256;
string public baseURI;
string public baseExtension = ".json";
uint256 public cost = 10000000000000000;
uint256 public maxSupply = 10000;
uint256 public maxMintAmount = 100;
bool public paused = false;
mapping(address => bool) public whitelisted;
constructor(
string memory _name,
string memory _symbol,
string memory _initBaseURI
) ERC721(_name, _symbol) {
setBaseURI(_initBaseURI);
mint(msg.sender, 5); // 5- for test
}
// internal
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
// public
function mint(address _to, uint256 _mintAmount) public payable {
uint256 supply = totalSupply();
require(!paused);
require(_mintAmount > 0);
require(_mintAmount <= maxMintAmount);
require(supply + _mintAmount <= maxSupply);
if (msg.sender != owner()) {
if(whitelisted[msg.sender] != true) {
require(msg.value >= cost * _mintAmount);
}
}
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(_to, supply + i);
}
}
function walletOfOwner(address _owner)
public
view
returns (uint256[] memory)
{
uint256 ownerTokenCount = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
return tokenIds;
}
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
string memory currentBaseURI = _baseURI();
return bytes(currentBaseURI).length > 0
? string(abi.encodePacked(currentBaseURI, tokenId.toString(), baseExtension))
: "";
}
//only owner
function setCost(uint256 _newCost) public onlyOwner {
cost = _newCost;
}
function getCost() public view returns (uint256) {
return cost;
}
function setmaxMintAmount(uint256 _newmaxMintAmount) public onlyOwner {
maxMintAmount = _newmaxMintAmount;
}
function setBaseURI(string memory _newBaseURI) public onlyOwner {
baseURI = _newBaseURI;
}
function setBaseExtension(string memory _newBaseExtension) public onlyOwner {
baseExtension = _newBaseExtension;
}
function pause(bool _state) public onlyOwner {
paused = _state;
}
function whitelistUser(address _user) public onlyOwner {
whitelisted[_user] = true;
}
function removeWhitelistUser(address _user) public onlyOwner {
whitelisted[_user] = false;
}
function withdraw() public onlyOwner {
uint256 balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
}
and my item json file example:
{
"description": "Test Description",
"external_url": "http://testurl.com",
"image": "ipfs://QmSrkLg3UR5AUthhCZfrK9nrX3fxJJ4aCJK7B99rUkCa72/4.png",
"name": "Test Name #4",
"symbol": "TNFT",
"collection": {
"name": "TestNFT123_321",
"family": ""
},
"date": 1643919095,
"attributes": {
"Story": "In Caffe",
"Company": "Test Company",
"Some": "thing else"
}
}
On the OpenSea I have created collection name with items, but, with active price button.
What I made wrong?
Thanks for help.
I investigated this issue, so:
Listing items on OpenSea could be with API endpoints (see OpenSea docs, and here).
OpenSea listing could be on mainnet or Rinkeby network only (as of today no Polygon, BSC ...)
There are a lot of clickers, which emulate add item, name, price on Polygon network.
Waiting for API V2 OpenSea =((
My token contract with solidity 0.8.4 is catching:
TypeError: Type is not callable
_isExcludedFromFee[(owner)] = true;
^^^^^^^^
From:
constructor () {
_rOwned[_msgSender()] = _rTotal;
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F);
// Create a uniswap pair for this new token
uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
// set the rest of the contract variables
uniswapV2Router = _uniswapV2Router;
_isExcludedFromFee[owner()] = true;
_isExcludedFromFee[address(this)] = true;
emit Transfer(address(0), _msgSender(), _tTotal);
initialize();
pause();
}
I believe it is "owner" that is causing the error, and will attach the Ownable and token contract below. There is an owner function that is typically included SafeMoon's Ownable that returns _owner but that just breaks everything more since I have newly declared address public owner.
Was able to correct by making these changes:
contract Ownable is Context {
// OWNER DATA
address public _owner;
address public _proposedOwner;
address private _oldOwner;
uint256 private _lockTime;
// OWNABLE EVENTS
event OwnershipTransferProposed(
address indexed currentOwner,
address indexed proposedOwner
);
event OwnershipTransferDisregarded(
address indexed oldProposedOwner
);
event OwnershipTransferred(
address indexed oldOwner,
address indexed newOwner
);
/**
* #dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* #dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* #dev Returns the address of the current owner.
*/
/**
* #dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* #dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* #dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
function getUnlockTime() public view returns (uint256) {
return _lockTime;
}
//Locks the contract for owner for the amount of time provided
function lock(uint256 time) public virtual onlyOwner {
_oldOwner = _owner;
_owner = address(0);
_lockTime = block.timestamp + time;
emit OwnershipTransferred(_owner, address(0));
}
//Unlocks the contract for owner when _lockTime is exceeds
function unlock() public virtual {
require(_oldOwner == msg.sender, "You don't have permission to unlock");
require(block.timestamp > _lockTime , "Contract is locked until 7 days");
emit OwnershipTransferred(_owner, _oldOwner);
_owner = _oldOwner;
}
}