Isn't this much more convenient?
Not really. When you do this through a gui that operates under this assumption, you aren't going to be filling in the
On the other hand, deploying extra code to the blockchain is expensive. One function that does it all in this case means less gas costs to deploy and less code to create bugs in and to audit.
Is there any implications for doing it this way such as security concerns that I don't see people are doing it like this? If I would like to, should I implement such a function in my own contract?
On the surface, why not? In practice, though, yes, probably many people would lose a lot of tokens... Or, after taking these recommendations into account, the function would likely never end up being used. :)
Because an ERC20 is not ETH, and sending ERC20 to a contract cannot trigger a
fallback() function, the way we almost always send ERC20 to a contract is by
approving() the contract, and then letting the contract pull the ERC20 from you, not pushing the ERC20 to it. (
ERC777 handles this instead by implementing hooks and operators btw, eliminating the need for the
approve() step, and its associated cost and problems.)
Trying to push ERC20 to a contract is basically the number one way it gets lost--just two months ago, a guy accidentally burned $500k USD (on etherscan) (news) by pushing ERC20 wETH to the wETH contract. Why is that a problem? Because the wETH contract is almost certainly designed, like all other ERC20 manipulating contracts, to
pull the tokens, not receive them from a push.
A quick point to understand the rest:
While you may see
safeTransferFrom() in both ERC20 and ERC721 related code, the two functions have basically nothing to do with each other and have very different reasons for claiming to be 'safe'. It is an official part of the
ERC721 spec, but not a part of the
ERC721 spec checks to make sure that, if the recipient is a contract, the recipient can return a magic value in order to confirm that it was designed to receive ERC721 NFTs.
The ERC20 implementation that I'm familiar with comes from Open Zeppelin's
SafeERC20.sol, where the "safe" refers to interacting with and handling non-standards-compliant tokens that don't fail properly. Their tldr:
Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful.
You could handle either/both of those concerns, and yet because you pushed it instead of letting the contract pull it, it would be lost forever because, in general, the contract would have no way of knowing who sent it.
As a part of
safeTransferTo(), you'd have to specify a new
EIP165-esque check to make sure the receiver, if it is a contract, expects and will handle tokens pushed to it directly. However, given that no project out there knows about your token and your token will be the only one doing this to start (getting momentum on new paradigms is hard, and there's a reason we don't do the more intuitive
to instead of
from, as elucidated at the beginning of this answer), this function likely won't end up seeing much use.
ERC20 is a problematic, creaky old standard that we only keep using because of its wide interoperability, even though we all know it's error-prone. Rather than throw in some new standards-non-conforming function, probably best to keep using
SafeERC20--or just switch to
...just make sure you have fully anticipated the re-entrancy consequences that can result from hooks. :)