1

This contract created token and has stored it in his own address (contract address).
I want to implement a function that transfer token from this contract address to an account address.

pragma solidity ^0.8.4;

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

contract MyToken is ERC20 {
    constructor() ERC20("MyToken", "MTK") {
        _mint(address(this), 500 * 10 ** decimals());
    }
   
    function testTra(address _to, uint _amount) public{
        transfer(_to,_amount);
    }
}

it didn't work, it shows an error in remix ide.

ERC20: transfer amount exceeds balance

Also when I check the balanceOf of the contract address it shows that it has tokens.
Basically, what I want is a user call testTra() to get rewarded with ERC20 token. How can users receive tokens from MyToken contract?

2 Answers 2

1

According to the OpenZeppelin documentation (OpenZeppelin), following has to be satisfied for transfer function:

  • recipient cannot be the zero address.
  • the caller must have a balance of at least amount.

The caller means the msg.sender. Now when someone calls your contract, their address is the msg.sender. When transfer function is invoked, it checks if the msg.sender has enough balance. However, all the token balance actually lies in the contract address, so that's why msg.sender has a balance of 0. And hence the transaction fails.

So in short words, what happens is, when Person A calls your testTra function, the contract tries to send the balance of Person A to the address specified in _to parameter.

The issue with your logic is that, if you mint tokens for the address of the contract, you cannot do anything with those tokens, because your contract will never be msg.sender in this case. Thus you can neither give allowance in your testTra function nor use transferFrom or transfer. What you can do however, is use another address (like another smart contract) as manager of tokens and mint the tokens to that address.

pragma solidity ^0.8.4;

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

contract MyToken is ERC20 {
    constructor(address _manager) ERC20("MyToken", "MTK") {
        _mint(_manager, 500 * 10 ** decimals());
    }
   
    function testTra(address _to, uint _amount) external{
        transfer(_to,_amount);
    }
}


contract ManagerContract {
    address public myTokenAddress;
    address public owner;
    constructor(){
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    modifier addressIsNotEmpty() {
        require(myTokenAddress != address(0), "Address is empty!");
        _;
    }

    function setMyTokenAddress(address _myTokenAddress) public onlyOwner {
        myTokenAddress = _myTokenAddress;
    }

    function testTra(address _to, uint _amount) public addressIsNotEmpty {
        (bool success, ) = myTokenAddress.call(abi.encodeWithSignature("testTra(address,uint256)",_to,_amount));

    }
}

What will happen is that, you first deploy your ManagerContract. And then you are going to deploy the TokenContract by providing the address of the ManagerContract in the constructor. After that you will call setMyTokenAddress function with the address of the TokenContract. With this way, the user now has to call testTra function in manager contract to get tokens. After that, user can normally interact with TokenContract.

0
1

If you want to transfer ERC20 from one wallet to another you can just use the "transfer" method, however the sender must have the ERC20 in the wallet. An example of this in javascript you can use:

let contract = new web3.eth.Contract("CONTRACT_ABI HERE", "ADRESSS HERE");
contract.methods
.transfer("USER RECEIVE ADDRESS", web3.utils.toWei("1000"))
.send({
  from: USER_SENDER,
  gas: 200000
}).on("receipt", async (response) => {
   console.log(response);
})

If you want to transfer values that are in your contract to some other wallet, the process is basically simple.

You need to first import the IERC20 interface into your contract.

Below I'll put a simplified example of the process, a detail that I'm using Ownable to "protect" our withdrawal method, once it became public anyone could withdraw the values from our contract.

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

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

contract MyContract is Ownable{
   IERC20 MyToken;

  constructor(address _contractAddress){
    MyToken= IERC20(_contractAddress);
  }

   function withdraw(address _to) public onlyOwner  {
        // Check balance token of contract
        uint256 balance = MyToken.balanceOf(address(this));
        
        if(balance > 0){
          MyToken.transfer(_to, balance);    
        }                  
    }
}

I hope it could have helped.

2
  • The question is about sending the transfer from a contract.
    – Ismael
    Apr 10, 2022 at 3:43
  • 1
    @Ismael I added in the answer an example of how to withdraw the contract.
    – Phpiando
    Apr 11, 2022 at 7:15

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.