(That's a very long answer to a rather simple question, TLDR: BEP20.transfer()
is an external call to a contract, payable.send()
isn't)
The difference between fallback and receive is well explained in the article linked in the other answer. About the difference between
payable(_to).transfer(_amount);
and
IBEP20(tokenAddress).transfer(to, amount);
well while they might look similar (and are pretty much exactly the same for the end user), they're radically different from a dev standpoint. Let's break them down.
First, IBEP20(tokenAddress).transfer(to, amount);
. Here we're making an external call to the contract located at tokenAddress using the transfer function from the IBEP20. What happens there is that we're sending a message to an external contract. If that contract happens to have a function that's called transfer
and takes an address and an uint256 (in that order) as parameters, it gets executed and then the execution jumps back to your contract; if it doesn't exist, then the contract's fallback()
function gets executed instead, and if it doesn't exist AND there's no fallback function or if you're calling to a non-contract address, the transaction reverts. Essentially, we're treating the external contract as a blackbox, for all we know it could contain completely arbitrary logic, do nothing, or even contain malicious code (look up reentrancy attacks).
payable(_to).transfer(_amount)
: here we're using a solidity keyword, transfer
, which is used to send _amount
of ether (I'm referring to the native chain's token as "ether". That's what you'll find in most documentation as well, but it can be anything you want, BNB on the BSC, MATIC on polygon...) to a payable
address (making an address payable
in your contract just means that you're acknowledging that this address can receive ether, which isn't the case of all addresses. Contracts that don't implement a fallback or receive function simply can't receive ether. If you end up sending ether to one of those, the transaction will revert). We actually know what we're doing, we're not relying on an external contract but on the EVM directly. Now for most application, they essentially work the same, but in some cases (typically when you have the user send a BEP 20 token of its choice, like in a DEX for example), they have to be treated differently.