Skip to main content
New to EVM state? Start with Fundamentals for guided examples and Merkle Patricia Trie concepts.

Type Definition

Composite key primitive uniquely identifying storage locations in the Ethereum Virtual Machine by combining contract address with storage slot.
export type BrandedStorageKey = {
  readonly address: AddressType;
  readonly slot: bigint;
};
StorageKey combines a 20-byte contract address with a 256-bit storage slot number, enabling efficient tracking of contract state across multiple contracts in a single VM instance.

Quick Reference

    API Methods

    Constructors

    • StorageKey() - Factory function creating storage key from address and slot
    • from() - Universal constructor from various inputs

    Serialization

    Comparison & Type Guards

    • equals() - Compare two storage keys for equality
    • is() - Type guard checking if value is StorageKey

    Utilities

    Types

    export type BrandedStorageKey = {
      readonly address: AddressType;
      readonly slot: bigint;
    };
    
    Main type combining contract address with storage slot. Design rationale:
    • Each contract has 2^256 storage slots
    • Each slot stores 256-bit value
    • Slots initially zero, consume gas on first write

    Usage Patterns

    Basic Storage Operations

    import * as State from 'tevm/State';
    import * as Address from 'tevm/Address';
    
    // Create storage key
    const contractAddr = Address("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
    const key = State.StorageKey(contractAddr, 0n);
    
    // Use in storage maps
    const storage = new Map<string, bigint>();
    storage.set(State.StorageKey.toString(key), 1000000000n);
    
    // Retrieve value
    const value = storage.get(State.StorageKey.toString(key)); // 1000000000n
    

    String Serialization

    import * as State from 'tevm/State';
    
    const key = State.StorageKey(contractAddress, 42n);
    
    // Convert to string for map keys
    const keyStr = State.StorageKey.toString(key);
    // "0x742d35cc6634c0532925a3b844bc9e7595f51e3e:42"
    
    // Parse from string
    const parsed = State.StorageKey(keyStr);
    // { address: AddressType(...), slot: 42n }
    
    // Round-trip conversion
    State.StorageKey.equals(key, parsed); // true
    

    Storage Slot Computation

    import * as State from 'tevm/State';
    import * as Address from 'tevm/Address';
    import { Keccak256 } from 'tevm/crypto';
    
    // USDC contract
    const usdcAddress = Address("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
    
    // Storage slot 0: total supply
    const totalSupplyKey = State.StorageKey(usdcAddress, 0n);
    
    // Mapping storage: balanceOf[userAddress]
    // Slot = keccak256(abi.encode(userAddress, balanceSlot))
    const userAddress = Address("0x742d35Cc6634C0532925a3b844Bc9e7595f51e3e");
    const balanceSlot = 1n;
    
    // Compute mapping slot (Solidity storage layout)
    const mappingSlotBytes = Bytes64();
    mappingSlotBytes.set(userAddress, 0);          // First 32 bytes (padded address)
    mappingSlotBytes.set(encodeBigInt(balanceSlot, 32), 32); // Last 32 bytes
    
    const computedSlot = BigInt(Hex.fromBytes(
      Keccak256.hash(mappingSlotBytes)
    ).toString('hex'));
    
    const userBalanceKey = State.StorageKey(usdcAddress, computedSlot);
    

    Multi-Contract State

    import * as State from 'tevm/State';
    
    // Track state across multiple contracts
    const stateDb = new Map<string, bigint>();
    
    // USDC total supply
    const usdcKey = State.StorageKey(usdcAddress, 0n);
    stateDb.set(State.StorageKey.toString(usdcKey), 1000000000n);
    
    // DAI total supply
    const daiKey = State.StorageKey(daiAddress, 0n);
    stateDb.set(State.StorageKey.toString(daiKey), 5000000000n);
    
    // Query by contract
    for (const [keyStr, value] of stateDb.entries()) {
      const key = State.StorageKey(keyStr);
      if (Address.equals(key.address, usdcAddress)) {
        console.log(`USDC slot ${key.slot}: ${value}`);
      }
    }
    

    Type Guards

    import * as State from 'tevm/State';
    
    function processStorage(key: unknown) {
      if (State.StorageKey.is(key)) {
        // TypeScript knows key is BrandedStorageKey
        console.log(`Address: ${Address.toHex(key.address)}`);
        console.log(`Slot: ${key.slot}`);
      }
    }
    

    Tree-Shaking

    Import only what you need for optimal bundle size:
    // Import specific functions (tree-shakeable)
    import { StorageKey, toString, fromString } from 'tevm/State';
    
    const key = StorageKey(contractAddress, 0n);
    const keyStr = toString(key);
    const parsed = fromString(keyStr);
    
    // Only these 3 functions included in bundle
    

    Core Documentation

    API Methods

    • Address - Contract address type
    • Uint - 256-bit unsigned integers for slot values
    • Keccak256 - Keccak256 hashing for state roots

    Specification