3

Returned error: VM Exception while processing transaction: revert ERC20: transfer amount exceeds allowance

Code:

ERC20Tokens[tokenTicker].token.approve(ERC20Tokens[tokenTicker].tokenHolder, 10);
    
emit tokenOwnerBalance(ERC20Tokens[tokenTicker].token.balanceOf(ERC20Tokens[tokenTicker].tokenHolder));
    
ERC20Tokens[tokenTicker].token.transferFrom(ERC20Tokens[tokenTicker].tokenHolder, address(this), 1);

Logs:

[
   {
      "from":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "topic":"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
      "event":"Approval",
      "args":{
         "0":"0x7A2946b37399fa3F1C9EF81c7Bcf94AE1099D18F",
         "1":"0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911",
         "2":"10",
         "owner":"0x7A2946b37399fa3F1C9EF81c7Bcf94AE1099D18F",
         "spender":"0x95Ba4cF87D6723ad9C0Db21737D862bE80e93911",
         "value":"10"
      }
   },
   {
      "from":"0x7A2946b37399fa3F1C9EF81c7Bcf94AE1099D18F",
      "topic":"0xcff530ae4ada35c1dd7ac314ef643b9eb7ae40665958ad5899e2fbc18865444a",
      "event":"tokenOwnerBalance",
      "args":{
         "0":"31000000"
      }
   }
]
taranchik
  • 51
  • 1
  • 1
  • 4

2 Answers2

6
ERC20Tokens[tokenTicker].token.approve(ERC20Tokens[tokenTicker].tokenHolder, 10);

This line approves the tokenHolder to spend your contract's tokens. Not the other way around.

So the transferFrom() fails because your contract is trying to spend the tokenHolder's tokens.


If you want your contract to be able to spend tokenHolder's tokens, the tokenHolder needs to execute the approve() function on the token from their address directly. Not through a contract in between.

Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
  • This is a fork of the main Ethereum network and I am trying to send some USDC coins to my account. I found out that the owner of the tokens has some of them, so I use his address. Is there any other way to get multiple USDC coins in this smart contract? – taranchik Sep 12 '21 at 09:53
  • @taranchik Unless you know the private key to the `tokenHolder` address (that you could use to execute the `transfer()` method directly from their address), they need to `approve()` the tokens first from their address directly. There's currently no other known way to spend tokens belonging to an other address without their key/approval. – Petr Hejda Sep 12 '21 at 10:04
  • Passing into the ERC20 openzeppelin constructor token address, would it be possible to get some of these tokens somehow? – taranchik Sep 12 '21 at 10:15
  • @taranchik Only tokens of the contract that you're instantiating (with the constructor). But since the USDC contract is already instantiated, you can't execute its constructor for the second time. – Petr Hejda Sep 12 '21 at 11:34
  • So in other words is the approve function called in the browser via e.g MetaMask, or can it still be called in the contract if the user is invoking that function (is `msg.sender`)? – Dominic Jan 18 '22 at 21:53
  • @Dominic Only directly (e.g. using MetaMask or web3js)... If it were invoked through another contract (_mediator_), the `msg.sender` in the target would hold the value of the _mediator_ address - not the user. – Petr Hejda Jan 18 '22 at 22:07
  • @PetrHejda thanks I thought so but had a param mixed up, got it working now – Dominic Jan 19 '22 at 00:37
1

For me, it was a mistake of using transferFrom instead of transfer when transferring tokens from the contract.

Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223