Example on how to use ERC20 token in another contract

When an ERC20 token holder interacts with another contract using the token, two transactions are required:

  1. The token holder calls approve to set an allowance of tokens that the contract can use. (assuming an OpenZeppelin ERC20 implementation can use increaseAllowance)
  2. The token holder calls the contract to perform an action and the contract can transferFrom an amount of tokens within the set allowance.

The receiving contract can use IERC20 to interact with the tokens ERC20 functions.

The example below includes a SimpleToken ERC20 contract and a TokenReceiver contract (that uses the token), along with the migrations script for truffle to deploy the contracts and some sample interactions using truffle console.

SimpleToken.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "@openzeppelin/contracts/GSN/Context.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 * @title SimpleToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract SimpleToken is Context, ERC20 {

    /**
     * @dev Constructor that gives _msgSender() all of existing tokens.
     */
    constructor () public ERC20("SimpleToken", "SIM") {
        _mint(_msgSender(), 10000 * (10 ** uint256(decimals())));
    }
}

TokenReceiver.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title TokenReceiver
 * @dev Very simple example of a contract receiving ERC20 tokens.
 */
contract TokenReceiver {

    IERC20 private _token;

    event DoneStuff(address from);

    /**
     * @dev Constructor sets token that can be received
     */
    constructor (IERC20 token) public {
        _token = token;
    }

    /**
     * @dev Do stuff, requires tokens
     */
    function doStuff() external {
        address from = msg.sender;

        _token.transferFrom(from, address(this), 1000);

        emit DoneStuff(from);
    }
}

2_deploy.js

// migrations/2_deploy.js
const SimpleToken = artifacts.require('SimpleToken');
const TokenReceiver = artifacts.require('TokenReceiver');

module.exports = async function (deployer) {
  await deployer.deploy(SimpleToken);
  const token = await SimpleToken.deployed();

  await deployer.deploy(TokenReceiver, token.address);
};

Deploy

npx truffle migrate

Interact

Setup

$ npx truffle console
truffle(development)> token = await SimpleToken.deployed()
undefined
truffle(development)> receiver = await TokenReceiver.deployed()
undefined

Attempt to do stuff (requires 1000 tokens but no allowance approved)

truffle(development)> receiver.doStuff()
Thrown:
{ Error: Returned error: VM Exception while processing transaction: revert ERC20: transfer amount exceeds allowance 
-- Reason given: ERC20: transfer amount exceeds allowance.

Approve allowance for receiver contract (for non-OpenZeppelin ERC20 implementations you could call token.approve(receiver.address, 1000))

truffle(development)> token.increaseAllowance(receiver.address, 1000) 

Do stuff (requires 1000 tokens)

truffle(development)> receiver.doStuff() 

Check balance

truffle(development)> (await token.balanceOf(receiver.address)).toString()
'1000'
10 Likes
Approve ERC20 token on another contract
How transferFrom can be used with addresses other than the contract’s own?
How ERC20 approve function works?
Stake contract test but fail to transfer LPtoken to stake
Cannot upgrade ERC20
ERC20: transfer amount exceeds balance
Token swap function 'Fail with error ‘SafeERC20: low-level call failed’
How to transfer an external ERC20 token with IERC20?
"Dai/insufficient-allowance" on transferFrom
Using ERC20 transferFrom on Remix
Using ERC20 transferFrom on Remix
Deploy BEP token to BSC
Can't burnFrom using ERC20PresetMinterPauser
Address with default unlimited allowance
Override approve in OpenZeppelin Contracts version 2.x
Contracts holding tokens
Example of withdrawing an ERC20 from another contract
Approve USDC using IERC20.approve
Extending ERC20PresetMinterPauser
Approve USDC using IERC20.approve
ERC20: Transferring token from another smart contract errors with transfer amount exceeds balance
Deploy BEP token to BSC
Getting a "revert" processing transaction on "transfer" call
What is the interface IERC20 contract used for vs implementation ERC20 contract
ERC20 Transfer failing
Uniswap: transferFrom error Dai/insufficient-allowance
Transfer ERC20 on deploy (truffle migrate)
How to use SafeERC20?
transferFrom fails with error 'Dai/insufficient-allowance'
Transfer and Approve of ERC20 tokens
Using approve to allow transfer of ERC20 tokens in a contract
Uniswap: transferFrom error Dai/insufficient-allowance
Call to Trust.tokensend errored: VM error: invalid opcode
Revert when using ERC20 transferFrom in a contract

2 posts were split to a new topic: How transferFrom can be used with addresses other than the contract’s own?

A post was split to a new topic: Request example of how to withdraw ERC20 token

A post was split to a new topic: ERC20 transferFrom Returned error: sender account not recognized

2 posts were split to a new topic: How to create a school fees payment system using a custom ERC20 token

Hi @abcoathup,

I’m facing this error while trying to implementing your solution:

Member “increaseAllowance” not found or not visible after argument-dependent lookup in contract IERC20

Version:
@openzeppelin/contracts: ^4.0.0
solidity 0.8.3

Any idea about how to resolve it ? Thanks