Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Delegated Token Transfers: The Approve/TransferFrom Pattern

Hello! In our last lesson, we introduced the ERC-20 standard as the essential "API specification" for fungible tokens on Ethereum. We covered its core functions and identified two ways to move tokens: a direct transfer and a delegated approve/transferFrom pattern.

Today, we will do a deep dive into that second mechanism. Your learning outcome is to describe the 'approve' and 'transferFrom' pattern for delegated token transfers. This pattern is the engine that powers most of decentralized finance (DeFi), so understanding it thoroughly is crucial for building a token that can be integrated into the wider ecosystem. We'll explore not just how it works, but why it's necessary and the security considerations you must be aware of as a developer.


1. The Core Problem: Why Not Just transfer?

You might be wondering, if a user wants to send tokens to a smart contract (like a staking or exchange contract), why can't they just use the transfer function we learned about?

This is a fantastic question, and the answer reveals a fundamental aspect of how contracts interact on Ethereum. The original ERC-20 transfer function was designed for sending tokens to another user's wallet (an Externally Owned Account). When you transfer tokens to a smart contract address, the contract receives the tokens, but it is not notified of the transaction. It has no way to react or execute any logic in response to the deposit.

This has led to millions of dollars in tokens being permanently lost. Users transfer tokens to a contract address, assuming the contract will "do something," but the tokens simply get stuck there, inaccessible forever.

Send tokens using approve and transferFrom vs only transfer

This StackExchange answer provides a powerful, real-world example of why blindly transferring tokens to a contract is dangerous. It clearly distinguishes between how the functions work and why the approve/transferFrom pattern is the safer, correct approach for contract interactions.

Read the section titled 'The How vs the Why'. Pay close attention to the story under 'User loses 500k USD'. It's a stark reminder of the consequences of misunderstanding this pattern.

The key takeaway is that for a smart contract to safely handle your tokens as part of a larger operation (like a swap or a deposit), it needs to be the one to initiate the token movement. It needs to pull the tokens from you, not have you push them to it. This is exactly what the delegated transfer pattern enables.


2. The Delegated Transfer Pattern: approve, allowance, and transferFrom

This pattern is a two-step process involving the token owner, a "spender" (usually a dApp's smart contract), and the token contract itself.

  1. Step 1: Approval (approve)
    The token owner calls the approve() function on the token contract. This function takes two arguments:

    • spender (address): The address that is being granted permission to spend tokens.
    • amount (uint256): The maximum number of tokens the spender is allowed to withdraw.

    When this function is called, the token contract updates an internal ledger. It records: "This owner has given this spender permission to withdraw up to this amount." This action costs gas because it writes data to the blockchain.

  2. Step 2: Transfer (transferFrom)
    At a later time, the spender (the dApp) calls the transferFrom() function on the token contract to actually move the tokens. This function takes three arguments:

    • from (address): The address of the original token owner.
    • to (address): The address where the tokens should be sent.
    • amount (uint256): The number of tokens to transfer.

    Before executing the transfer, the token contract performs a crucial check: Does the address calling this function (msg.sender, which is the spender) have a sufficient allowance to withdraw amount from the from address? If yes, the transfer proceeds, and the spender's allowance is reduced by the amount transferred. If no, the transaction reverts.

The allowance(owner, spender) function can be called at any time by anyone to check the remaining amount a spender is approved to withdraw from an owner.

Let's visualize this flow.

ERC-20 'approve' and 'transferFrom' Pattern
This diagram illustrates the two-step delegated transfer. First, the Sender approves the Spender (1). Later, the Spender calls `transferFrom` to move tokens from the Sender's account (2). The table shows how the `balanceOf` and `allowance` values change at each stage.

This mechanism is what enables the rich interactions you see in DeFi.

Transfer, Approve, TransferFrom methods in ERC20

Let's watch a short clip from BlockchainBob that explains this concept in the context of Uniswap, a decentralized exchange you'll interact with later in this course.

Watch the segment from 00:37 to 01:37. It clearly explains how a user grants Uniswap permission to handle a token swap on their behalf. This is a perfect real-world use case.


3. A Practical Demonstration

To see how these function calls look in a development environment, let's watch a hands-on demonstration in the Remix IDE.

How to Use an ERC-20 Token | Solidity (0.6)

The 'Smart Contract Programmer' channel provides a clear walkthrough of this process. Watching someone execute these calls helps connect the theory to practice.

Watch the segment from 06:56 to 08:44. Notice the sequence: Alice's account calls approve for Bob. Then, Bob's account calls transferFrom to pull the tokens from Alice. You'll also see the allowance being checked.

This sequence is the standard for almost every dApp that needs to interact with your tokens, from staking platforms to NFT marketplaces that accept ERC-20 tokens for payment.


4. Security Risks and Best Practices for Developers

As a developer, simply knowing how the pattern works is not enough. You must also be aware of its associated risks and the best practices for secure implementation. When you build dApps, both your contracts and your users will be affected by these considerations.

ERC20 Approve Pattern: Secure Token Allowances Guide

The 'ERC20 Approve Pattern' guide from Speedrun Ethereum is an excellent resource that covers the security landscape of token approvals. We will focus on the most common pitfalls and the recommended best practices.

Please read the following sections from the guide: Section 3: Common Pitfalls & Security Risks: Focus on understanding the vulnerabilities listed in the table, especially 'Infinite Approval' and the 'Race Condition'. Section 4: Best Practices for Developers: Pay close attention to the 'approve-to-zero-then-set' pattern and the mention of OpenZeppelin's increaseAllowance and decreaseAllowance functions.

Let's summarize the two most critical points for you as a developer:

  1. The "Infinite Approval" Problem:

    • What it is: Many dApps, for user convenience, request approval for the maximum possible uint256 amount (type(uint256).max). This means the user only has to sign one approve transaction and can then interact with the dApp indefinitely.
    • The Risk: If that dApp's smart contract ever gets hacked or has a vulnerability, the attacker could use that infinite approval to drain all of that specific token from the user's wallet.
    • Best Practice: When possible, only approve the exact amount needed for an operation. While less convenient, it's far more secure.
  2. The Allowance Race Condition:

    • What it is: Imagine a user approves a spender for 100 tokens. They later decide to change it to 50. They submit a new approve(spender, 50) transaction. A malicious spender watching the mempool could see this, front-run the transaction, quickly call transferFrom for the original 100, and then, once the user's second transaction is mined, call transferFrom again for the new 50, stealing a total of 150 tokens.
    • The Mitigation: The standard safe way to decrease an allowance is to first set it to zero and then set it to the new, lower amount in a separate transaction (approve(spender, 0) then approve(spender, 50)). This eliminates the window of opportunity.
    • The Modern Solution: To avoid this complexity, libraries like OpenZeppelin (which we'll use in the next lesson) provide helper functions like increaseAllowance() and decreaseAllowance(). These functions safely modify the current allowance, preventing the race condition.
Test your understanding!

You are building a dApp frontend. A user has previously approved your contract to spend 1,000 of their tokens. Now, they want to perform an action that only requires 200 tokens, and for security, they want to reduce your contract's allowance from 1,000 to just 200.

Based on the race condition vulnerability, what is the safest sequence of function calls to recommend to the user's wallet?

Show answer

The safest sequence involves two separate transactions:

  1. First, the user should call approve(your_contract_address, 0).
  2. Once that transaction is confirmed, they should then call approve(your_contract_address, 200).

This "approve-to-zero-then-set" pattern ensures the original 1,000 allowance is nullified before the new 200 allowance is created, preventing any front-running attacks. If the token contract supported it, using a single decreaseAllowance(800) call would be even better.


Conclusion

You have now completed a deep dive into one of the most important design patterns in all of Ethereum development. Understanding this flow is non-negotiable for building anything that interacts with the DeFi ecosystem.

Key Takeaways:

  • The "Pull over Push" Principle: The approve/transferFrom pattern is necessary because it allows smart contracts to pull tokens from a user in a controlled, predictable way, rather than having users blindly push tokens to contracts.
  • A Two-Step Process: The token owner first grants permission with approve(), and the spender later executes the transfer with transferFrom().
  • Essential for dApps: This pattern is the backbone of decentralized exchanges, lending platforms, staking protocols, and more.
  • Security is Paramount: You must be aware of the risks of infinite approvals and race conditions. Always favor security and use established best practices and libraries.

Preview of the Next Lesson:
We've spent the last two lessons dissecting the ERC-20 blueprint. Now, it's time to build. In the next lesson, you will use the OpenZeppelin Contracts library to build a standard-compliant ERC-20 token. You'll see how this powerful library provides secure, gas-efficient, and battle-tested implementations of everything we've discussed, allowing you to create your own token with just a few lines of code.

Can't find a good explanation? Sign up and we'll make it for you

Sign up