Consider the following simplified Solidity code snippet for an ERC-20 token:
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
function approve(address spender, uint amount) public returns (bool) {
allowed[msg.sender][spender] = amount;
return true;
}
function transferFrom(address from, address to, uint amount) public returns (bool) {
require(balances[from] >= amount, "Insufficient balance");
require(allowed[from][msg.sender] >= amount, "Allowance exceeded");
balances[from] -= amount;
balances[to] += amount;
allowed[from][msg.sender] -= amount;
return true;
}
// Initial state:
balances["Alice"] = 100;
// Sequence:
approve("Bob", 50) called by Alice
transferFrom("Alice", "Charlie", 30) called by Bob
transferFrom("Alice", "Dave", 25) called by BobWhat happens at the last transferFrom call?
Remember that allowance decreases after each transferFrom call.
After Alice approves Bob for 50 tokens, Bob transfers 30 tokens to Charlie, reducing allowance to 20. The next transferFrom tries to transfer 25 tokens, which exceeds the remaining allowance, so it fails with "Allowance exceeded".
In ERC-20 tokens, why do we use the approve and transferFrom functions instead of just allowing direct transfers?
Think about how a decentralized exchange or contract might move tokens for a user.
The approve and transferFrom pattern allows a user to give permission to another address (like a smart contract or exchange) to spend tokens on their behalf up to a certain amount, enabling delegated transfers.
Review this Solidity approve function snippet:
function approve(address spender, uint amount) public returns (bool) {
require(amount > 0, "Amount must be positive");
allowed[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}What is the main issue with this implementation?
Think about how users revoke or change allowances safely.
Requiring amount > 0 prevents setting allowance to zero, which is a common pattern to safely reset or revoke approvals to avoid race conditions.
Choose the correct Solidity code snippet that properly checks allowance before transferring tokens in transferFrom:
The spender should be allowed to spend exactly or more than the requested amount.
The allowance must be at least the amount to transfer, so the check uses >=. Using > would block transfers equal to allowance, == is too strict, <= is incorrect logic.
Given the following initial balances and approvals:
balances = {"Alice": 100, "Bob": 50, "Charlie": 0}
approvals:
Alice approved Bob for 60 tokens
Bob approved Charlie for 30 tokens
Sequence of calls:
- Bob calls transferFrom("Alice", "Bob", 40)
- Charlie calls transferFrom("Bob", "Charlie", 20)
- Bob calls transferFrom("Alice", "Charlie", 25)
What are the final balances of Alice, Bob, and Charlie?
Track each transferFrom call carefully, updating balances and allowances.
Step 1: Bob transfers 40 from Alice to Bob (Alice: 60, Bob: 90, Alice-Bob allowance now 20)
Step 2: Charlie transfers 20 from Bob to Charlie (Bob: 70, Charlie: 20)
Step 3: Bob tries to transfer 25 from Alice to Charlie, but remaining Alice-Bob allowance 20 < 25, fails with "Allowance exceeded".
Final balances: Alice 60, Bob 70, Charlie 20.