Allowance means that we can grant approval to another contract or address to be able to transfer our ERC20 tokens. And this requirement is common in distributed applications, such as escrows, games, auctions, etc. Hence, we need a way to approve other addresses to spend our tokens. Let's say you have tether contract and you want a DEX(Decentralized Exchange) or any other entity transfer coins from the tether contract. So you keep track of which entity how much can transfer from tether contract in a mapping.
// my address is allowing your address for this much token
mapping(address=>mapping(address=>uint)) public allowance;
In the ERC20 standard, we have a global variable allowed in which we keep the mapping from an "owner's address" to an "approved spender’s" address and then to the amount of tokens. Calling approve() function can add an approval to its desired _spender and _value. The amount of token is not checked here and it will be checked in transfer().
Once the approval is granted, the "approved spender" can use transferFrom() to transfer tokens. _from is the owner address and _to is the receiver’s address and _value is the required number of tokens to be sent. First, we check if the owner actually possesses the required number of tokens.
Let's say you want to deposit some ether to a DEFI platform. Interacting with a DEFI platform is actually interacting with the smart contract of that platform. Before you deposit money, you first approve the transaction. You are telling that this contract address can take some money from my account. Then you call the deposit function of DEFI smart contract and deposit the money. This how transfer occurs in order:
1- Inside Defi, defi contract has deposit to get coin from tether
function depositTokens(uint _amount) public{
require(_amount>0,'amount cannot be zero');
// transfer tether to this contract address for staking
tether.transferFrom(msg.sender,address(this), _amount);
// update the state inside Defi, like staked tokens, amount etc
}
2- Inside tether we have transferFrom
mapping(address=>mapping(address=>uint)) public allowance;
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success){
// check the allowance
require(_value <=allowance[_from][msg.sender]);
balanceOf[_to]+=_value;
balanceOf[_from]-=_value;
allowance[_from][msg.sender]-=_value;
emit Transfer(_from,_to,_value);
return true;
}
The first requirement is checking the allowance. mapping(address=>mapping(address=>uint)) public allowance. So actually before calling this, tether contract has to update its allowance mapping so this transferFrom will run smoothly
3- Update the allowance with approve:
function approve(address _spender, uint _value)public returns (bool success){
allowance[msg.sender][_spender]=_value;
// This event must trigger when a successful call is made to the approve function.
emit Approval(msg.sender,_spender,_value);
return true;
}