hello I'm writing a contract and got this error in my function.
function mintCardNFT(uint _cardIndex) external {
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
nftHolderAttributes[newItemId] = CardAttributes({
cardIndex: _cardIndex,
name: defaultCards[_cardIndex].name,
imageURI: defaultCards[_cardIndex].imageURI,
alignments: defaultCards[_cardIndex].alignments,
power: defaultCards[_cardIndex].power,
maxPower: defaultCards[_cardIndex].maxPower,
resistance: defaultCards[_cardIndex].resistance,
income: defaultCards[_cardIndex].income
});
console.log("Minted NFT w/ tokenId %s and cardIndex %s", newItemId, _cardIndex);
nftHolders[msg.sender] = newItemId;
_tokenIds.increment();}
solidity version is 0.8.1 in hardhat.config and ^0.8.1 in contract.
everything looks normal to me. Merci!
You're trying to invoke a function _safeMint() but this function is not declared.
Most likely you forgot to derive your contract from the OpenZeppelin ERC721.
pragma solidity ^0.8;
// import the OpenZeppelin `ERC721` contract
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
// derive your contract from the imported `ERC721` contract
contract MyCollection is ERC721 {
// call the parent constructor
constructor() ERC721("MyCollection", "MyC") {}
function mintCardNFT() external {
// now the `_safeMint()` function is available
_safeMint(msg.sender, 1);
}
}
Related
How do I accept an ERC 20 token for minting NFTS on my smart contract. I’m currently paying for the minting using ETH, and I will like to accept another ERC 20 token.
You can change your mint function in order to accept the preferred token type as payment. And in order to prevent paying gas in eth, you can use biconomy forward.Check out their docs.
https://docs.biconomy.io/products/enable-paying-gas-in-erc20
You need a reference from the NFT contract to your token contract.
Let's say we have these two contracts: NFTContract, TokenContract.
contract NFTContract {
TokenContract tokenContract;
...
mint() {
tokensContract.transfer(msg.sender(), addressReceiver, tokensToSend);
...
}
}
contract TokenContract {
transfer(sender, receiver, balance) {}
}
You can check an example of how I did this in my repo I'm developing for my thesis.
https://github.com/NickVanzo/Contracts_For_Thesis
Maybe it will work for you but be careful you can take errors for solidity versions.
pragma solidity ^0.8.9;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract LSTNFT is ERC721, ERC721Burnable, Ownable {
uint256 public cost;
uint256 maxSupply = 20;
uint256 maxMintAmountPerTx = 2;
// address of the ERC-20 contract
address public erc20Contract = "ERC-20 address is here";
// instance of the ERC-20 contract
ERC20 public erc20;
constructor() ERC721("Lestonz NFT", "LSTN") {
erc20 = ERC20(erc20Contract);
}
function _baseURI() internal pure override returns (string memory) {
return "ipfs://your ipfs url";
}
modifier mintPriceCompliance(uint256 _mintAmount) {
if (msg.sender != owner()) {
require(msg.value >= cost * _mintAmount, 'Insufficient funds!');
}
_;
}
function mint(uint256 _mintAmount) public payable mintPriceCompliance(_mintAmount) {
require(erc20.balanceOf(msg.sender) >= msg.value, "Not enough ERC-20 tokens");
_safeMint(_msgSender(), _mintAmount);
}
function setCost(uint256 _cost) public onlyOwner {
cost = _cost;
}
}
I'm trying to transfer Matic to my smart contract in the Mumbai test net using ethers.
I'm using the most basic contract which comes with hardhat - Greeter. sol.
The error I keep getting is(in the polygonscan-mumbai):
The client side transfer using ethers:
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const erc20Contract = new ethers.Contract("0x0000000000000000000000000000000000001010", erc20abi, signer);
const parsedAmount = ethers.utils.parseUnits(amount.toString(), 'ether');
const transferTokens = await erc20Contract.transfer(contractAddress , parsedAmount);
Greeter.sol:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract Greeter {
string private greeting;
constructor(string memory _greeting) {
console.log("Deploying a Greeter with greeting:", _greeting);
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
greeting = _greeting;
}
}
Also when I manually try to send Matic to the smart contract using metamsk it's giving me the same error(only to contracts, not other wallets).
But if I try other tokens it works fine - am I missing something?
Your contract needs to implement either receive() or fallback() function to be able to accept native currency of the network.
Docs: https://docs.soliditylang.org/en/v0.8.13/contracts.html#special-functions
Example:
contract Greeter {
// ...
receive() external payable {
}
}
I have created a nft on Rarible ( ropsten test net) but looks like people are not able to buy it....can anyone help me with why this seems to be happenning ?
rarible NFT : nft-link
solidity contract:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "./rarible/impl/RoyaltiesV2Impl.sol";
import "./rarible/royalties/contracts/LibPart.sol";
import "./rarible/royalties/contracts/LibRoyaltiesV2.sol";
contract RoyaltyNFT is ERC721, Ownable, RoyaltiesV2Impl {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdTracker;
constructor() ERC721("RoyaltyNFT", "ROYA") {}
function mint(address _to) public onlyOwner {
super._mint(_to, _tokenIdTracker.current());
_tokenIdTracker.increment();
}
function _baseURI() internal view virtual override returns (string memory) {
return "https://gateway.pinata.cloud/ipfs/QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH";
}
function setRoyalties(uint _tokenId, address payable _royaltiesReceipientAddress, uint96 _percentageBasisPoints) public onlyOwner {
LibPart.Part[] memory _royalties = new LibPart.Part[](1);
_royalties[0].value = _percentageBasisPoints;
_royalties[0].account = _royaltiesReceipientAddress;
_saveRoyalties(_tokenId, _royalties);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) {
if(interfaceId == LibRoyaltiesV2._INTERFACE_ID_ROYALTIES) {
return true;
}
return super.supportsInterface(interfaceId);
}
}
I had followed a blog to create rarible NFT and i was able to do so but i was unable to sell it to other people as transfer could not be initiated by others.
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...
}
}
I have an ERC20 token already deployed on the Ropsten testnet with two versions.
V1 is a simple unproxied ERC20 token and looks like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor() ERC20("MyToken", "MTK") {}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
I can interact with this contract using web3:
const Web3 = require('web3');
const MyToken = require('./build/contracts/MyToken.json');
const HDWalletProvider = require('#truffle/hdwallet-provider');
const provider = new HDWalletProvider(process.env.ACCOUNT_SECRET, process.env.INFURA_URL);
const web3 = new Web3(provider);
const contract = new web3.eth.Contract(MyToken.abi, process.env.CONTRACT_ADDRESS);
For example, here is a call that retrieves the owner of the contract:
await contract.methods.owner().call();
On the other hand, V2 is a UUPS upgradeable contract which looks like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "#openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "#openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyToken is Initializable, ERC20Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
/// #custom:oz-upgrades-unsafe-allow constructor
constructor() initializer {}
function initialize() initializer public {
__ERC20_init("MyToken", "MTK");
__Ownable_init();
__UUPSUpgradeable_init();
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override
{}
}
To interact with V2 using the same web3 nodejs code, I tried updating the build/abi as well as process.env.CONTRACT_ADDRESS from V1's address to V2's. However, whenever I retrieve the owner using the same code, it always returns the zero address.
I think the call should be proxied or something, but I don't know how and I can't find resources (docs/tutorials) on this.
Contracts V1 and V2 are generated from wizard.openzeppelin.com. Nothing was modified.
V2 passes the get owner, symbol, and name truffle tests.
I'm not really sure what's the best practice regarding the initializer {} modifier in constructor(). My guess is that OpenZeppelin recommends to use it with constructor in case you're also setting other variables in constructor and not using other init function.
However, the effect of your implementation is that it simply sets the initialized variable to true without executing the top-level initialize() function - effectively not setting the owner variable (and others, such as name and symbol).
I was able to perform a quick fix by removing the initializer modifier (since it's already with the initialize() function, and calling the initialize() from the constructor. Please check if there aren't any side effects to it.
// removed the modifier
// added the call to `initialize()`
constructor() {
initialize();
}
// stays the same
function initialize() initializer public {