Skip to main content

Overview

Storage instructions provide persistent and transient data access for smart contracts. The EVM supports two distinct storage scopes: Persistent Storage (SLOAD/SSTORE)
  • Contract state maintained across transactions
  • Account-specific storage per contract instance
  • Complex gas metering with refunds (EIP-2200, EIP-2929, EIP-3529)
  • Cold/warm access tracking for gas optimization
Transient Storage (TLOAD/TSTORE)
  • Transaction-scoped temporary storage (Cancun, EIP-1153)
  • Cleared at end of transaction, not persisted
  • Fixed 100 gas cost (no refunds, no access tracking)
  • Common for reentrancy guards and local state

Instructions

OpcodeMnemonicNameGasHardforkPurpose
0x54SLOADStorage Load100/2100FrontierLoad persistent storage
0x55SSTOREStorage Store5000-20000FrontierSave persistent storage
0x5cTLOADTransient Load100CancunLoad transient storage
0x5dTSTORETransient Store100CancunSave transient storage

Storage Model

Persistent Storage

Each contract account has a key-value store mapping 256-bit keys to 256-bit values:
contract MyContract {
  uint256 public count;        // Storage slot 0
  mapping(address => uint) balances;  // Slot 1+ (hash-based)
}
Storage changes are:
  • Committed to blockchain state
  • Persisted across transactions and blocks
  • Accessible to all transactions and external callers
  • Refundable when clearing slots (EIP-3529)

Transient Storage

Similar structure but transaction-scoped and cleared automatically:
// During transaction execution
TSTORE(key, value)   // Write to transient storage
TLOAD(key)           // Read from transient storage
// Transaction ends
// Transient storage cleared (not persisted)
Use cases:
  • Reentrancy protection (guard flags)
  • Call context passing (inter-contract communication)
  • Temporary work variables
  • Avoiding expensive storage refunds

Gas Costs

SLOAD (Persistent Read)

ConditionCostEIP
Warm access100 gasEIP-2929
Cold access2100 gasEIP-2929
Cold/warm tracking per transaction. First access to a slot: cold (2100). Subsequent accesses: warm (100).

SSTORE (Persistent Write)

Complex metering based on current/original values and access history:
CaseCostRefundNotes
Sentry check failNone0Requires >= 2300 gas remaining
Zero to non-zero200000Setting new value
Non-zero to different50000Modifying existing
Any to zero50004800 (EIP-3529)Clearing slot
Reset to original50004800Restoring pre-transaction value
EIP-2200 Rules (Istanbul+):
  • Sentry: SSTORE requires >= 2300 gas remaining
  • Gas varies by current vs original value
  • Refunds only 4800 per cleared slot (EIP-3529 reduced from 15000)

TLOAD/TSTORE (Transient)

Fixed 100 gas each, no gas refunds, no access tracking.

Common Patterns

Persistent Storage Patterns

State management:
// Simple counter
uint256 public count;

function increment() external {
  count++;  // SLOAD, ADD, SSTORE
}
Access list optimization:
// Multiple reads from same slot - use local var
function expensive() external {
  uint256 value = state[key];  // Cold SLOAD (2100)
  for (let i = 0; i < 10; i++) {
    // ... use value ...
    // Next reads are warm (100) if cached
  }
}

Transient Storage Patterns

Reentrancy guard:
contract ReentrancyGuard {
  // Check pattern using transient storage
  function _nonReentrant() internal {
    uint256 locked = 1;
    assembly {
      // tstore(key, locked)
      // Before call: check tload(key) == 0
      // After call: tstore(key, 0)
    }
  }
}
Call context:
// Pass data between contract calls without storage
TSTORE(contextKey, contextValue)  // Store in caller
CALL(...)                          // Callee can TLOAD(contextKey)
// Context available only during transaction

See Also