no matter what I try, I am unable to call token.transferFrom without getting ERC20: transfer amount exceeds allowance - even though I have approved the allowance.

Code speaks better than words:


contract Strategy is ReentrancyGuard {
  IERC20 private  paymentToken;
  Token private  strategyToken;

  constructor(IERC20 _paymentToken, Token _strategyToken) {
    paymentToken = _paymentToken;
    strategyToken = _strategyToken;

  function deposit(uint256 amount) external payable nonReentrant {
    // Transfer payment token from msg.sender to contract
    paymentToken.transferFrom(msg.sender, address(this), amount);

In my test (this is where it fails):

import { expect} from "chai";
import { ethers } from "hardhat";
import { Strategy } from "../typechain/Strategy";
import { Token } from "../typechain/Token";

describe("Strategy", () => {
  let strategy: Strategy;
  let paymentToken: Token;
  let receivedStrategyToken: Token;
  before(async () => {
    const Strategy = await ethers.getContractFactory("Strategy");
    const TokenMock = await ethers.getContractFactory("Token");

    paymentToken = await TokenMock.deploy("Payment token mock", "PAYMOCK") as Token;
    receivedStrategyToken = await TokenMock.deploy("Received token mock", "RECEIVEMOCK") as Token;

    strategy = await Strategy.deploy(paymentToken.address, receivedStrategyToken.address) as Strategy;

  describe("Strategy contract", () => {
    it("It will return a strategy token when depositing", async () => {
      const [addr] = await ethers.getSigners();
      await paymentToken.mint(addr.address, "1000");
      await paymentToken.increaseAllowance(addr.address, "1000");
      expect(await strategy.deposit(1)).to.be.ok;

As stated above, it complains with ERC20: transfer amount exceeds allowance - but I don’t know why, because I have increased the allowance?

  • You have to call approve or increase allowance for the strategy contract, not addr.
    – Ismael
    Jun 12 at 1:14
  • That worked! Ismael, can you please explain why? Jun 12 at 1:26
  • @Ismael the reason why I am confused is because if you look at the source code where this error is thrown (source is OpenZeplin), it makes no reference at all the recipient: uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds Jun 12 at 1:33
  • It is how ERC20 works. The user has to approve the contract for it to be able to access the user's tokens. Without user approval the contract can't access the token, which is quite reasonable. More details here: ethereum.stackexchange.com/questions/80266/….
    – Ismael
    Jun 12 at 1:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.