Implemented a ERC20Mintable but the safeTransfer in the safeTrans function reverts TRANSFER_FAILED.

Wondering what I did wrong here. Thanks.

pragma solidity 0.8.17;

import "solmate/src/tokens/ERC20.sol";
import "solmate/src/utils/SafeTransferLib.sol";

contract ERC20Mintable is ERC20 {
  using SafeTransferLib for ERC20;

  constructor (string memory name, string memory code, uint8 decimal) 
    ERC20(name, code, decimal) 


  function mint(address to, uint amount) public {
    _mint(to, amount);

  function safeTrans(address to, uint amount) public {

    ERC20(this).safeApprove(to, amount);

    ERC20(this).safeTransfer(to, amount);



const { expect } = require("chai");
const { ethers } = require("hardhat");
const { TASK_COMPILE_SOLIDITY_HANDLE_COMPILATION_JOBS_FAILURES } = require("hardhat/builtin-tasks/task-names");

describe('ERC20Mntable', function() {

  describe('test safetransfer', () => {
    it('safetransfer', async () => {
      const token0 = await ethers.getContractFactory("ERC20Mintable");
      contract0 = await token0.deploy('token0', 'TOK0', 18);
      const token1 = await ethers.getContractFactory("ERC20Mintable");
      contract1 = await token1.deploy('token1', 'TOK1', 18);

      [owner, addr1] = await ethers.getSigners();

      await contract0.connect(owner).mint(owner.getAddress(), 1000)    
      await contract0.connect(addr1).mint(addr1.getAddress(), 1000)
      await contract1.connect(owner).mint(owner.getAddress(), 1000)
      await contract1.connect(addr1).mint(addr1.getAddress(), 1000)

      await contract0.connect(owner).safeTrans(addr1.getAddress(), 500)



1 Answer 1


Ok, so your function safeTrans() needs to be changed a little.

  1. Unfortunately, you cannot give approval here using safeApprove(), because using this library, the token contract becomes the msg.sender and the approval is not perfectly given. Also, you need to give approval to the contract address, not the to address.

  2. I am guessing you need to transfer the tokens from 1 user's wallet to the 2nd using contract's function? In this case, you need to use safeTranferFrom(). The final code will be something like:

    function safeTrans(address to, uint amount) public {
        approve(address(this), amount);
        ERC20(this).safeTransferFrom(msg.sender, to, amount);
  • Great thanks. I am curious why safeApprove doesn't work, i.e.ERC20(this).safeApprove(address(this), amount);
    – mkmkmkmk
    Dec 6, 2022 at 14:59
  • According to me, the reason for it not working was ERC20(this) instance you were attaching to safeApprove(). When you do that, the attached instance becomes the target contract, and thus the calling contract becomes the msg.sender. Here, both the contracts were in fact your own contract. Thus, approval was given from your contract itself, instead of from your actual msg.sender address. Expected allowance was never provided. Dec 7, 2022 at 4:46

Your Answer

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

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