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;
}