ERC2981 NFT Royalties Implementation in a ERC721 Marketplace - solidity

I've read already many posts regarding this topic, but I just can't wrap my head around this Royalty implementation thing.
Pls help me out, I don't know how I should play with this thing.
what is feeNumerator? _setDefaultRoyalty(address receiver, uint96 feeNumerator)
is it NFT Price? Nft Royalty Percent?
Pls take a look at the following contract and help me with how I can implement NftRoyalty in this contract. Am I doing it right? if not then pls correct me. Thanks.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.8;
import "hardhat/console.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/token/common/ERC2981.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract PodShip is ERC721URIStorage, ERC2981, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _podcastId;
Counters.Counter private _nftId;
struct Podcast {
address nftCreator;
address nftOwner;
string nftName;
string nftDescription;
uint256 nftPrice;
uint256 nftRoyaltyPercent;
uint256 nftId;
bool listed;
}
mapping(uint256 => Podcast) podcastId;
constructor() ERC721("PodShip NFTs", "PODSHIP") {}
function mintNft(
string memory ipfsURI,
string memory _nftName,
string memory _nftDescription,
uint256 _nftPrice,
uint256 _nftRoyaltyPercent) public returns(uint256) {
require(_nftPrice > 0, "NFT Price not set correctly");
require(_nftRoyaltyPercent > 0 && _nftRoyaltyPercent <= 50, "NFT Royalty should be in-between 1 & 50");
_podcastId.increment();
_nftId.increment();
uint256 nft_Id = _nftId.current();
_safeMint(msg.sender, nft_Id);
_setTokenURI(nft_Id, ipfsURI);
podcastId[_podcastId.current()] = Podcast(
payable(msg.sender),
payable(msg.sender),
_nftName,
_nftDescription,
_nftPrice,
_nftRoyaltyPercent,
nft_Id,
false
);
console.log(nft_Id);
console.log(_podcastId.current());
return nft_Id;
}
function listNFT(uint256 _podcastID) public {
require(msg.sender == podcastId[_podcastID].nftOwner && msg.sender == podcastId[_podcastID].nftCreator, "Only Owner can list his NFT");
podcastId[_podcastID].listed = true;
approve(address(this), podcastId[_podcastID].nftId);
setApprovalForAll(address(this), true);
_setDefaultRoyalty(podcastId[_podcastID].nftCreator, uint96(podcastId[_podcastID].nftRoyaltyPercent));
}

Related

OpenZeppelin ERC721URIStorage _setTokenURI

i'm trying to create a smart contract for minting NFT's. When i try to import and use _setTokenUri from OpenZeppelin, there is an error accours in Remix ide says that "Undeclared identifier". I wonder why, so here is my code ;
pragma solidity ^0.8.9;
import '#openzeppelin/contracts/token/ERC721/ERC721.sol';
import '#openzeppelin/contracts/access/Ownable.sol';
import '#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';
contract MintNft is ERC721, Ownable {
uint256 public mintPrice = 0.005 ether;
uint public totalSupply;
uint public maxSupply;
bool public isMintEnabled;
// Mapping for amount of minted nfts by an address
mapping(address => uint256) public mintedWallets;
constructor() payable ERC721('Pokemon Card', 'POKE') {
maxSupply = 20;
}
function toggleIsMintEnabled() external onlyOwner {
isMintEnabled = !isMintEnabled;
}
function setMaxSupply(uint256 _maxSupply) external onlyOwner {
maxSupply = _maxSupply;
}
function mint(string memory tokenURI) external payable {
require(isMintEnabled,"Minting is not enable");
require(mintedWallets[msg.sender] < 2, 'You have reached maximum mint number');
require(msg.value == mintPrice, "Wrong value");
require(maxSupply > totalSupply, "Sold Out ! ");
mintedWallets[msg.sender]++;
totalSupply++;
uint256 tokenId = totalSupply;
_safeMint(msg.sender, tokenId);
_setTokenURI(tokenId,tokenURI);
}
}
Thanks already.
Okay i figured out that i forget to implement ERC721URIStorage when naming my contract.
i changed it to contract MintNft is ERC721URIStorage, Ownable
Now it works fine.

Allow ERC20 token for minting ERC721 NFT

I'm new in Solidity and trying to allow purchasing using ETH and other token such as USDT but I keep getting this error no matter what I tried.
DeclarationError: Identifier already declared. --> contract-9b5b02c5de.sol:9:1:
|
9 | import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
This is my code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "#openzeppelin/contracts#4.8.0/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts#4.8.0/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts#4.8.0/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts#4.8.0/access/Ownable.sol";
import "#openzeppelin/contracts#4.8.0/utils/Counters.sol";
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Combat is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
ERC20 public tokenUsdt;
uint256 public ethPrice = 0;
uint256 public usdtPrice = 0;
uint256 public maxSupply; //Maximum amount token
bool public isMintEnabled; //default : false
mapping(address=>uint256) public mintedWallets;
constructor(address _tokenUsdt) ERC721("XXX", "QAZ") {
maxSupply = 100;
tokenUsdt = ERC20(_tokenUsdt);
}
function setToken(address _tokenUsdt) external onlyOwner {
tokenUsdt = _tokenUsdt;
}
function setPrice(uint256 _ethPrice, uint256 _usdtPrice) external onlyOwner {
ethPrice = _ethPrice;
usdtPrice = _usdtPrice;
}
function buyMembershipUsdt() external payable {
require(msg.value >= usdtPrice, "Price Error");
tokenUsdt.safeTransferFrom(msg.sender, owner(), _amount);
mintMembership();
}
function buyMembershipEth() external payable {
require(msg.value >= ethPrice, "Price Error");
mintMembership();
}
function mintMembership() internal {
require(isMintEnabled, "Not For Sale");
require(totalSupply() < maxSupply, "Sold Out");
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(msg.sender, tokenId);
}
function setMintEnabled(bool isMintEnabled_) external onlyOwner {
isMintEnabled = isMintEnabled_;
}
function _baseURI() internal pure override returns (string memory) {
return "ipfs://bafybeiebgbvibloa3p3vge7ecxobwxxnuyg4pdozbcfjigfglhz2ogidq4/";
}
function setMaxSupply(uint256 maxSupply_) external onlyOwner{
maxSupply = maxSupply_;
}
function withdraw() public onlyOwner {
require(address(this).balance > 0, "Balance is 0");
payable(owner()).transfer(address(this).balance);
}
function withdrawToken() external onlyOwner {
uint256 tokenBalance = tokenUsdt.balanceOf(address(this));
require(tokenBalance > 0, "Insufficient balance");
tokenUsdt.safeTransfer(msg.sender, tokenBalance);
}
// The following functions are overrides required by Solidity.
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
I seen some guides our there but none seems to help because it uses custom token which I'm not using it. Regardless whether I'm using IERC20 or ERC20, I will keep getting error above I mentioned. Am I missing something or what?
You import should be
import "#openzeppelin/contracts#4.8.0/token/ERC20/ERC20.sol";
instead of
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";

How do I accept an ERC20 token for Nft mint payment instead of ETH

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

Exclusive NFT per smart contract in SOLIDITY

I want to mint only one exclusive NFT per smart contract. All tutorials and books shows how to make collectables through inheritance of ERC721. So the simple code is:
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "hardhat/console.sol";
contract SimpleCollectible is ERC721 {
uint256 public tokenCounter;
constructor () public ERC721 ("Dogie", "DOG"){
tokenCounter = 0;
}
function createCollectible(string memory tokenURI) public returns (uint256) {
uint256 newItemId = tokenCounter;
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
tokenCounter = tokenCounter + 1;
return newItemId;
}
}
How restrict minting to 1 piece of art?
Add a condition to tokenCounter. You could use the following:
function createCollectible(string memory tokenURI) public returns(uint256) {
require(tokenCounter == 0, "error msg here");
uint256 newItemId = tokenCounter;
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
tokenCounter = tokenCounter + 1;
return newItemId;
}
In fact, there are tons of ways of achieving the same result. Maybe you could use a simple boolean to save a little bit on gas.
I hope you fin this useful :)

how to write a contract to set a reward for players and they claim the reward?

I want to create a contract to give the players rewards and they claim their rewards.
It seems everything is ok!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract Rewards is Ownable {
IERC20 public rewardsToken;
mapping(address => uint) public rewards;
constructor(address _rewardsToken) {
rewardsToken = IERC20(_rewardsToken);
}
function setReward(address account,uint256 amount) public onlyOwner {
rewards[account] = amount;
}
function claimReward() public{
uint256 reward = rewards[msg.sender];
rewards[msg.sender] = 0;
rewardsToken.transfer(msg.sender, reward);
}
}
but I don't know why when I claim the reward nothing happens and I have this errors.
how can I send tokens to my contract?
rewardsToken.transfer(msg.sender, reward);
This snippet fails because the Rewards contract address doesn't hold sufficient token balance.
Solution: Send at least the reward amount of tokens to the Rewards contract address, so that the contract can transfer them to the user.
stakingToken = contract address token
rewardsToken = wallet where you have the tokens
Note: You need approve() the smart contract address and amount after created this
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract Rewards is Ownable {
IERC20 public stakingToken;
IERC20 public rewardsToken;
mapping(address => uint) public rewards;
constructor(address _stakingToken, address _rewardsToken) {
stakingToken = IERC20(_stakingToken);
rewardsToken = IERC20(_rewardsToken);
}
function setReward(address account,uint256 amount) public onlyOwner {
rewards[account] = amount;
}
function claimReward() public{
uint256 reward = rewards[msg.sender];
rewards[msg.sender] = 0;
stakingToken.transferFrom(address(rewardsToken), msg.sender,reward);
}
}