I have two methods: sendfromself() and getbalance()
The only difference is that the first method, checks if the msg.sender has any coins in the ERC20 address supplied in the method's arguments, and if so, transfers that balance to the contract.
The second method, checks if the contract has any ERC20 coins and if so, transfers these coins to a nominated address.
Strangely the second method works, the first one sendfromself() does not. For the avoidance of doubt, I have invoked the ERC20 approve() method with the address of this contract.
What am I doing wrong? Why doesn't the first method send me msg.sender's ERC20 coins?
from vyper.interfaces import ERC20
event balancex:
balancex: uint256
other: constant(address) = 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db
@payable
@external
def sendfromself(_coin: address) -> bool:
amount: uint256 = ERC20(_coin).balanceOf(msg.sender)
log balancex(amount)
if amount > 0:
ERC20(_coin).transferFrom(msg.sender, self, amount)
return True
@payable
@external
def getbalance(_coin: address) -> bool:
amount: uint256 = ERC20(_coin).balanceOf(self)
response: Bytes[32] = raw_call(
_coin,
concat(
method_id("transfer(address,uint256)"),
convert(other, bytes32),
convert(amount, bytes32),
),
max_outsize=32,
)
if len(response) != 0:
assert convert(response, bool)
return True
Best Answer
For
transferFrom(from, to, amount)
to work, the calling address (msg.sender
) need to have enough token allowance assinged by thefrom
address, even if thefrom
address was the calling address itself. This might be counter-intuitive, as why should the calling address have approval to use its own token balance? But apparently that's how ERC20 is implemented. So you should proceed this line with: