i intend to use my erc20 token for doing some payment for minting nft. but when i call testPay function always got ERC20: insufficient allowance error.

already looking for answer but can't find one.

can someone tellme what i do wrong here?

msg.sender already have some erc20 token. address(this) don't have token. this contract is not my real nft minting contract, i just want to test the payment function.

contract GameItem is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    ERC20 public GXGToken;

    constructor(address mytoken) ERC721("GameItem", "ITM") {
        GXGToken = ERC20(mytoken);

    function awardItem(address player, string memory tokenURI)
        returns (uint256)

        uint256 newItemId = _tokenIds.current();
        _mint(player, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;

    function approval(uint amount) public{

    function myallowance() view public returns (uint){
        return GXGToken.allowance(msg.sender,address(this));

    function testpay(uint _amount) public{

    function pay(uint _amount) internal{

Edited: ok got it, thanks for all for the replies.

this is what i'm doing.

so i call approve function on erc20 first, approving erc721 address, and amount, then call the transferFrom on erc721 contract, param1 is sender and param2 is erc721 address.

and it's working.

3 Answers 3


msg.sender will have to approve GameItem smart contract address before transferFrom can be initialized to work, you were trying to transfer from the sender and the sender is yet to approve the contract address it won't work, the declaration that you here


GXGToken token has an approve function, the user must interact with GXGToken token contract address direct and use it approval function to approve GameItem smart contract address before the user (address) before the user(address) will call the function.

approve(GameItem smart contract address, _amount);

your intention was that it would automatically set the msg.sender to approve the GameItem smart contract address, it doesn't work that way.

the solution here can explain the use case of Approval and transferFrom excplicitly: What is the use case of transferFrom function in ERC20 token contract?

  • Sorry i'm still confuse how to write the the transferFrom the correct way, can you give me quick example? Or can i just use transfer function?, cause i just want account A to pay my erc20 token to the account B, which is the owner of gameitem smartcontract Commented Feb 12, 2022 at 22:51

The function

function testpay(uint _amount) public{

Is called by msg.sender, so msg.sender is approving msg.sender to spend _amount of this tokens. It is not correct. The function approve works this way -> Lets say Adress A is calling the ERC20 contract, so when he calls approve function, he is saying something like "I, Address A (msg.sender), approve Address B (1st parameter) to spend some amount (2nd parameter) of my tokens". So msg.sender cannot be the first parameter, otherwise he is approving himself to transfer his tokens.

I believe you won't be able to do this with just one transaction. First you will have to make the user access the Token smart contract (ERC20), approving the NFT smart contract (ERC721) to transfers tokens on his/her behalf. That is, you will have to do the msg.sender to execute the approve function on the ERC20 contract, not this one. Then the ERC721 contract will be able to call TransferFrom the ERC20, as TransferFrom (msg.sender, address(this), amount)

  • Thank you for answering, so the approve function must be called on erc20 contract then? But on what event? The minting function is on erc721 contract, so i just call transferFrom from erc721 contract and call approve where or when? Commented Feb 12, 2022 at 23:15
  • Also i always hear can't do in 1 transaction, what do you mean by 1 transaction is 1 function? Commented Feb 12, 2022 at 23:17
  • I believe that the user should first approve the contract to transfer tokens on his behalf, so yes, it should interact first with the ERC20. A transaction means an interaction with a contract, (usually, the execution of one function). The issue is that you are doing 2 different things: Approving a transfer in an ERC20 contract and minting a token in another, ERC721. Commented Feb 13, 2022 at 1:56

Actually the process is very different. msg.sender should first approve the amount to spend to the nft contract using web3 front end.

web3js should call approve function to allow your NFT contract to spend it like (eg. react js front end)

await GXGToken.approve(NFTAddress, amount).then(tx=>{
    tx.wait().then(data => {
       console.log('success', data)


Then in your NFT contract you canll transferFrom function like

function testpay(uint _amount) public{
   GXGToken.transferFrom(msg.sender,address(this), amount);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.