Definition of base has to precede definition of derived contract (ERC721 implementation) - solidity

The top SO or ETH Stack Exchange answers don't seem to apply to my case (I could be wrong of course)
I'm getting the error describer in the title in this file:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ERC721Metadata.sol";
import "./ERC721.sol";
contract ERC721Connector is ERC721Metadata, ERC721 {
// ^^^^^^^ (Definition of base has to precede definition of derived contract)
constructor(string memory name, string memory symbol) ERC721Metadata(name, symbol) {}
}
Here's what ERC721Metadadata looks like:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ERC721Metadata {
string private _name;
string private _symbol;
constructor(string memory named, string memory symbolified) {
_name = named;
_symbol = symbolified;
}
function name() external view returns (string memory) {
return _name;
}
function symbol() external view returns (string memory) {
return _symbol;
}
}
And here is what ERC721 looks like:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ERC721Metadata.sol";
import "./ERC721Connector.sol";
contract ERC721 {
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
mapping(uint256 => address) private _tokenOwner;
mapping(address => uint256) private _OwnedTokensCount;
function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId];
return owner != address(0);
}
function _mint(address to, uint256 tokenId) internal {
require(to != address(0), "ERC721: minting to the zero address");
require(
!_exists(tokenId),
"ERC721: minting a token that already exists (been minted)"
);
_tokenOwner[tokenId] = to;
_OwnedTokensCount[to] += 1;
emit Transfer(address(0), to, tokenId);
}
}

Do you need to import ERC721Connector contract in your ERC721 contract? If not, you can remove
import "./ERC721Connector.sol"; // line 4, ERC721.sol
from your file and it should work fine. Your imports are causing the issue,
ERC721Connector tries to import ERC721, but ERC721 also needs ERC721Connector so the compiler says
Definition of base has to precede definition of derived contract
Because the base contract doesn't precede the defined contract.

Related

Receiving a DeclarationError: Identifier not found or not unique while using counters using Remix

I am trying to run the code which is generating an error stating that DeclarationError: Identifier not found or not unique.
The smart contract NFTCollection is a solidity code which enables me to mint a specific number of ERC721 Tokens and to count the tokens of owner. I am receiving a error while displaying the error message "DeclarationError: Identifier not found or not unique" at line 20 which reads "using Counters for Counters.counter;"
Please find the code below.
Any help would be highly appreciated.
The contract and the error message.
pragma solidity ^0.8.4;
// Importing required libraries
/*
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/utils/Counters.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
*/
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
// This is a simple NFT contract
//Start of a contract
//INitialising contract as a ERC721, ERC721Enumerable, Ownable contract.
contract NFTCollection is ERC721, ERC721Enumerable, Ownable {
using Counters for Counters.counter;
// Specifing the maximum supply
uint256 maxSupply = 1000000;
// Initiatina a counter to store to be able to use Counters on uint265 without impacting the rest of the uint256 in the contract.
//Counter helps to find every function from a single library to a type to reduce gass fee.
Counters.Counter private _tokenIDCounter;
// Initialising a constructor.
constructor(string memory _name, string memory _symbol)
ERC721(_name, _symbol){}
// ERC721 interface is initialised and the _name, _symbol details aere passed in to hold.
//End of constructor.
//Start of function mint.
//This function is used to mint ERC721 tokens.
//Mint function adds the capability to mint ERC721 tokens and assign it to a address which accepts user address, number of tokens as arguments.
function mint(address _user, uint256 _amount) public {
//Start of for loop
for(uint256 i;i<_amount;i++)
{
//Incrementing the _tokenIdCounter by 1 using increment function.
_tokenIdCounter.increment();
// Creating a variable which stores the current value of _tokenIdCounter.
uint256 tokenId = _tokenIdcounter.current();
//Using safemint to mint ERC721 Tokens.
_safeMint(_user,tokenId);
}
}//End of function mint.
//Start of function tokensOfOwner
// This function is used to keep track of the owners Tokens.
// The function seeks a owner address to check the number of tokens he owns.
function tokensOfOwner(address _owner) public view returns (uint256[] memory)
{ // Creating a ownerTokenCount which stores the balance of the owner.
uint256 ownerTokenCount = balanceOf(_owner);
// Creating a memory variable and storing a array of ownerTokenCount.
uint256[] memory ownedTokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; ++i) {
ownedTokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}//End of for loop
return ownedTokenIds; //Return statement.
}
// Function overrides required by solidity
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);
}
}
Error Message
--> contracts/nft.sol:20:24:
|
20 | using Counters for Counters.counter;~~~

I generated a flattened of my contract using Remix but it gives error: Definition of base has to precede definition of derived contract

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

Is there a way to check how many times an ERC721 token has been minted?

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);
}
}

Solidity calling contract with elevated permissions

I have two contracts, one for handling staking and one for minting a NFT. The flow I want is for the user to stake in frontend react app which will invoke the staking contract. The user will then be eligible to mint a NFT when staked.
Now the issue I am facing is that because the minting role is called from stakingExample contract, which requires the user to invoke this, but as it has a critical function (mint) of the other contract, it should be protected with permissions such that only StakingExample can call NFTExample contract.
Is there a way to allow the user to run NFTExample with elevated permissions temporary in smart contract?
Example of staking contract:
// SPDX-License-Identifier: unlicensed
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/access/AccessControl.sol";
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
import "#openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract StakingExample is AccessControl {
bytes32 public constant CONTRACT_ROLE = keccak256("CONTRACT_ROLE");
NFTExample public _NFTExample;
...
function someStakingFunction() {
// code that stakes and
// set some variable that tracks if user have minted
}
function claimNFT(uint256 _pid, string memory _tokenURI) public onlyRole(CONTRACT_ROLE) {
// checks if user have unclaimed NFT
if (haveUnclaimed) {
_NFTExample.mintItem(msg.sender, _tokenURI)
}
}
}
Example of NFT contract:
// SPDX-License-Identifier: unlicensed
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/access/AccessControl.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract CMRGachaSeedNFT is ERC721URIStorage, AccessControl, ERC721Enumerable {
bytes32 public constant CONTRACT_ROLE = keccak256("CONTRACT_ROLE");
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
...
// Only Contract Role can call mint item, which mint item and transfers it to user's address
function mintItem(address _address, string memory _tokenURI)
public
onlyRole(CONTRACT_ROLE)
returns (uint256)
{
// Do some checks
// Mint
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(_address, newItemId);
_setTokenURI(newItemId, _tokenURI);
return newItemId;
}
}
You need to add one function in staking contract which shows amount of the staking:
function showStakeAmount() external view returns(uint256){
//I don't know your codes about this but you need a mapping to store
//the stake amount of each user and here you return it but something like this:
return StakingAmountOfUsers(msg.sender);
}
Then you need an interface of the staking contract and its address, also make an modifier in NFT contract (Following changes must be added):
interface StakingInterface{
function showStakeAmount() external view returns(uint256);
}
contract CMRGachaSeedNFT is ERC721URIStorage, AccessControl, ERC721Enumerable {
uint256 AmountThatShouldBeStaked;
StakingInterface StakingContract;
constructor(address STAKING_CONTRACT_ADDRESS){
StakingContract = StakingInterface(STAKING_CONTRACT_ADDRESS);
}
modifier isStaked(){
require(StakingContract.showStakeAmount() > AmountThatShouldBeStaked, "You did not stake enough amount of X token");
_;
}
function mintItem(address _address, string memory _tokenURI)
public
onlyRole(CONTRACT_ROLE)
returns (uint256)
isStaked()
{
//Continue coding...
}
}

What is the type of `this` object in solidity

In the following claimPayment function that is used to claim a payment made earlier to this contract, the line bytes32 message = prefixed(keccak256(abi.encodePacked(msg.sender, amount, nonce, this))); has this as part of the signed message. This makes me wonder what is this and what the type of this is. If I'm returning this in a function, what type is used for it? Thanks.
function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) public {
require(!usedNonces[nonce]);
usedNonces[nonce] = true;
// this recreates the message that was signed on the client
bytes32 message = prefixed(keccak256(abi.encodePacked(msg.sender, amount, nonce, this)));
require(recoverSigner(message, signature) == owner);
payable(msg.sender).transfer(amount);
}
this is a pointer to the current class instance, as in many other programming languages. You can for example point to public methods:
pragma solidity ^0.8.0;
contract MyContract {
function foo() external {
this.bar();
}
function bar() public {
}
}
When this is typecasted, it takes a form of the address, where the current instance is deployed.
pragma solidity ^0.8.0;
contract MyContract {
function foo() external view returns (bytes memory) {
return abi.encodePacked(this);
}
function bar() external view returns (address) {
return address(this);
}
}