i am trying to build a NFT Marketplace using ERC-721. i have two contracts one is Minting Contract and other is Marketplace contract. Everything is working well like from minting to listing. but when i come to buy the NFT that is listed on the fixed price selling.it alwasy gives me error that transaction is reverted to initial state.
then i try to debug the code , using console.log("") the thing my code is not working after line console.log("12") the line that is not working is , contract unable to send royalty fee to the royalty recipient.
when i remove the following line from the function the code is working well
This is the code for both smart contracts. kindly help me to sort out the issue
Minting Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract NFToken is ERC721, ERC721URIStorage, ERC721Burnable, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("NFtToken", "NFTT") {}
mapping(uint256=>mapping(address=>uint256)) public mRoyaltyPercentage;
mapping(uint256=>address) public mMinter ;
function getMinter(uint256 _tokenid) external view returns(address _minterAddress)
{
return mMinter[_tokenid];
}
function getRoyaltyPercentage(uint256 _tokenid , address _address) external view returns(uint256 _royaltyPercentage)
{
return mRoyaltyPercentage[_tokenid][_address];
}
function safeMint(address to, string memory uri , uint256 _royaltypercentage) public
{
require(to != address(0) , "NFT:: invalid address");
require(_royaltypercentage >= 150 && _royaltypercentage <=1000 , "NFT:: invalid royalty percentage | should be in between from 1.5% to 10%");
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
mMinter[tokenId] = to;
mRoyaltyPercentage[tokenId][address(this)] = _royaltypercentage ;
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
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);
}
}
Marketplace Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
interface INFT
{
function getMinter(uint256 _tokenid) external view returns(address _minterAddress) ;
function getRoyaltyPercentage(uint256 _tokenid , address _address) external view returns(uint256 _royaltyPercentage);
}
contract Marketplace is ERC721Holder {
using SafeMath for uint256;
using Counters for Counters.Counter;
Counters.Counter private _listingId;
// State Variables
INFT private inft;
uint256 private platformFee = 250;
// uint256 private royaltyFee = 150;
address public NFTcontract;
address public MarketPlaceOwner = msg.sender;
constructor(address _NFTcontract)
{
NFTcontract = _NFTcontract;
}
// Errors Defined
string public constant REVERT_PAY_EXACT_PRICE = "Marketplace:: pay exact price ";
struct FixedPriceItem
{
bool isSold;
bool forSale;
uint256 tokendId;
uint256 listingId;
uint256 nftPrice;
uint256 royaltyfee;
address seller;
address nftAddress;
address royaltyReciever;
}
mapping(uint256 => FixedPriceItem) public mFixedPriceItem;
event efixedPriceListing(
uint256 _tokenId,
uint256 _listingId,
address _nftaddress,
uint256 _nftPrice,
address _seller
);
function listItemForFixedPrice(address _nftAddress , uint256 _tokenid , uint256 _nftPrice) public returns(bool isListed)
{
inft = INFT(_nftAddress);
uint256 listingId = _listingId.current();
_listingId.increment();
address RoyaltyReciever = inft.getMinter(_tokenid);
mFixedPriceItem[listingId] = FixedPriceItem({
isSold:false,
forSale:true,
tokendId: _tokenid,
listingId: listingId,
nftPrice:_nftPrice,
royaltyfee:inft.getRoyaltyPercentage(_tokenid, _nftAddress),
seller:msg.sender,
nftAddress:_nftAddress,
royaltyReciever: RoyaltyReciever
});
IERC721(_nftAddress).transferFrom(msg.sender ,address(this) , _tokenid);
emit efixedPriceListing(_tokenid,listingId,_nftAddress,_nftPrice,msg.sender);
return true;
}
event eBuyFixedPriceItem(
uint256 _listingid,
uint256 _tokenid,
uint256 _nftPrice,
address _buyer,
address _seller
);
function calculatePlatformFee(uint256 _nftprice , uint256 _pbp) public pure returns(uint256)
{
uint256 platformfee = _nftprice.mul(_pbp).div(10000);
return platformfee;
}
function calculateRoyaltyFee(uint256 _nftprice , uint256 _pbp) public pure returns(uint256)
{
uint256 royaltyfee = _nftprice.mul(_pbp).div(10000);
return royaltyfee;
}
function buyFixedPriceItem(uint256 _listingid) public payable returns(bool isBought)
{
require(msg.value == mFixedPriceItem[_listingid].nftPrice , REVERT_PAY_EXACT_PRICE);
uint256 tokenid = mFixedPriceItem[_listingid].tokendId;
address sellers = mFixedPriceItem[_listingid].seller;
uint256 platformfee = calculatePlatformFee
(
mFixedPriceItem[_listingid].nftPrice , platformFee
);
uint256 royaltyfes = calculateRoyaltyFee
(
mFixedPriceItem[_listingid].nftPrice, mFixedPriceItem[_listingid].royaltyfee
);
uint256 totalFeeCharge = platformFee + royaltyfes;
uint256 amountPayToSeller = mFixedPriceItem[_listingid].nftPrice.sub(totalFeeCharge);
payable(MarketPlaceOwner).transfer(platformfee);
payable(sellers).transfer(amountPayToSeller);
console.log("log 12");
payable(mFixedPriceItem[_listingid].royaltyReciever).transfer(royaltyfes);
console.log("log 13");
IERC721(mFixedPriceItem[_listingid].nftAddress).transferFrom(address(this),msg.sender,tokenid);
console.log("log 14");
emit eBuyFixedPriceItem(_listingid,tokenid,msg.value,msg.sender,sellers);
console.log("log 15");
return true;
}
}