Currently, I try to send Wrapped ETH from my account to a contract address by using IERC20. But it returned an error on Remix. By the way, I could call token.balanceOf(msg.sender)
but can't execute token.transferFrom(msg.sender, address(this), amount)
somehow.
My code is below
pragma solidity ^0.6.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol";
contract Test2 {
IERC20 public token;
constructor(address _token) public {
token = IERC20(_token);
}
function getBalance() public view returns(uint) {
uint balance_ = token.balanceOf(msg.sender);
return balance_;
}
function deposit(uint amount) public {
require(amount <= token.balanceOf(msg.sender), "you don't have enough balance.");
token.transferFrom(msg.sender, address(this), amount);
}
}
And ERC20 token I want to send is Wrapped ETH. So I copied the WETH contract and deployed on Remix before I deployed this contract. And when I deploy the above contract I add deployed
WETH contract address as an argument of the constructor.
The error message is always like below on Javascript VM on Remix IDE. But this error message doesn't tell what the real problem is. making my contract payable doesn't make sense and I checked that the balance I own is always more than I want to send.
VM error: revert. revert The transaction has been reverted to the initial state. Note: The called function should be payable if you send value and the value you send should be less than your current balance.
WETH contract is here but actually which erc20 I use doesn't matter because I tried the same thing with other deployed ERC20 tokens and even external LINK contract on the Ropsten net (https://ropsten.etherscan.io/address/0x20fe562d797a42dcb3399062ae9546cd06f63280)
contract WETH9 {
string public name = "Wrapped Ether";
string public symbol = "WETH";
uint8 public decimals = 18;
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
event Deposit(address indexed dst, uint wad);
event Withdrawal(address indexed src, uint wad);
mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
function() public payable {
deposit();
}
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
Deposit(msg.sender, msg.value);
}
function withdraw(uint wad) public {
require(balanceOf[msg.sender] >= wad);
balanceOf[msg.sender] -= wad;
msg.sender.transfer(wad);
Withdrawal(msg.sender, wad);
}
function totalSupply() public view returns (uint) {
return this.balance;
}
function approve(address guy, uint wad) public returns (bool) {
allowance[msg.sender][guy] = wad;
Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
returns (bool)
{
require(balanceOf[src] >= wad);
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad);
allowance[src][msg.sender] -= wad;
}
balanceOf[src] -= wad;
balanceOf[dst] += wad;
Transfer(src, dst, wad);
return true;
}
}
Please help me if you know what the problem is! thanks!
Best Answer
Let's take a look at this method:
What the contract does is transfer a quantity
amount
of WETH token from the caller of the function (msg.sender
) to the contract (address(this)
).Now let's see the
transferFrom
method. The causes of transaction failure are as follows :In your
Test2
contract, the caller ofdeposit
is the user who interact with the contract. However, the caller oftransferFrom
is the contract itself, not the user. Thenmsg.sender
is not the same inTest2
andWETH9
contracts during the transaction execution. The user must thereforeapprove
theTest2
contract to allow it to transfer their token.See this for more information : Approve contract to withdraw funds from users's wallet