This page is a placeholder. All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.
Overview
Opcode: 0x30
Introduced: Frontier (EVM genesis)
ADDRESS pushes the address of the currently executing account onto the stack. This is the address of the contract whose code is being executed, not the address of the contract that initiated the call chain.
Specification
Stack Input:
Stack Output:
address (uint160 as uint256)
Gas Cost: 2 (GasQuickStep)
Operation:
stack.push(execution_context.address)
Behavior
ADDRESS provides access to the address of the contract currently executing. In the context of DELEGATECALL, this returns the address of the contract being called into (the caller’s address), not the implementation contract.
Key characteristics:
- Returns the address where code is executing
- Value is a 160-bit address stored as uint256 (20 bytes right-padded)
- Does not change with CALL but changes with DELEGATECALL
- Always available (cannot fail)
Examples
Basic Usage
import { address } from '@tevm/voltaire/evm/context';
import { createFrame } from '@tevm/voltaire/evm/Frame';
import * as Address from '@tevm/voltaire/Address';
// Get current contract address
const contractAddr = Address('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb');
const frame = createFrame({
address: contractAddr,
stack: []
});
const err = address(frame);
console.log(frame.stack.length); // 1
console.log(frame.stack[0]); // 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbn
Contract Self-Reference
contract Example {
address public self;
constructor() {
// Store contract's own address
assembly {
let addr := address()
sstore(0, addr)
}
}
function getAddress() public view returns (address) {
return address(this); // Compiler uses ADDRESS opcode
}
}
CALL vs DELEGATECALL
contract Implementation {
function whoAmI() public view returns (address) {
return address(this);
}
}
contract Proxy {
Implementation impl;
function regularCall() public view returns (address) {
// Returns Implementation's address
return impl.whoAmI();
}
function delegateCall() public returns (address) {
// Returns Proxy's address (context is preserved)
(bool success, bytes memory data) = address(impl).delegatecall(
abi.encodeWithSignature("whoAmI()")
);
require(success);
return abi.decode(data, (address));
}
}
Gas Cost
Cost: 2 gas (GasQuickStep)
ADDRESS is one of the cheapest operations, sharing the same cost tier with:
- ORIGIN (0x32)
- CALLER (0x33)
- CALLVALUE (0x34)
- CALLDATASIZE (0x36)
- CODESIZE (0x38)
- GASPRICE (0x3a)
- RETURNDATASIZE (0x3d)
Comparison:
- Environment context (ADDRESS, CALLER, ORIGIN): 2 gas
- Data loading (CALLDATALOAD): 3 gas
- External account access (BALANCE, EXTCODESIZE): 700+ gas
Common Usage
Proxy Pattern Identification
contract Proxy {
address public implementation;
fallback() external payable {
address impl = implementation;
assembly {
// Load calldata
calldatacopy(0, 0, calldatasize())
// Delegate to implementation
let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
// In implementation: address() returns Proxy's address
// Return data
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
Self-Destruct Recipient
contract SelfDestructible {
function destroy() public {
// Send remaining balance to this contract's address
selfdestruct(payable(address(this)));
}
}
Token Address Validation
contract TokenSwap {
function swap(address token, uint256 amount) public {
// Ensure not swapping with the swap contract itself
require(token != address(this), "Cannot swap with self");
// ...
}
}
Ether Reception Check
contract PaymentReceiver {
receive() external payable {
// Log payment to this contract
emit PaymentReceived(msg.sender, address(this), msg.value);
}
}
Security
ADDRESS vs CALLER vs ORIGIN
Critical distinction:
// ADDRESS (0x30) - Contract being executed
address(this)
// CALLER (0x33) - Immediate caller
msg.sender
// ORIGIN (0x32) - Transaction originator
tx.origin
Example call chain:
User (0xAAA) → Contract A (0xBBB) → Contract B (0xCCC)
In Contract B:
- address(this) = 0xCCC (Contract B's address)
- msg.sender = 0xBBB (Contract A called us)
- tx.origin = 0xAAA (User started the transaction)
DELEGATECALL Context Preservation
contract Vulnerable {
address public owner;
function upgrade(address newImpl) public {
// DANGEROUS: In delegatecall, address(this) is caller's address
// An attacker can delegatecall to malicious code
require(msg.sender == owner);
(bool success,) = newImpl.delegatecall(msg.data);
require(success);
}
}
Safe Patterns
contract Safe {
// Store contract's own address for validation
address immutable self = address(this);
function initialize() public {
// Prevent initialization in delegatecall context
require(address(this) == self, "Cannot delegatecall initialize");
// ...
}
}
Implementation
import { consumeGas } from "../Frame/consumeGas.js";
import { pushStack } from "../Frame/pushStack.js";
import { toU256 } from "../../primitives/Address/AddressType/toU256.js";
/**
* ADDRESS opcode (0x30) - Get address of currently executing account
*
* Stack: [] => [address]
* Gas: 2 (GasQuickStep)
*/
export function address(frame: FrameType): EvmError | null {
const gasErr = consumeGas(frame, 2n);
if (gasErr) return gasErr;
const addrU256 = toU256(frame.address);
const pushErr = pushStack(frame, addrU256);
if (pushErr) return pushErr;
frame.pc += 1;
return null;
}
Edge Cases
Maximum Address Value
// Address is 160 bits, stored as uint256
const maxAddr = (1n << 160n) - 1n;
const frame = createFrame({ address: maxAddr });
address(frame);
console.log(frame.stack[0]); // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFn
Zero Address
// Zero address is valid
const frame = createFrame({ address: 0x0n });
address(frame);
console.log(frame.stack[0]); // 0x0n
Stack Overflow
// Stack at maximum capacity
const frame = createFrame({
address: 0x123n,
stack: new Array(1024).fill(0n)
});
const err = address(frame);
console.log(err); // { type: "StackOverflow" }
Out of Gas
// Insufficient gas
const frame = createFrame({
address: 0x123n,
gasRemaining: 1n
});
const err = address(frame);
console.log(err); // { type: "OutOfGas" }
References