I’m building an NFT marketplace where users can purchase NFTs using my custom ERC20 token instead of ETH. I have a marketplace contract that uses IERC20 interface to interact with my token called DGX. My main issue is understanding how to properly handle the approval process when someone clicks the buy button on my frontend. I need to figure out how to get the user’s wallet to approve spending their DGX tokens for the purchase.
HERE’S MY MARKETPLACE CONTRACT:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract NFTMarketplace is ReentrancyGuard, Ownable {
struct CurrencyInfo{
IERC20 tokenContract;
uint256 listingCost;
uint256 creationCost;
uint256 itemPrice;
}
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
Counters.Counter private _soldItems;
IERC20 public tokenContract;
CurrencyInfo[] public AcceptedTokens;
address payable owner;
constructor() {
owner = payable(msg.sender);
}
struct MarketItem {
uint itemId;
address nftContract;
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}
mapping(uint256 => MarketItem) private idToMarketItem;
event MarketItemCreated (
uint indexed itemId,
address indexed nftContract,
uint256 indexed tokenId,
address seller,
address owner,
uint256 price,
bool sold
);
function AddToken (IERC20 _tokenContract,uint256 _listingCost,uint256 _creationCost,uint256 _itemPrice) public onlyOwner {
AcceptedTokens.push(CurrencyInfo({
tokenContract:_tokenContract,
listingCost:_listingCost,
creationCost: _creationCost,
itemPrice:_itemPrice
}));
}
function approveToken (uint256 _tokenId) public payable nonReentrant{
CurrencyInfo storage currency = AcceptedTokens[_tokenId];
tokenContract = currency.tokenContract;
uint256 maxAmount = 500000000000000000000000000;
tokenContract.approve(msg.sender, maxAmount);
}
function getListingCost(uint256 _tokenId) public view returns (uint256) {
CurrencyInfo storage currency = AcceptedTokens[_tokenId];
return currency.listingCost;
}
function listItem(address nftContract,uint256 tokenId,uint256 _tokenId) public payable nonReentrant {
CurrencyInfo storage currency = AcceptedTokens[_tokenId];
tokenContract = currency.tokenContract;
uint256 listingCost = currency.listingCost;
uint256 itemPrice = currency.itemPrice;
require(itemPrice > 0, "Price must be greater than zero");
require(msg.value == listingCost, "Must pay listing fee");
_tokenIds.increment();
uint256 itemId = _tokenIds.current();
idToMarketItem[itemId] = MarketItem(itemId,nftContract,tokenId,payable(msg.sender),payable(address(0)),itemPrice,false);
IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);
emit MarketItemCreated(itemId,nftContract,tokenId,msg.sender,address(0),itemPrice,false);
}
function purchaseItem(address nftContract,uint256 itemId,uint256 _tokenId) public payable nonReentrant {
CurrencyInfo storage currency = AcceptedTokens[_tokenId];
tokenContract = currency.tokenContract;
uint256 listingCost = currency.listingCost;
uint price = currency.itemPrice;
uint tokenId = idToMarketItem[itemId].tokenId;
tokenContract.approve(msg.sender, price);
require(msg.value == tokenContract.balanceOf(address(this)), "Insufficient balance");
idToMarketItem[itemId].seller.transfer(msg.value);
IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId);
idToMarketItem[itemId].owner = payable(msg.sender);
idToMarketItem[itemId].sold = true;
_soldItems.increment();
payable(owner).transfer(listingCost);
}
function fetchMarketItems() public view returns (MarketItem[] memory) {
uint itemCount = _tokenIds.current();
uint unsoldItemCount = _tokenIds.current() - _soldItems.current();
uint currentIndex = 0;
MarketItem[] memory items = new MarketItem[](unsoldItemCount);
for (uint i = 0; i < itemCount; i++) {
if (idToMarketItem[i + 1].owner == address(0)) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
}