This article explains the inner workings of approve and allowance methods in ERC20 tokens, shedding light on how they facilitate secure token transfers within the Ethereum ecosystem.
In the world of Ethereum and ERC20 tokens, you have control over your digital assets. But what happens when you want a smart contract to use some of your tokens on your behalf? This is where the concepts of approve and allowance become crucial for managing permissions and ensuring the security of your tokens.
Let's break down ERC20 approvals and allowances:
Imagine this: You have some ERC20 tokens (like digital money). You want a smart contract (a program on the blockchain) to spend some of them on your behalf, but not all.
Here's where approve and allowance come in:
approve(spender, amount): This is your action. You use it to give permission ("approval") to another address (spender) to use a specific amount of your tokens.
// You give permission to the "exchangeContract"
// to spend up to 100 of your tokens
myToken.approve(exchangeContract, 100); allowance(owner, spender): This function lets anyone check how many tokens a spender is allowed to use from an owner.
// Check how much the "exchangeContract"
// is allowed to spend from your account
uint256 allowedAmount = myToken.allowance(msg.sender, exchangeContract); transferFrom(from, to, amount): The spender (e.g., the exchange contract) uses this function to actually move your tokens. Important:
spender can only transfer up to the allowance you set.from address must be your address (the one that gave approval).// Inside the "exchangeContract" (simplified):
function buySomething(address _from, uint256 _amount) public {
// ... some logic ...
// Transfer tokens from the user to the contract
myToken.transferFrom(_from, address(this), _amount);
// ... more logic ...
}Key Points:
spender contract is compromised, you could lose tokens.increaseAllowance and decreaseAllowance exist to manage allowances more safely.This codebase demonstrates a basic ERC20 token implementation and its interaction with an example exchange contract. The MyToken.sol contract defines the ERC20 token with standard functions like transfer, approve, transferFrom, and allowance. The Exchange.sol contract simulates an exchange platform that utilizes the ERC20 token. It showcases the use of the transferFrom function to spend user-approved tokens for a hypothetical purchase scenario. The example emphasizes the importance of the approve function, where users grant permission to the exchange contract to spend a specified amount of their tokens. This pattern highlights a common practice in decentralized finance (DeFi) for interacting with ERC20 tokens in a secure and controlled manner.
This example demonstrates a simple ERC20 token (MyToken) and how to use approve, allowance, and transferFrom for interacting with it.
1. MyToken.sol (ERC20 Token Contract):
pragma solidity ^0.8.0;
// Import the ERC20 interface from OpenZeppelin
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
contract MyToken is IERC20 {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_totalSupply = 1000 * 10**18; // 1000 tokens with 18 decimals
_balances[msg.sender] = _totalSupply;
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function decimals() public pure override returns (uint8) {
return 18;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public override returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public override returns (bool) {
address spender = msg.sender;
uint256 currentAllowance = _allowances[from][spender];
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(from, spender, currentAllowance - amount);
}
_transfer(from, to, amount);
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
}2. Exchange.sol (Example Contract Using Approvals):
pragma solidity ^0.8.0;
// Import the ERC20 interface
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
contract Exchange {
IERC20 public myToken; // Instance of your ERC20 token
constructor(address _tokenAddress) {
myToken = IERC20(_tokenAddress);
}
function buySomething(uint256 _amount) public {
// ... some logic ...
// Transfer tokens from the user to the contract
require(myToken.transferFrom(msg.sender, address(this), _amount), "Transfer failed");
// ... more logic ...
}
}Explanation:
transfer, approve, transferFrom, allowance, etc.buySomething function demonstrates how to use transferFrom to spend user-approved tokens.How to Use:
MyToken.sol: This will create your ERC20 token.Exchange.sol: Pass the address of your deployed MyToken contract to the constructor.approve function on your MyToken contract. Specify the Exchange contract address as the spender and the desired token amount.buySomething function on the Exchange contract. The contract will then be able to use transferFrom to spend your approved tokens.Important Notes:
Understanding the Risks:
Mitigating Risks:
increaseAllowance and decreaseAllowance: These functions provide a safer way to adjust allowances without having to revoke and re-approve. They help prevent certain types of front-running attacks.Beyond the Basics:
approve and transferFrom are standard ERC20 functions, the functions increaseAllowance and decreaseAllowance are not strictly part of the original ERC20 standard. However, they are widely adopted and considered best practice for improved security.Remember: Understanding ERC20 approvals is essential for safely navigating the world of decentralized applications (dApps) and DeFi. Always be cautious, do your research, and prioritize the security of your digital assets.
This table summarizes the key concepts of ERC20 token approvals and allowances:
| Concept | Description | Your Role | Spender's Role |
|---|---|---|---|
approve(spender, amount) |
Grants permission to a spender (address) to use a specific amount of your tokens. |
You call this function to set the allowance. | Receives the allowance. |
allowance(owner, spender) |
Checks the remaining amount of tokens a spender is allowed to use from an owner. |
You can use this to verify the allowance you set. | Anyone can call this function to check the allowance. |
transferFrom(from, to, amount) |
Used by the spender to transfer tokens from the owner (you) to another address. |
Your address is used as the from address. |
Spender calls this function to move your tokens. |
Security Considerations:
Advanced Features:
increaseAllowance and decreaseAllowance offer more granular control over allowances.Understanding and properly managing ERC20 token approvals is crucial for secure participation in the decentralized world. By grasping the roles of approve, allowance, and transferFrom, users can confidently interact with smart contracts while minimizing the risks associated with token permissions. Remember to follow best practices like approving only the necessary amounts, revoking unused allowances, and utilizing advanced features like increaseAllowance and decreaseAllowance for enhanced security. As you explore the exciting possibilities of dApps and DeFi, prioritize the safety of your digital assets by staying informed and adopting secure practices.
ERC-20's approve/transferFrom security concerns for the ICRC-1 ... | Hi everyone, Yesterday during the Ledger&Tokenization Working Group we discussed ERC-20 the approve/transferFrom flow and its issues. Only 16 people participated in the meeting so I thought it could be useful to have a conversation about the topic here on the forum. For context, on Friday we asked people whether ERC-20 like approve/transferFrom should be added to the ICRC-1 Token Standard and half of the people voted against it. If we had to make a decision right now we would not include appro...
IERC20 approve and Allowance not matching - Contracts ... | Hey, so i'm writing a smart contract for a staking pool but i have been stuck for days with the exactly same problem. I keep getting "insufficient allowance" when trying to use my contract to transfer to another address on behalf of the client. The thing is that my contract has run IERC20.approve() method and it returns a true. I tried debugging and found that even though the approve method works. the allowance for some reason is still 0. No matter the amount i placed on the approve method. Is ...
ERC 20 - OpenZeppelin Docs | Emitted when the allowance of a spender for an owner is set by a call to approve . ... Finally, the non-standard decreaseAllowance and increaseAllowance ...
increaseAllowance and decreaseAllowance ERC20 - Support ... | We all know the problem ERC20 has about front-running approve, so I won't go into explaining this. in OZ v4, increaseAllowance and decreaseAllowance was added to mitigate this and honestly, the way I look at these functions, they really solved the problem. Assume Bob has 100 tokens allowed to spend by Alice. If Alice wants to update the allowance to 150, she calls increaseAllowance(50). Even if Bob front-runs this and calls transferFrom beforehand, Bob will only be able to end up in the end wi...
ERC 20 - OpenZeppelin Docs | Finally, the non-standard decreaseAllowance and increaseAllowance functions ... Not doing so will make the contract unpausable. Functions.