0

I am trying to call transfer of an ERC20 token from another "escrow" smart contract in remix JavaScript VM (London). I have 2 contracts like so:

MyToken.sol (an ERC20Votes.sol, but "votes" should not affect anything here?):

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

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";

contract MyToken is ERC20Votes { uint256 public maxSupply = 555; // * 10**18;

constructor() ERC20("MyToken", "MT") ERC20Permit("MyToken") {
    _mint(msg.sender, maxSupply);
}

// The functions below are overrides required by Solidity.

function _afterTokenTransfer(
    address from,
    address to,
    uint256 amount
) internal override(ERC20Votes) {
    super._afterTokenTransfer(from, to, amount);
}

function _mint(address to, uint256 amount) internal override(ERC20Votes) {
    super._mint(to, amount);
}

function _burn(address account, uint256 amount)
    internal
    override(ERC20Votes)
{
    super._burn(account, amount);
}

}

Escrow3.sol

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

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

import "hardhat/console.sol";

contract Escrow3 { ERC20 token;

constructor(address _token) {
    token = ERC20(_token);
}

function confirm(
    address _recipient,
    uint256 _amount
) external {

    require(msg.sender != _recipient, "Caller cannot be recipient");
    require(token.balanceOf(msg.sender) >= _amount, "Insufficient funds");

    bool sent = token.transfer(_recipient, _amount);
    require(sent, "transfer fail");

}

function getBalanceToken() external view returns(uint256) {
    return token.balanceOf(msg.sender);
}

}

In remix, I first deploy MyToken.sol, then deploy Escrow3.sol with MyToken's address in its constructor. With the deployer's address, I then call getBalanceToken in remix and it returns 555 as expected. In remix, I then call (via deployer's address) confirm with _recipient = another address and _amount = 5. I get this error:

ERC20: transfer amount exceeds balance

This is strange because getBalanceToken clearly shows deployer's address with enough tokens in balance and the check for Insufficient funds did not revert in the confirm function.

I have tried everything and looked everywhere and I still do not understand how to solve this.

user82768
  • 25
  • 4
  • You are using transfer but it will not work in your contract. See for an explanation here: https://ethereum.stackexchange.com/questions/46457/send-tokens-using-approve-and-transferfrom-vs-only-transfer. – Ismael Nov 06 '21 at 05:30
  • @Ismael ok but why does the first check of "Insufficient funds" pass but the second one fail?

    I have also tried approve _ transferFrom, but I can get it to work in the same contract.

    – user82768 Nov 06 '21 at 05:35
  • Because transfer uses the caller's funds, in this case the caller is the contract. – Ismael Nov 06 '21 at 05:39
  • @Ismael I am confused on the caller/msg.sender. My understanding is the "caller" is the address that deployed the Escrow3.sol contract, which is also msg.sender. How does the caller become the contract's address, but msg.sender still being the deployer's address? – user82768 Nov 06 '21 at 05:46
  • Read https://ethereum.stackexchange.com/questions/98892/what-is-the-difference-between-transfer-and-trasnferfrom-and-when-should-i-uthis – Ismael Nov 06 '21 at 05:59
  • thanks, I see now that the only way is to use approve & transferFrom in 2 separate calls and not within the same contract. – user82768 Nov 06 '21 at 06:16

0 Answers0