0

I'm trying to transfer balance from one account to another, but whenever I try I get the following feedback...

Error: Returned error: VM Exception while processing transaction: revert ERC20: transfer amount exceeds allowance -- Reason given: ERC20: transfer amount exceeds allowance.

I'm trying to do this action via frontend (solidity test unit).

Below I put my files.

My file test.js

contract("Token721", (accounts) => {    
    let [alice, bob, cain, dan] = accounts;
    let contractInstance;
    beforeEach(async () => {
        coinInstance = await TokenCoin.deployed();                   
        contractInstance = await Token721.deployed();              
    });
     
    describe("deploy Heroes", async () => {
        it("transfer founds from alice to bob", async () => {
            await coinInstance.transfer(bob, web3.utils.toWei("550", "ether"));
            let totalBob  = await coinInstance.balanceOf(bob);

            assert.equal(web3.utils.fromWei(totalBob.toString()), "550");
        })
        it("invoke a new hero", async () => {
            let totalBob  = await coinInstance.balanceOf(bob);
            console.log("TOTAL BOB "+web3.utils.fromWei(totalBob.toString()));
            
           const hero = await contractInstance.invokeRandomHero(bob, 
                'https://myurl.com/heroes/8356281049284737', cain, {from: bob, gas: 3000000});
            // const uri = await hero.tokenURI();        

            totalBob  = await coinInstance.balanceOf(bob);
            console.log("TOTAL BOB "+web3.utils.fromWei(totalBob.toString()));

            let totalCain  = await coinInstance.balanceOf(bob);
            console.log("TOTAL CAIN "+web3.utils.fromWei(totalCain.toString()));
        });
        xit("total heroes created is equals 1", async () => {
            const total = await contractInstance.totalHeroes();
            assert.equal(total.toString(), "1");
        });
    });
})

My file ERC721.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract Token721 is Ownable, ERC721URIStorage {
  using Counters for Counters.Counter;
  Counters.Counter private _tokenIds;
  
  //event para novos hero invocados
  event CreatedNewHero(uint heroId, string uri);
  //TEST COIN
  address coin;
  uint amountInvoke = 300;
 
  constructor(address _coin) ERC721("Token721", "SAKH") {
    coin = _coin;
  }

  function setCoin(address _coin) public{
    coin = _coin;
  }

  function invokeRandomHero(address _player, string memory _tokenURI, address _recepient) public returns (uint){
    //CHECK IF EXISTS COINS
    IERC20 tokenA = IERC20(coin);
    uint _total = tokenA.balanceOf(_player);

    if(_total < amountInvoke)
      revert("No Founds");
      
    tokenA.transferFrom(_player, _recepient, 300);

    _tokenIds.increment();

    uint256 newHeroId = _tokenIds.current();
    _mint(_player, newHeroId);
    _setTokenURI(newHeroId, _tokenURI);

    // emit CreatedNewHero(newHeroId, _tokenURI); 

    return newHeroId;       
  }

  function totalHeroes() public view returns(uint){
    return _tokenIds.current();
  }

}

1 Answer 1

0

Asumming that the TokenCoin contract is an ERC20 you need to call approve before attempting a transfer. and also you need to run the TokenCoin contract as alice to with the connect method.

It will look like this:

it("transfer founds from alice to bob", async () => {
        await coinInstance.connect(alice).approve(bob, web3.utils.toWei("550", "ether"));
        await coinInstance.connect(alice).transfer(bob, web3.utils.toWei("550", "ether"));
        let totalBob  = await coinInstance.balanceOf(bob);

        assert.equal(web3.utils.fromWei(totalBob.toString()), "550");
    })
3
  • Thanks for the answer.. I would like to use transfer inside the invokeRandomHero method, would it be possible? Or not?
    – Crazy
    Nov 1, 2021 at 14:31
  • You can, as long as you do the approve first outside of the function
    – Julissa DC
    Nov 1, 2021 at 17:10
  • I tried this: ``` lang-js await coinInstance.connect(alice).approve(cain, web3.utils.toWei("550", "ether"), {from: bob}) const hero = await contractInstance.invokeRandomHero(bob, 'myurl.com/heroes/8356281049284737', cain, {from: bob, gas: 3000000}); ``` but I'm having the error saying: ``` TypeError: coinInstance.connect is not a function```
    – Crazy
    Nov 2, 2021 at 7:32

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.