I’m having difficulty making a function that is both payable
and includes the ERC20 transerFrom
method.
I’ve created contracts/Coin.sol:
pragma solidity ^0.6.1;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Coin is ERC20 {
constructor(uint _initialSupply) public ERC20("RandomCoin", "RC") {
_mint(msg.sender, _initialSupply);
}
}
and then contracts/CoinDeploy.sol:
pragma solidity ^0.6.1;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract CoinDeploy {
ERC20 private coin;
address payable public beneficiary;
event DoneStuff(address from);
constructor(ERC20 _coin) public {
coin = _coin;
beneficiary = payable(address(this));
}
function buyCoin(address _receiver, uint256 _amount) external payable {
coin.transferFrom(msg.sender, _receiver, _amount);
emit DoneStuff(_receiver);
}
}
and I migrate this with migrations/2_deploy_contract.js
var Coin = artifacts.require("Coin");
var CoinDeploy = artifacts.require("CoinDeploy");
module.exports = function(deployer) {
deployer.deploy(Coin, 1000).then(function() {
return deployer.deploy(CoinDeploy, Coin.address);
});
};
Entering the truffle console I run the following:
token = await Coin.deployed()
receiver = await CoinDeploy.deployed()
token.increaseAllowance(receiver.address, 1000)
Picking a random address from Ganache I try and buy a Coin for 1 ETH:
receiver.buyCoin("0xE82413334b868122f627eD03157C08dBBD3b2378", 7, {from: "0xE82413334b868122f627eD03157C08dBBD3b2378", value: 1000000000000000000})
this fails with a message “ERC20: transfer amount exceeds balance.”
However if I enter:
receiver.buyCoin("0xE82413334b868122f627eD03157C08dBBD3b2378", 7)
the transaction goes through without problem.
I understand why this is failing. In the first example as I am explicitly sending Eth from a specific account the msg.sender becomes the account I am sending Eth from. And the buyCoin uses msg.sender as the from address in the the transferFrom. And that account has no ERC20, so failure.
In the second example the msg.sender as no Eth is specified, defaults to the first address in Ganache; which is the account that holds the ERC20. So success.
The solution to get the first example to work is therefore obvious (?): change transferFrom
so that the first argument refers to the account that currently holds the ERC20, rather than msg.sender. I’ve tried all sorts of combinations: tx.origin, address(coin), coin.address, etc. But none of them work.
Very grateful for any help.
Environment
Truffle v5.1.30 (core: 5.1.30)
Solidity - ^0.6.0 (solc-js)
Node v14.4.0
Web3.js v1.2.1
OS: Ubuntu 20.04