🔍 View, Pure & Payable: Function Types Explained
Understand which functions read state, modify state, or accept Ether
Your Progress
0 / 5 completed←
Previous
Introduction
🔀 Understanding Call Types
Let's dive deep into how different call types work at the EVM level. Understanding these mechanics is crucial for writing efficient contracts.
🎮 Interactive: External Call Flow Visualizer
Watch how execution flows when Contract A calls Contract B
Step 1 of 4
Contract A: Start
1
2
3
4
Contract A: Start
Contract A prepares to call Contract B
Code:
contractB.setValue(42)
Call Stack:
msg.sender: User
Contract A Context
What's happening: Execution begins in Contract A. Current context has User as msg.sender.
🎮 Interactive: Call Type Comparison
Compare different call types side-by-side
CALL vs DELEGATECALL
| Aspect | 📡 Regular CALL | 🎭 DELEGATECALL |
|---|---|---|
| msg.sender | Calling contract address | Original caller (preserved) |
| Storage Used | Called contract's storage | Calling contract's storage |
| Code Executed | Called contract's code | Called contract's code |
| Use Case | Normal external interactions | Proxy patterns, libraries |
| Gas Cost | ~2,600 base + execution | ~2,600 base + execution |
📡 External Calls Deep Dive
contract TokenVault {
IERC20 public token;
// External call to another contract
function deposit(uint amount) external {
// CALL opcode used here
bool success = token.transferFrom(msg.sender, address(this), amount);
require(success, "Transfer failed");
}
// External call via this keyword
function checkBalance() external view returns (uint) {
// Forces external call even within same contract
return this.getBalance();
}
// Will be called externally via this.getBalance()
function getBalance() public view returns (uint) {
return token.balanceOf(address(this));
}
}Line 7: External call to token contract—uses CALL opcode
Line 13: Using
this forces external call to same contractWhy this matters: External calls are expensive but necessary for cross-contract interaction
🎭 Delegatecall: Proxy Pattern
contract Proxy {
address public implementation;
uint public value;
// Delegatecall preserves Proxy's storage
fallback() external payable {
address impl = implementation;
assembly {
// Copy calldata
calldatacopy(0, 0, calldatasize())
// DELEGATECALL to implementation
let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
// Copy return data
returndatacopy(0, 0, returndatasize())
// Return or revert
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
contract Implementation {
address public implementation; // Same storage slot as Proxy!
uint public value; // Same storage slot as Proxy!
function setValue(uint _value) external {
value = _value; // Updates PROXY's storage, not Implementation's!
}
}Key Point: Implementation code runs in Proxy's storage context
Storage Layout: Must match exactly between Proxy and Implementation
msg.sender: Preserved—remains original caller, not Proxy address
Use Case: Upgradeable contracts, minimize deployment costs
🔒 Staticcall: Safe Reads
contract Oracle {
// View function—automatically uses STATICCALL when called externally
function getPrice() external view returns (uint) {
return 1500 * 1e18; // Cannot modify state
}
}
contract PriceConsumer {
Oracle oracle;
function checkPrice() external view returns (uint) {
// STATICCALL ensures oracle cannot modify state
return oracle.getPrice();
}
// This would fail—view function cannot call non-view
function badExample() external view returns (uint) {
// oracle.updatePrice(); // Compilation error!
return 0;
}
}STATICCALL: Like CALL but reverts if target tries to modify state
When: Automatically used for view/pure external function calls
Benefit: Guarantees read-only access—prevents malicious state changes
Gas: ~1,600 base cost (cheaper than CALL's 2,600)
⚡ Quick Reference
functionName()
Internal call—JUMP opcode, same context
Gas: ~24-100
contract.func()
External call—CALL opcode, new context
Gas: ~2,600+
delegatecall
Caller's storage, target's code
Gas: ~2,600+
staticcall
View/pure external calls only
Gas: ~1,600+