Need help with custom token integration
I’m building an NFT marketplace where users can purchase digital collectibles using my custom ERC20 token called DGC. I have the basic structure set up but I’m struggling with the approval mechanism.
The main issue: When someone clicks the purchase button on my frontend, how do I properly handle the token approval from their wallet to complete the transaction?
I’m using the IERC20 interface to interact with my token contract, but I’m not sure if my current implementation is correct. The marketplace should allow users to buy and sell NFTs exclusively with DGC tokens.
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 PaymentToken{
IERC20 tokenContract;
uint256 listingCost;
uint256 creationCost;
uint256 itemPrice;
}
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
Counters.Counter private _soldItems;
IERC20 public tokenContract;
PaymentToken[] 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 addPaymentToken(IERC20 _tokenContract, uint256 _listingCost, uint256 _creationCost, uint256 _itemPrice) public onlyOwner {
AcceptedTokens.push(PaymentToken({
tokenContract: _tokenContract,
listingCost: _listingCost,
creationCost: _creationCost,
itemPrice: _itemPrice
}));
}
function executePayment(uint256 _tokenIndex) public payable nonReentrant {
PaymentToken storage token = AcceptedTokens[_tokenIndex];
tokenContract = token.tokenContract;
uint256 maxAmount = 500000000000000000000000000;
tokenContract.approve(msg.sender, maxAmount);
}
function checkAllowance(uint256 _tokenIndex) public payable nonReentrant {
PaymentToken storage token = AcceptedTokens[_tokenIndex];
tokenContract = token.tokenContract;
tokenContract.allowance(address(this), msg.sender);
}
function getListingCost(uint256 _tokenIndex) public view returns (uint256) {
PaymentToken storage token = AcceptedTokens[_tokenIndex];
return token.listingCost;
}
function listItem(address nftContract, uint256 tokenId, uint256 _tokenIndex) public payable nonReentrant {
PaymentToken storage token = AcceptedTokens[_tokenIndex];
tokenContract = token.tokenContract;
uint256 listingCost = token.listingCost;
uint256 itemPrice = token.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 completePurchase(address nftContract, uint256 itemId, uint256 _tokenIndex) public payable nonReentrant {
PaymentToken storage token = AcceptedTokens[_tokenIndex];
tokenContract = token.tokenContract;
uint256 listingCost = token.listingCost;
uint256 itemPrice = token.itemPrice;
uint256 tokenId = idToMarketItem[itemId].tokenId;
tokenContract.approve(msg.sender, itemPrice);
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);
}
}
Any guidance on the proper workflow would be really helpful!