Starknet Substreams Type Glossary

Block

pub struct Block {
    pub block_hash: Vec<u8>,
    pub parent_hash: Vec<u8>,
    pub block_number: u64,
    pub new_root: Vec<u8>,
    pub timestamp: u64,
    pub sequencer_address: Vec<u8>,
    pub l1_gas_price: Option<ResourcePrice>,
    pub l1_data_gas_price: Option<ResourcePrice>,
    pub l1_da_mode: i32,
    pub starknet_version: String,
    pub transactions: Vec<TransactionWithReceipt>,
    pub state_update: Option<StateUpdate>,
}

L1DaMode

pub enum L1DaMode {
    Unspecified = 0,    // Default mode when not specified
    Calldata = 1,       // Data posted as calldata on L1 (traditional method)
    Blob = 2,           // Data posted as blob on L1 (EIP-4844)
}

Fields

block_hash

  • Description: Unique identifier of the block
  • Type: Vec<u8>
  • Example: Hash bytes representing the block’s identity

parent_hash

  • Description: Hash of the previous block in the chain
  • Type: Vec<u8>
  • Example: Hash bytes linking to the parent block

block_number

  • Description: Sequential number of this block
  • Type: u64
  • Example: 1234567

new_root

  • Description: New global state root after block execution
  • Type: Vec<u8>
  • Example: State root hash bytes

timestamp

  • Description: Unix timestamp when block was created
  • Type: u64
  • Example: 1678901234

sequencer_address

  • Description: Starknet address of the sequencer that produced the block
  • Type: Vec<u8>
  • Example: Sequencer’s address bytes

l1_gas_price, l1_data_gas_price

  • Description: Gas pricing information for L1 operations
  • Type: Option<ResourcePrice>
  • Example: Current gas prices in FRI and Wei

l1_da_mode

  • Description: Data availability mode (Calldata or Blob)
  • Type: i32 (enum L1DaMode)
  • Values:
    • 0: Unknown
    • 1: Calldata
    • 2: Blob

starknet_version

  • Description: Protocol version string
  • Type: String
  • Example: "0.11.0"

transactions

  • Description: List of transactions with their receipts
  • Type: Vec<TransactionWithReceipt>

state_update

  • Description: Changes to the global state in this block
  • Type: Option<StateUpdate>

Important Notes

  • Block structure represents the fundamental unit of the Starknet blockchain
  • Contains both transaction data and state changes
  • Links to Ethereum L1 through gas prices and data availability modes
  • Maintains version information for protocol compatibility
  • Includes complete execution results through transaction receipts

Example Use Case

fn analyze_block(block: &Block) -> BlockAnalysis {
    BlockAnalysis {
        timestamp: block.timestamp,
        transaction_count: block.transactions.len(),
        version: block.starknet_version.clone(),
        da_mode: match block.l1_da_mode {
            1 => "Calldata",
            2 => "Blob",
            _ => "Unknown"
        }.to_string(),
        has_state_update: block.state_update.is_some()
    }
}

ResourcePrice

pub struct ResourcePrice {
    pub price_in_fri: Vec<u8>,
    pub price_in_wei: Vec<u8>,
}

Fields

price_in_fri

  • Description: Price in Starknet’s native token (FRI - Fee Rate Index)
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 0, 0, 100] (representing 100 FRI)
  • Note: Stored as big-endian bytes representing a large integer

price_in_wei

  • Description: Price in Ethereum’s smallest unit (Wei)
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 0, 1, 0] (representing 256 Wei)
  • Note: Stored as big-endian bytes representing a large integer

Example Use Cases

fn calculate_transaction_costs(
    resource_price: &ResourcePrice,
    gas_used: u64
) -> TransactionCosts {
    // Convert bytes to numeric values
    let fri_price = BigInt::from_bytes_be(Sign::Plus, &resource_price.price_in_fri);
    let wei_price = BigInt::from_bytes_be(Sign::Plus, &resource_price.price_in_wei);
    
    TransactionCosts {
        cost_in_fri: fri_price * gas_used,
        cost_in_wei: wei_price * gas_used,
    }
}
 
// Example of price comparison
fn is_price_favorable(
    current: &ResourcePrice,
    threshold: &ResourcePrice
) -> bool {
    let current_wei = BigInt::from_bytes_be(Sign::Plus, &current.price_in_wei);
    let threshold_wei = BigInt::from_bytes_be(Sign::Plus, &threshold.price_in_wei);
    
    current_wei <= threshold_wei
}

Important Notes

  • Used for both L1 gas prices and L1 data gas prices in blocks
  • Prices are represented as byte arrays to handle large numbers
  • Dual pricing system reflects Starknet’s L2 nature:
    • FRI pricing for Starknet’s internal economy
    • Wei pricing for L1 interaction costs
  • Common scenarios:
    • Gas cost estimation
    • Fee calculation
    • Price monitoring
    • Transaction cost optimization

Common Patterns

// Example of typical resource price structure
let typical_price = ResourcePrice {
    price_in_fri: vec![0, 0, 0, 0, 0, 0, 0, 100],  // 100 FRI
    price_in_wei: vec![0, 0, 0, 0, 0, 0, 1, 0],    // 256 Wei
};
 
// Example of high gas price scenario
let high_price = ResourcePrice {
    price_in_fri: vec![0, 0, 0, 0, 0, 1, 0, 0],    // Higher FRI amount
    price_in_wei: vec![0, 0, 0, 0, 1, 0, 0, 0],    // Higher Wei amount
};

TransactionWithReceipt

pub struct TransactionWithReceipt {
    pub receipt: Option<TransactionReceipt>,
    pub transaction: Option<transaction_with_receipt::Transaction>,
}
 
pub enum Transaction {
    InvokeTransactionV0(InvokeTransactionV0),
    InvokeTransactionV1(InvokeTransactionV1),
    InvokeTransactionV3(InvokeTransactionV3),
    L1HandlerTransaction(L1HandlerTransaction),
    DeclareTransactionV0(DeclareTransactionV0),
    DeclareTransactionV1(DeclareTransactionV1),
    DeclareTransactionV2(DeclareTransactionV2),
    DeclareTransactionV3(DeclareTransactionV3),
    DeployTransactionV0(DeployTransactionV0),
    DeployAccountTransactionV1(DeployAccountTransactionV1),
    DeployAccountTransactionV3(DeployAccountTransactionV3),
}

Fields

receipt

  • Description: Execution receipt containing the transaction outcome
  • Type: Option<TransactionReceipt>
  • Example: Contains execution status, events, messages, etc.

transaction

  • Description: The actual transaction data in one of multiple possible formats
  • Type: Option<Transaction> (enum)
  • Variants:
    • InvokeTransactionV0/V1/V3: Contract function calls
    • L1HandlerTransaction: Processes messages from Ethereum L1
    • DeclareTransactionV0/V1/V2/V3: Declares new contract classes
    • DeployTransactionV0: Deploys new contract instances
    • DeployAccountTransactionV1/V3: Creates new account contracts

Example Use Cases

fn process_transaction(tx_with_receipt: &TransactionWithReceipt) -> TransactionAnalysis {
    let tx_type = match &tx_with_receipt.transaction {
        Some(tx) => match tx {
            Transaction::InvokeTransactionV0(_) => "Invoke V0",
            Transaction::InvokeTransactionV1(_) => "Invoke V1",
            Transaction::InvokeTransactionV3(_) => "Invoke V3",
            Transaction::L1HandlerTransaction(_) => "L1 Handler",
            Transaction::DeclareTransactionV0(_) => "Declare V0",
            Transaction::DeclareTransactionV1(_) => "Declare V1",
            Transaction::DeclareTransactionV2(_) => "Declare V2",
            Transaction::DeclareTransactionV3(_) => "Declare V3",
            Transaction::DeployTransactionV0(_) => "Deploy V0",
            Transaction::DeployAccountTransactionV1(_) => "Deploy Account V1",
            Transaction::DeployAccountTransactionV3(_) => "Deploy Account V3",
        },
        None => "Unknown",
    };
 
    let status = tx_with_receipt.receipt.as_ref().map(|r| r.execution_status);
    
    TransactionAnalysis {
        transaction_type: tx_type.to_string(),
        success: matches!(status, Some(1)), // ExecutionStatus::Success
        has_events: tx_with_receipt.receipt
            .as_ref()
            .map(|r| !r.events.is_empty())
            .unwrap_or(false)
    }
}

Important Notes

  • Combines transaction data with its execution receipt
  • Supports multiple transaction versions and types
  • Key transaction types:
    • Invoke: Function calls to existing contracts
    • Declare: Adding new contract classes
    • Deploy: Creating contract instances
    • L1Handler: Processing L1→L2 messages
    • DeployAccount: Creating account contracts

Common Patterns

// Example of an invoke transaction with receipt
let invoke_tx = TransactionWithReceipt {
    transaction: Some(Transaction::InvokeTransactionV3(InvokeTransactionV3 {
        // Invoke transaction details
    })),
    receipt: Some(TransactionReceipt {
        execution_status: 1, // Success
        events: vec![/* ... */],
        // Other receipt fields
    })
};
 
// Example of a declare transaction with receipt
let declare_tx = TransactionWithReceipt {
    transaction: Some(Transaction::DeclareTransactionV2(DeclareTransactionV2 {
        // Contract declaration details
    })),
    receipt: Some(TransactionReceipt {
        execution_status: 1, // Success
        // Other receipt fields
    })
};

TransactionReceipt

pub struct TransactionReceipt {
    pub transaction_hash: Vec<u8>,
    pub actual_fee: Option<ActualFee>,
    pub execution_status: i32,
    pub revert_reason: String,
    pub r#type: i32,
    pub message_hash: String,
    pub messages_sent: Vec<MessagesSent>,
    pub events: Vec<Event>,
    pub execution_resources: Option<ExecutionResources>,
    pub contract_address: Vec<u8>,
}

ExecutionStatus

pub enum ExecutionStatus {
    Unspecified = 0,    // Default/unknown execution status
    Succeeded = 1,      // Transaction executed successfully
    Reverted = 2,       // Transaction execution was reverted
}

TransactionType

pub enum TransactionType {
    Unspecified = 0,            // Default/unknown transaction type
    Declare = 1,                // Contract class declaration
    Deploy = 2,                 // Contract deployment
    DeployAccount = 3,          // Account contract deployment
    Invoke = 4,                 // Contract function invocation
    L1Handler = 5,              // L1 to L2 message handler
    Initialize = 6,             // Contract initialization
}

Fields

transaction_hash

  • Description: Unique identifier hash of the transaction
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of transaction hash */]

actual_fee

  • Description: The fee charged by the sequencer for transaction execution
  • Type: Option<ActualFee>
  • Example: Contains amount and unit of fee charged

execution_status

  • Description: Status of transaction execution
  • Type: i32 (enum ExecutionStatus)
  • Values:
    • 0: Unknown
    • 1: Success
    • 2: Reverted

revert_reason

  • Description: Error message if transaction was reverted
  • Type: String
  • Example: "Insufficient balance"

type

  • Description: Type of transaction
  • Type: i32 (enum TransactionType)
  • Values:
    • 0: Unknown
    • 1: Invoke
    • 2: Declare
    • 3: Deploy
    • 4: DeployAccount
    • 5: L1Handler

message_hash

  • Description: Hash of messages sent to L1
  • Type: String
  • Example: Hash string of L1 messages

messages_sent

  • Description: List of messages sent to L1
  • Type: Vec<MessagesSent>
  • Example: L2→L1 messages for cross-layer communication

events

  • Description: Events emitted during transaction execution
  • Type: Vec<Event>
  • Example: Contract events, state changes, etc.

execution_resources

  • Description: Resources consumed during execution
  • Type: Option<ExecutionResources>
  • Example: Steps, memory usage, builtin instance counts

contract_address

  • Description: Address of deployed/interacted contract
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

Example Use Cases

fn analyze_receipt(receipt: &TransactionReceipt) -> ReceiptAnalysis {
    ReceiptAnalysis {
        success: receipt.execution_status == 1,
        has_messages: !receipt.messages_sent.is_empty(),
        event_count: receipt.events.len(),
        fee_info: receipt.actual_fee.as_ref().map(|fee| {
            format!("{} {}", fee.amount, fee.unit)
        }),
        error: if receipt.execution_status == 2 {
            Some(receipt.revert_reason.clone())
        } else {
            None
        }
    }
}
 
// Example of processing L2->L1 messages
fn process_l1_messages(receipt: &TransactionReceipt) -> Vec<L1Message> {
    receipt.messages_sent.iter().map(|msg| {
        L1Message {
            from: msg.from_address.clone(),
            to: msg.to_address.clone(),
            payload: msg.payload.clone()
        }
    }).collect()
}

Important Notes

  • Key component for transaction result analysis
  • Contains all execution outcomes:
    • Success/failure status
    • Resource usage
    • Cross-layer messages
    • Emitted events
    • Fee information

Common Patterns

// Successful transaction receipt
let success_receipt = TransactionReceipt {
    transaction_hash: vec![/* hash */],
    execution_status: 1, // Success
    actual_fee: Some(ActualFee {
        amount: vec![/* amount */],
        unit: "WEI".to_string()
    }),
    events: vec![/* events */],
    messages_sent: vec![],
    revert_reason: "".to_string(),
    // ... other fields
};
 
// Failed transaction receipt
let failed_receipt = TransactionReceipt {
    transaction_hash: vec![/* hash */],
    execution_status: 2, // Reverted
    revert_reason: "Insufficient funds".to_string(),
    actual_fee: Some(ActualFee {
        amount: vec![/* amount */],
        unit: "WEI".to_string()
    }),
    // ... other fields
};

MessagesSent

pub struct MessagesSent {
    pub from_address: Vec<u8>,
    pub to_address: Vec<u8>,
    pub payload: Vec<Vec<u8>>,
}

Fields

from_address

  • Description: The address of the L2 contract sending the message
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of Starknet contract address */]

to_address

  • Description: The target L1 address the message is sent to
  • Type: Vec<u8>
  • Example: vec![/* 20 bytes of Ethereum address */]

payload

  • Description: The payload data of the message
  • Type: Vec<Vec<u8>>
  • Example: Vector of byte arrays containing function selector and parameters

Example Use Cases

fn process_l2_to_l1_message(message: &MessagesSent) -> MessageAnalysis {
    // Convert addresses to hex strings
    let from_hex = format!("0x{}", hex::encode(&message.from_address));
    let to_hex = format!("0x{}", hex::encode(&message.to_address));
    
    // Analyze payload
    let payload_analysis = if !message.payload.is_empty() {
        analyze_message_payload(&message.payload)
    } else {
        PayloadType::Empty
    };
    
    MessageAnalysis {
        l2_sender: from_hex,
        l1_recipient: to_hex,
        payload_type: payload_analysis,
        payload_size: message.payload.len()
    }
}
 
// Example of common message patterns
fn analyze_message_payload(payload: &[Vec<u8>]) -> PayloadType {
    if let Some(first_word) = payload.first() {
        match first_word.as_slice() {
            // Common function selectors
            [0x12, 0x34, 0x56, 0x78, ..] => PayloadType::TokenTransfer,
            [0xa9, 0x05, 0x9c, 0xbb, ..] => PayloadType::TokenApproval,
            _ => PayloadType::Unknown
        }
    } else {
        PayloadType::Empty
    }
}

Common Message Patterns

// Token bridge message example
let token_bridge_message = MessagesSent {
    from_address: vec![/* L2 bridge contract address */],
    to_address: vec![/* L1 bridge contract address */],
    payload: vec![
        vec![0x12, 0x34, 0x56, 0x78],  // transfer function selector
        vec![/* token amount */],
        vec![/* recipient address */]
    ]
};
 
// State verification message
let verification_message = MessagesSent {
    from_address: vec![/* L2 verifier contract */],
    to_address: vec![/* L1 verifier contract */],
    payload: vec![
        vec![/* state root */],
        vec![/* block number */],
        vec![/* timestamp */]
    ]
};

Important Notes

  • Key component for L2→L1 communication

  • Common use cases:

    • Token bridging
    • State verification
    • Cross-layer governance
    • Data availability proofs
  • Security considerations:

    • Messages must be verified on L1
    • Payload format must match L1 expectations
    • Address formats differ between L1 and L2

Event

pub struct Event {
    pub from_address: Vec<u8>,
    pub keys: Vec<Vec<u8>>,
    pub data: Vec<Vec<u8>>,
}

Fields

from_address

  • Description: The address of the contract that emitted the event
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

keys

  • Description: Indexed event parameters used for efficient filtering
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* event selector */],
        vec![/* indexed param 1 */],
        vec![/* indexed param 2 */]
    ]

data

  • Description: Non-indexed event parameters containing additional data
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* amount */],
        vec![/* timestamp */],
        vec![/* other data */]
    ]

Example Use Cases

fn process_event(event: &Event) -> EventAnalysis {
    // Convert event selector (first key) to identify event type
    let event_type = if let Some(selector) = event.keys.first() {
        match selector.as_slice() {
            // Common event selectors
            [0x12, 0x34, 0x56, 0x78, ..] => "Transfer",
            [0xa9, 0x05, 0x9c, 0xbb, ..] => "Approval",
            [0xdc, 0x13, 0x45, 0x67, ..] => "Swap",
            _ => "Unknown"
        }
    } else {
        "Unknown"
    };
 
    EventAnalysis {
        emitter: format!("0x{}", hex::encode(&event.from_address)),
        event_type: event_type.to_string(),
        indexed_params: event.keys.len() - 1, // Subtract selector
        data_params: event.data.len()
    }
}
 
// Example of processing transfer events
fn process_transfer_event(event: &Event) -> Option<TransferDetails> {
    if event.keys.len() < 3 || event.data.is_empty() {
        return None;
    }
 
    Some(TransferDetails {
        from: event.keys[1].clone(),  // First indexed param
        to: event.keys[2].clone(),    // Second indexed param
        amount: event.data[0].clone() // First data param
    })
}

Common Event Patterns

// Transfer event example
let transfer_event = Event {
    from_address: vec![/* token contract address */],
    keys: vec![
        vec![0x12, 0x34, 0x56, 0x78],  // Transfer event selector
        vec![/* from address */],       // Indexed
        vec![/* to address */]          // Indexed
    ],
    data: vec![
        vec![/* amount */]              // Non-indexed
    ]
};
 
// Swap event example
let swap_event = Event {
    from_address: vec![/* DEX contract address */],
    keys: vec![
        vec![0xdc, 0x13, 0x45, 0x67],  // Swap event selector
        vec![/* token_in */],           // Indexed
        vec![/* token_out */]           // Indexed
    ],
    data: vec![
        vec![/* amount_in */],          // Non-indexed
        vec![/* amount_out */],         // Non-indexed
        vec![/* recipient */]           // Non-indexed
    ]
};

Important Notes

  • Events are crucial for:

    • Off-chain indexing
    • State tracking
    • UI updates
    • Analytics
  • Key characteristics:

    • Indexed parameters (keys) for efficient filtering
    • Non-indexed parameters (data) for additional information
    • Emitted by specific contracts
    • Immutable once emitted

ExecutionResources

pub struct ExecutionResources {
    pub steps: u64,
    pub memory_holes: u64,
    pub range_check_builtin_applications: u64,
    pub pedersen_builtin_applications: u64,
    pub poseidon_builtin_applications: u64,
    pub ec_op_builtin_applications: u64,
    pub ecdsa_builtin_applications: u64,
    pub bitwise_builtin_applications: u64,
    pub keccak_builtin_applications: u64,
    pub segment_arena_builtin: u64,
}

Fields

steps

  • Description: Number of Cairo VM steps executed
  • Type: u64
  • Example: 1500 (represents computational complexity)

memory_holes

  • Description: Number of unused memory cells
  • Type: u64
  • Example: 32 (memory optimization metric)

range_check_builtin_applications

  • Description: Number of range check operations
  • Type: u64
  • Example: 50 (number of range validations)

pedersen_builtin_applications

  • Description: Number of Pedersen hash computations
  • Type: u64
  • Example: 10 (hash operations count)

poseidon_builtin_applications

  • Description: Number of Poseidon hash operations
  • Type: u64
  • Example: 5 (alternative hash operations)

ec_op_builtin_applications

  • Description: Number of elliptic curve operations
  • Type: u64
  • Example: 2 (cryptographic operations)

ecdsa_builtin_applications

  • Description: Number of ECDSA signature verifications
  • Type: u64
  • Example: 1 (signature checks)

bitwise_builtin_applications

  • Description: Number of bitwise operations
  • Type: u64
  • Example: 20 (bit manipulation operations)

keccak_builtin_applications

  • Description: Number of Keccak hash computations
  • Type: u64
  • Example: 3 (Ethereum-compatible hashing)

segment_arena_builtin

  • Description: Memory segment allocations
  • Type: u64
  • Example: 15 (memory management operations)

Example Use Cases

fn analyze_execution_cost(resources: &ExecutionResources) -> ResourceAnalysis {
    ResourceAnalysis {
        total_steps: resources.steps,
        crypto_operations: resources.pedersen_builtin_applications 
            + resources.poseidon_builtin_applications 
            + resources.ec_op_builtin_applications 
            + resources.ecdsa_builtin_applications,
        hash_operations: resources.pedersen_builtin_applications 
            + resources.poseidon_builtin_applications 
            + resources.keccak_builtin_applications,
        memory_efficiency: calculate_memory_efficiency(
            resources.steps,
            resources.memory_holes
        )
    }
}
 
// Example of resource usage estimation
fn estimate_gas_cost(resources: &ExecutionResources) -> u64 {
    let base_cost = resources.steps * STEP_COST;
    let builtin_cost = 
        resources.pedersen_builtin_applications * PEDERSEN_COST +
        resources.ecdsa_builtin_applications * ECDSA_COST +
        resources.bitwise_builtin_applications * BITWISE_COST;
    
    base_cost + builtin_cost
}

Common Resource Patterns

// Simple transfer transaction resources
let transfer_resources = ExecutionResources {
    steps: 1000,
    memory_holes: 10,
    range_check_builtin_applications: 20,
    pedersen_builtin_applications: 2,
    poseidon_builtin_applications: 0,
    ec_op_builtin_applications: 0,
    ecdsa_builtin_applications: 1,
    bitwise_builtin_applications: 0,
    keccak_builtin_applications: 0,
    segment_arena_builtin: 5,
};
 
// Complex DeFi transaction resources
let defi_resources = ExecutionResources {
    steps: 5000,
    memory_holes: 50,
    range_check_builtin_applications: 100,
    pedersen_builtin_applications: 10,
    poseidon_builtin_applications: 5,
    ec_op_builtin_applications: 2,
    ecdsa_builtin_applications: 1,
    bitwise_builtin_applications: 30,
    keccak_builtin_applications: 3,
    segment_arena_builtin: 25,
};

Important Notes

  • Used for:

    • Gas cost calculation
    • Performance optimization
    • Resource usage tracking
    • Transaction fee estimation
  • Key aspects:

    • Different builtin costs
    • Memory efficiency metrics
    • Computational complexity
    • Cryptographic operation tracking

InvokeTransactionV0

pub struct InvokeTransactionV0 {
    pub max_fee: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub contract_address: Vec<u8>,
    pub entry_point_selector: Vec<u8>,
    pub calldata: Vec<Vec<u8>>,
}

Fields

max_fee

  • Description: Maximum fee the sender is willing to pay for the transaction
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents fee in wei)

signature

  • Description: List of signature elements proving transaction authorization
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* r value */],
        vec![/* s value */]
    ]

contract_address

  • Description: Address of the contract to invoke
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

entry_point_selector

  • Description: The selector of the function to call
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of function selector */]

calldata

  • Description: Arguments passed to the function
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* arg1 */],
        vec![/* arg2 */]
    ]

Example Use Cases

fn process_invoke_v0(tx: &InvokeTransactionV0) -> InvokeAnalysis {
    // Convert function selector to identify the function
    let function_name = match tx.entry_point_selector.as_slice() {
        [0x12, 0x34, 0x56, 0x78, ..] => "transfer",
        [0xa9, 0x05, 0x9c, 0xbb, ..] => "approve",
        _ => "unknown"
    };
 
    InvokeAnalysis {
        contract: format!("0x{}", hex::encode(&tx.contract_address)),
        function: function_name.to_string(),
        argument_count: tx.calldata.len(),
        max_fee: format!("0x{}", hex::encode(&tx.max_fee)),
        signed: !tx.signature.is_empty()
    }
}

Common Transaction Patterns

// ERC20 transfer transaction
let transfer_tx = InvokeTransactionV0 {
    max_fee: vec![0, 0, 0, 0, 0, 1, 0, 0],  // 256 wei
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    contract_address: vec![/* ERC20 contract address */],
    entry_point_selector: vec![0x12, 0x34, 0x56, 0x78],  // transfer
    calldata: vec![
        vec![/* recipient address */],
        vec![/* amount */]
    ]
};
 
// Contract interaction transaction
let interaction_tx = InvokeTransactionV0 {
    max_fee: vec![0, 0, 0, 0, 0, 2, 0, 0],  // 512 wei
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    contract_address: vec![/* contract address */],
    entry_point_selector: vec![/* custom function selector */],
    calldata: vec![
        vec![/* parameter 1 */],
        vec![/* parameter 2 */],
        vec![/* parameter 3 */]
    ]
};

Important Notes

  • Legacy transaction format (V0)
  • Key differences from later versions:
    • Single contract call only
    • Direct function selector specification
    • Simpler fee model
    • Basic signature scheme

InvokeTransactionV1

pub struct InvokeTransactionV1 {
    pub max_fee: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub sender_address: Vec<u8>,
    pub calldata: Vec<Vec<u8>>,
}

Fields

max_fee

  • Description: Maximum fee the sender is willing to pay for the transaction
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents fee in wei)

signature

  • Description: List of signature elements for transaction authorization
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* r value */],
        vec![/* s value */]
    ]

nonce

  • Description: Account nonce to prevent transaction replay
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1] (sequential transaction number)

sender_address

  • Description: Address of the account initiating the transaction
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account address */]

calldata

  • Description: Encoded function calls and parameters
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* contract address */],
        vec![/* function selector */],
        vec![/* parameters... */]
    ]

Example Use Cases

fn process_invoke_v1(tx: &InvokeTransactionV1) -> InvokeV1Analysis {
    // Parse calldata to extract calls
    let calls = parse_calldata(&tx.calldata);
    
    InvokeV1Analysis {
        sender: format!("0x{}", hex::encode(&tx.sender_address)),
        nonce: u64::from_be_bytes(tx.nonce.try_into().unwrap_or([0; 8])),
        call_count: calls.len(),
        max_fee: format!("0x{}", hex::encode(&tx.max_fee)),
        signed: !tx.signature.is_empty()
    }
}
 
fn parse_calldata(calldata: &[Vec<u8>]) -> Vec<Call> {
    let mut calls = Vec::new();
    let mut i = 0;
    while i < calldata.len() {
        if i + 2 < calldata.len() {
            calls.push(Call {
                contract: calldata[i].clone(),
                selector: calldata[i + 1].clone(),
                params: if i + 2 < calldata.len() {
                    calldata[i + 2].clone()
                } else {
                    vec![]
                }
            });
        }
        i += 3;
    }
    calls
}

Common Transaction Patterns

// Single contract call
let single_call_tx = InvokeTransactionV1 {
    max_fee: vec![0, 0, 0, 0, 0, 1, 0, 0],
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 1],
    sender_address: vec![/* account address */],
    calldata: vec![
        vec![/* contract address */],
        vec![/* function selector */],
        vec![/* parameters */]
    ]
};
 
// Multi-call transaction
let multi_call_tx = InvokeTransactionV1 {
    max_fee: vec![0, 0, 0, 0, 0, 2, 0, 0],
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 2],
    sender_address: vec![/* account address */],
    calldata: vec![
        // First call
        vec![/* contract address 1 */],
        vec![/* function selector 1 */],
        vec![/* parameters 1 */],
        // Second call
        vec![/* contract address 2 */],
        vec![/* function selector 2 */],
        vec![/* parameters 2 */]
    ]
};

Important Notes

  • Improvements over V0:

    • Added nonce for replay protection
    • Explicit sender address
    • Support for multiple contract calls
    • More flexible calldata format
  • Key features:

    • Transaction sequencing
    • Multi-call support
    • Account abstraction ready
    • Improved security

InvokeTransactionV3

pub struct InvokeTransactionV3 {
    pub sender_address: Vec<u8>,
    pub calldata: Vec<Vec<u8>>,
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub resource_bounds: Option<ResourceBounds>,
    pub tip: Vec<u8>,
    pub paymaster_data: Vec<Vec<u8>>,
    pub account_deployment_data: Vec<Vec<u8>>,
    pub nonce_data_availability_mode: i32,
    pub fee_data_availability_mode: i32,
}

FeeDataAvailabilityMode (nonce_data_availability_mode & fee_data_availability_mode)

pub enum FeeDataAvailabilityMode {
    Unspecified = 0,    // Default mode when not specified
    L1 = 1,             // Fee data stored on L1
    L2 = 2,             // Fee data stored on L2
}

Fields

sender_address

  • Description: Address of the account initiating the transaction
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account address */]

calldata

  • Description: Encoded function calls and parameters
  • Type: Vec<Vec<u8>>
  • Example: Multiple contract calls encoded sequentially

signature

  • Description: Authorization signature(s) for the transaction
  • Type: Vec<Vec<u8>>
  • Example: Multiple signature components

nonce

  • Description: Account nonce for replay protection
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1]

resource_bounds

  • Description: Maximum resources allowed for transaction
  • Type: Option<ResourceBounds>
  • Example: Limits on L1 gas, L2 gas, etc.

tip

  • Description: Additional fee paid to sequencer
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 100] (100 wei tip)

paymaster_data

  • Description: Data for fee payment delegation
  • Type: Vec<Vec<u8>>
  • Example: Paymaster contract info and authorization

account_deployment_data

  • Description: Data for deploying account contract
  • Type: Vec<Vec<u8>>
  • Example: Account class hash and constructor params

nonce_data_availability_mode

  • Description: DA mode for nonce storage
  • Type: i32
  • Values: 0 (Unknown), 1 (L1), 2 (L2)

fee_data_availability_mode

  • Description: DA mode for fee storage
  • Type: i32
  • Values: 0 (Unknown), 1 (L1), 2 (L2)

Example Use Cases

fn process_invoke_v3(tx: &InvokeTransactionV3) -> InvokeV3Analysis {
    InvokeV3Analysis {
        sender: format!("0x{}", hex::encode(&tx.sender_address)),
        is_account_deployment: !tx.account_deployment_data.is_empty(),
        has_paymaster: !tx.paymaster_data.is_empty(),
        resource_bounds: tx.resource_bounds.as_ref().map(analyze_bounds),
        da_mode: analyze_da_modes(
            tx.nonce_data_availability_mode,
            tx.fee_data_availability_mode
        ),
        tip_amount: u64::from_be_bytes(tx.tip.try_into().unwrap_or([0; 8]))
    }
}
 
// Example of paymaster integration
fn create_paymaster_tx(
    base_tx: InvokeTransactionV3,
    paymaster: &PaymasterInfo
) -> InvokeTransactionV3 {
    InvokeTransactionV3 {
        paymaster_data: vec![
            paymaster.address.clone(),
            paymaster.signature.clone(),
            paymaster.extra_data.clone()
        ],
        ..base_tx
    }
}

Common Transaction Patterns

// Account deployment with transaction
let deployment_tx = InvokeTransactionV3 {
    sender_address: vec![/* new account address */],
    calldata: vec![/* initial transaction calldata */],
    signature: vec![/* signature components */],
    nonce: vec![0, 0, 0, 0],  // Initial nonce
    resource_bounds: Some(ResourceBounds {
        max_amount: vec![/* resource limits */],
        max_price_per_unit: vec![/* price limits */]
    }),
    account_deployment_data: vec![
        vec![/* account class hash */],
        vec![/* constructor params */]
    ],
    ..Default::default()
};
 
// Paymaster-sponsored transaction
let sponsored_tx = InvokeTransactionV3 {
    sender_address: vec![/* user account */],
    calldata: vec![/* transaction calldata */],
    signature: vec![/* user signature */],
    nonce: vec![0, 0, 0, 1],
    resource_bounds: Some(ResourceBounds { /* ... */ }),
    paymaster_data: vec![
        vec![/* paymaster contract */],
        vec![/* paymaster signature */]
    ],
    fee_data_availability_mode: 1,  // L1
    ..Default::default()
};

Important Notes

  • Latest transaction version with advanced features:
    • Resource bounds for better fee estimation
    • Paymaster support for fee abstraction
    • Account deployment capabilities
    • Flexible data availability modes
    • Sequencer tips

L1HandlerTransaction

pub struct L1HandlerTransaction {
    pub contract_address: Vec<u8>,
    pub entry_point_selector: Vec<u8>,
    pub calldata: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub version: i32,
}

Fields

contract_address

  • Description: Address of the L2 contract handling the L1 message
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

entry_point_selector

  • Description: Selector of the L1 handler function to be called
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of function selector */]

calldata

  • Description: Parameters from the L1 message
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* from_address */],
        vec![/* payload... */]
    ]

nonce

  • Description: Unique identifier for the L1 message
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1]

version

  • Description: Version of the L1 handler transaction format
  • Type: i32
  • Example: 1

Example Use Cases

fn process_l1_handler(tx: &L1HandlerTransaction) -> L1HandlerAnalysis {
    // Identify common L1 handler types
    let handler_type = match tx.entry_point_selector.as_slice() {
        [0x12, 0x34, 0x56, 0x78, ..] => "TokenBridge",
        [0xa9, 0x05, 0x9c, 0xbb, ..] => "StateUpdate",
        [0xdc, 0x13, 0x45, 0x67, ..] => "MessageHandler",
        _ => "Unknown"
    };
 
    L1HandlerAnalysis {
        contract: format!("0x{}", hex::encode(&tx.contract_address)),
        handler_type: handler_type.to_string(),
        nonce: u64::from_be_bytes(tx.nonce.try_into().unwrap_or([0; 8])),
        version: tx.version,
        param_count: tx.calldata.len()
    }
}
 
// Example of parsing L1 message data
fn parse_l1_message(tx: &L1HandlerTransaction) -> Option<L1Message> {
    if tx.calldata.len() < 2 {
        return None;
    }
 
    Some(L1Message {
        from_address: tx.calldata[0].clone(),
        payload: tx.calldata[1..].to_vec()
    })
}

Common Transaction Patterns

// Token bridge message handler
let bridge_handler = L1HandlerTransaction {
    contract_address: vec![/* bridge contract address */],
    entry_point_selector: vec![0x12, 0x34, 0x56, 0x78], // handle_bridge
    calldata: vec![
        vec![/* L1 bridge address */],
        vec![/* token address */],
        vec![/* recipient */],
        vec![/* amount */]
    ],
    nonce: vec![0, 0, 0, 1],
    version: 1
};
 
// State update handler
let state_handler = L1HandlerTransaction {
    contract_address: vec![/* state contract address */],
    entry_point_selector: vec![0xa9, 0x05, 0x9c, 0xbb], // handle_state
    calldata: vec![
        vec![/* L1 contract */],
        vec![/* state root */],
        vec![/* block number */]
    ],
    nonce: vec![0, 0, 0, 2],
    version: 1
};

Important Notes

  • Key component for L1→L2 communication

  • Common use cases:

    • Token bridging
    • State synchronization
    • Cross-layer messaging
    • Governance actions
  • Security considerations:

    • Message origin verification
    • Nonce uniqueness
    • Handler authorization
    • State consistency

DeclareTransactionV0

pub struct DeclareTransactionV0 {
    pub max_fee: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub class_hash: Vec<u8>,
    pub sender_address: Vec<u8>,
}

Fields

max_fee

  • Description: Maximum fee the sender is willing to pay for declaration
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents fee in wei)

signature

  • Description: Transaction authorization signature(s)
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ]

class_hash

  • Description: Hash of the contract class being declared
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of class hash */]

sender_address

  • Description: Address of the account declaring the contract
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account address */]

Example Use Cases

fn process_declare_v0(tx: &DeclareTransactionV0) -> DeclareAnalysis {
    DeclareAnalysis {
        declarer: format!("0x{}", hex::encode(&tx.sender_address)),
        class: format!("0x{}", hex::encode(&tx.class_hash)),
        max_fee: u64::from_be_bytes(tx.max_fee.try_into().unwrap_or([0; 8])),
        signed: !tx.signature.is_empty()
    }
}
 
// Example of validating a declare transaction
fn validate_declare_v0(tx: &DeclareTransactionV0) -> Result<(), String> {
    // Check signature presence
    if tx.signature.is_empty() {
        return Err("Missing signature".to_string());
    }
 
    // Validate class hash length
    if tx.class_hash.len() != 32 {
        return Err("Invalid class hash length".to_string());
    }
 
    // Validate sender address
    if tx.sender_address.len() != 32 {
        return Err("Invalid sender address length".to_string());
    }
 
    Ok(())
}

Common Transaction Patterns

// Basic contract declaration
let basic_declare = DeclareTransactionV0 {
    max_fee: vec![0, 0, 0, 0, 0, 1, 0, 0],  // 256 wei
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    class_hash: vec![/* contract class hash */],
    sender_address: vec![/* account address */]
};
 
// System contract declaration
let system_declare = DeclareTransactionV0 {
    max_fee: vec![0, 0, 0, 0, 0, 2, 0, 0],  // 512 wei
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    class_hash: vec![/* system contract class hash */],
    sender_address: vec![/* privileged account address */]
};

Important Notes

  • Legacy declaration format (V0)
  • Used to register contract classes on Starknet
  • Key aspects:
    • Simple fee model
    • Basic signature scheme
    • No class code included
    • Class must be valid Cairo

DeclareTransactionV1

pub struct DeclareTransactionV1 {
    pub max_fee: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub class_hash: Vec<u8>,
    pub sender_address: Vec<u8>,
}

Fields

max_fee

  • Description: Maximum fee the sender is willing to pay for declaration
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents fee in wei)

signature

  • Description: Transaction authorization signature(s)
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ]

nonce

  • Description: Account nonce for replay protection
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1]

class_hash

  • Description: Hash of the contract class being declared
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of class hash */]

sender_address

  • Description: Address of the account declaring the contract
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account address */]

Example Use Cases

fn process_declare_v1(tx: &DeclareTransactionV1) -> DeclareV1Analysis {
    DeclareV1Analysis {
        declarer: format!("0x{}", hex::encode(&tx.sender_address)),
        class: format!("0x{}", hex::encode(&tx.class_hash)),
        nonce: u64::from_be_bytes(tx.nonce.try_into().unwrap_or([0; 8])),
        max_fee: u64::from_be_bytes(tx.max_fee.try_into().unwrap_or([0; 8])),
        signed: !tx.signature.is_empty()
    }
}
 
// Example of transaction sequencing validation
fn validate_declare_sequence(
    tx: &DeclareTransactionV1,
    current_nonce: &[u8]
) -> Result<(), String> {
    if tx.nonce <= current_nonce {
        return Err("Invalid nonce sequence".to_string());
    }
    
    // Additional validation logic
    Ok(())
}

Common Transaction Patterns

// Standard contract declaration
let standard_declare = DeclareTransactionV1 {
    max_fee: vec![0, 0, 0, 0, 0, 1, 0, 0],  // 256 wei
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 1],
    class_hash: vec![/* contract class hash */],
    sender_address: vec![/* account address */]
};
 
// Upgraded contract version declaration
let upgrade_declare = DeclareTransactionV1 {
    max_fee: vec![0, 0, 0, 0, 0, 2, 0, 0],  // 512 wei
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 2],
    class_hash: vec![/* upgraded class hash */],
    sender_address: vec![/* account address */]
};

Important Notes

  • Improvements over V0:

    • Added nonce for replay protection
    • Better transaction sequencing
    • Same class declaration capabilities
    • Enhanced security model
  • Key features:

    • Transaction ordering
    • Replay prevention
    • Account abstraction support
    • Legacy fee model compatibility

DeclareTransactionV2

pub struct DeclareTransactionV2 {
    pub max_fee: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub class_hash: Vec<u8>,
    pub sender_address: Vec<u8>,
    pub compiled_class_hash: Vec<u8>,
}

Fields

max_fee

  • Description: Maximum fee the sender is willing to pay for declaration
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents fee in wei)

signature

  • Description: Transaction authorization signature(s)
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ]

nonce

  • Description: Account nonce for replay protection
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1]

class_hash

  • Description: Hash of the Sierra contract class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of Sierra class hash */]

sender_address

  • Description: Address of the account declaring the contract
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account address */]

compiled_class_hash

  • Description: Hash of the compiled CASM class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of CASM class hash */]

Example Use Cases

fn process_declare_v2(tx: &DeclareTransactionV2) -> DeclareV2Analysis {
    DeclareV2Analysis {
        declarer: format!("0x{}", hex::encode(&tx.sender_address)),
        sierra_class: format!("0x{}", hex::encode(&tx.class_hash)),
        casm_class: format!("0x{}", hex::encode(&tx.compiled_class_hash)),
        nonce: u64::from_be_bytes(tx.nonce.try_into().unwrap_or([0; 8])),
        max_fee: u64::from_be_bytes(tx.max_fee.try_into().unwrap_or([0; 8])),
        signed: !tx.signature.is_empty()
    }
}
 
// Example of class hash validation
fn validate_class_hashes(tx: &DeclareTransactionV2) -> Result<(), String> {
    // Validate Sierra class hash
    if tx.class_hash.len() != 32 {
        return Err("Invalid Sierra class hash length".to_string());
    }
 
    // Validate CASM class hash
    if tx.compiled_class_hash.len() != 32 {
        return Err("Invalid CASM class hash length".to_string());
    }
 
    // Additional validation logic
    Ok(())
}

Common Transaction Patterns

// Sierra contract declaration
let sierra_declare = DeclareTransactionV2 {
    max_fee: vec![0, 0, 0, 0, 0, 1, 0, 0],
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 1],
    class_hash: vec![/* Sierra class hash */],
    compiled_class_hash: vec![/* CASM class hash */],
    sender_address: vec![/* account address */]
};
 
// Upgraded Sierra contract declaration
let upgrade_declare = DeclareTransactionV2 {
    max_fee: vec![0, 0, 0, 0, 0, 2, 0, 0],
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 2],
    class_hash: vec![/* new Sierra class hash */],
    compiled_class_hash: vec![/* new CASM class hash */],
    sender_address: vec![/* account address */]
};

Important Notes

  • First version supporting Sierra contracts

  • Key improvements:

    • Sierra class support
    • Compiled class verification
    • Better type safety
    • Enhanced compilation validation
  • Important features:

    • Dual hash verification
    • Sierra/CASM compatibility
    • Backward compatibility
    • Enhanced security checks

DeclareTransactionV3

pub struct DeclareTransactionV3 {
    pub sender_address: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub class_hash: Vec<u8>,
    pub compiled_class_hash: Vec<u8>,
    pub resource_bounds: Option<ResourceBounds>,
    pub tip: Vec<u8>,
    pub paymaster_data: Vec<Vec<u8>>,
    pub account_deployment_data: Vec<Vec<u8>>,
    pub nonce_data_availability_mode: i32,
    pub fee_data_availability_mode: i32,
}

FeeDataAvailabilityMode (nonce_data_availability_mode & fee_data_availability_mode)

pub enum FeeDataAvailabilityMode {
    Unspecified = 0,    // Default mode when not specified
    L1 = 1,             // Fee data stored on L1
    L2 = 2,             // Fee data stored on L2
}

Fields

sender_address

  • Description: Address of the account declaring the contract
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account address */]

signature

  • Description: Transaction authorization signature(s)
  • Type: Vec<Vec<u8>>
  • Example: Multiple signature components

nonce

  • Description: Account nonce for replay protection
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1]

class_hash

  • Description: Hash of the Sierra contract class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of Sierra class hash */]

compiled_class_hash

  • Description: Hash of the compiled CASM class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of CASM class hash */]

resource_bounds

  • Description: Maximum resources allowed for declaration
  • Type: Option<ResourceBounds>
  • Example: Limits on L1 gas, L2 gas

tip

  • Description: Additional fee for sequencer
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 100] (100 wei tip)

paymaster_data

  • Description: Data for fee payment delegation
  • Type: Vec<Vec<u8>>
  • Example: Paymaster contract info and authorization

account_deployment_data

  • Description: Data for deploying account contract
  • Type: Vec<Vec<u8>>
  • Example: Account class hash and constructor params

nonce_data_availability_mode, fee_data_availability_mode

  • Description: DA modes for nonce and fee storage
  • Type: i32
  • Values: 0 (Unknown), 1 (L1), 2 (L2)

Example Use Cases

fn process_declare_v3(tx: &DeclareTransactionV3) -> DeclareV3Analysis {
    DeclareV3Analysis {
        declarer: format!("0x{}", hex::encode(&tx.sender_address)),
        sierra_class: format!("0x{}", hex::encode(&tx.class_hash)),
        casm_class: format!("0x{}", hex::encode(&tx.compiled_class_hash)),
        has_paymaster: !tx.paymaster_data.is_empty(),
        is_account_deployment: !tx.account_deployment_data.is_empty(),
        resource_bounds: tx.resource_bounds.as_ref().map(analyze_bounds),
        tip_amount: u64::from_be_bytes(tx.tip.try_into().unwrap_or([0; 8]))
    }
}
 
// Example of paymaster-sponsored declaration
fn create_sponsored_declare(
    base_tx: DeclareTransactionV3,
    paymaster: &PaymasterInfo
) -> DeclareTransactionV3 {
    DeclareTransactionV3 {
        paymaster_data: vec![
            paymaster.address.clone(),
            paymaster.signature.clone()
        ],
        fee_data_availability_mode: 1, // L1
        ..base_tx
    }
}

Common Transaction Patterns

// Standard Sierra declaration
let standard_declare = DeclareTransactionV3 {
    sender_address: vec![/* account address */],
    signature: vec![/* signature components */],
    nonce: vec![0, 0, 0, 1],
    class_hash: vec![/* Sierra class hash */],
    compiled_class_hash: vec![/* CASM class hash */],
    resource_bounds: Some(ResourceBounds {
        max_amount: vec![/* resource limits */],
        max_price_per_unit: vec![/* price limits */]
    }),
    tip: vec![0, 0, 0, 0],
    paymaster_data: vec![],
    account_deployment_data: vec![],
    nonce_data_availability_mode: 1,
    fee_data_availability_mode: 1,
};
 
// Sponsored declaration with account deployment
let sponsored_declare = DeclareTransactionV3 {
    sender_address: vec![/* new account address */],
    signature: vec![/* signature components */],
    nonce: vec![0, 0, 0, 0],
    class_hash: vec![/* Sierra class hash */],
    compiled_class_hash: vec![/* CASM class hash */],
    resource_bounds: Some(ResourceBounds { /* ... */ }),
    paymaster_data: vec![/* paymaster info */],
    account_deployment_data: vec![
        vec![/* account class hash */],
        vec![/* constructor params */]
    ],
    ..Default::default()
};

Important Notes

  • Latest declaration version with advanced features:
    • Resource bounds
    • Fee delegation via paymaster
    • Account deployment support
    • Flexible DA modes
    • Sequencer tips

DeployTransactionV0

pub struct DeployTransactionV0 {
    pub version: i32,
    pub contract_address: Vec<u8>,
    pub contract_address_salt: Vec<u8>,
    pub class_hash: Vec<u8>,
    pub constructor_calldata: Vec<Vec<u8>>,
}

Fields

version

  • Description: Version identifier for the deploy transaction
  • Type: i32
  • Example: 0 (V0 deployment)

contract_address

  • Description: Computed address where contract will be deployed
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

contract_address_salt

  • Description: Salt used in contract address computation
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of random salt */]

class_hash

  • Description: Hash of the contract class to deploy
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of class hash */]

constructor_calldata

  • Description: Arguments for contract constructor
  • Type: Vec<Vec<u8>>
  • Example: Constructor parameters as byte arrays

Example Use Cases

fn process_deploy_v0(tx: &DeployTransactionV0) -> DeployAnalysis {
    DeployAnalysis {
        address: format!("0x{}", hex::encode(&tx.contract_address)),
        class: format!("0x{}", hex::encode(&tx.class_hash)),
        salt: format!("0x{}", hex::encode(&tx.contract_address_salt)),
        constructor_args: tx.constructor_calldata.len(),
        version: tx.version
    }
}
 
// Example of address computation validation
fn validate_contract_address(
    tx: &DeployTransactionV0,
    computed_address: &[u8]
) -> Result<(), String> {
    if tx.contract_address != computed_address {
        return Err("Invalid contract address computation".to_string());
    }
    
    // Additional validation logic
    Ok(())
}

Common Transaction Patterns

// Basic contract deployment
let basic_deploy = DeployTransactionV0 {
    version: 0,
    contract_address: vec![/* computed contract address */],
    contract_address_salt: vec![/* random salt */],
    class_hash: vec![/* contract class hash */],
    constructor_calldata: vec![
        vec![/* initial parameter */]
    ]
};
 
// Token contract deployment
let token_deploy = DeployTransactionV0 {
    version: 0,
    contract_address: vec![/* computed address */],
    contract_address_salt: vec![/* unique salt */],
    class_hash: vec![/* ERC20 class hash */],
    constructor_calldata: vec![
        vec![/* name */],
        vec![/* symbol */],
        vec![/* decimals */],
        vec![/* initial_supply */],
        vec![/* owner */]
    ]
};

Important Notes

  • Legacy deployment format (V0)

  • Key characteristics:

    • Deterministic addressing
    • No explicit fee handling
    • Simple constructor interface
    • Basic deployment logic
  • Address computation:

    • Based on salt
    • Class hash included
    • Constructor parameters affect address
    • Must match computed value

DeployAccountTransactionV1

pub struct DeployAccountTransactionV1 {
    pub max_fee: Vec<u8>,
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub contract_address_salt: Vec<u8>,
    pub constructor_calldata: Vec<Vec<u8>>,
    pub class_hash: Vec<u8>,
}

Fields

max_fee

  • Description: Maximum fee willing to pay for account deployment
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents fee in wei)

signature

  • Description: Signature(s) authorizing the deployment
  • Type: Vec<Vec<u8>>
  • Example:
    vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ]

nonce

  • Description: Initial nonce for the account
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0] (typically starts at 0)

contract_address_salt

  • Description: Salt for deterministic address computation
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of random salt */]

constructor_calldata

  • Description: Arguments for account constructor
  • Type: Vec<Vec<u8>>
  • Example: Account initialization parameters

class_hash

  • Description: Hash of the account contract class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account class hash */]

Example Use Cases

fn process_deploy_account_v1(
    tx: &DeployAccountTransactionV1
) -> DeployAccountAnalysis {
    DeployAccountAnalysis {
        class: format!("0x{}", hex::encode(&tx.class_hash)),
        salt: format!("0x{}", hex::encode(&tx.contract_address_salt)),
        max_fee: u64::from_be_bytes(tx.max_fee.try_into().unwrap_or([0; 8])),
        constructor_args: tx.constructor_calldata.len(),
        initial_nonce: u64::from_be_bytes(tx.nonce.try_into().unwrap_or([0; 8]))
    }
}
 
// Example of computing account address
fn compute_account_address(tx: &DeployAccountTransactionV1) -> Vec<u8> {
    let mut hasher = StarknetKeccak::new();
    hasher.update(&[1]); // prefix for account deployment
    hasher.update(&tx.contract_address_salt);
    hasher.update(&tx.class_hash);
    hasher.update(&serialize_calldata(&tx.constructor_calldata));
    hasher.finalize().to_vec()
}

Common Transaction Patterns

// Basic account deployment
let basic_account = DeployAccountTransactionV1 {
    max_fee: vec![0, 0, 0, 0, 0, 1, 0, 0],
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 0],
    contract_address_salt: vec![/* random salt */],
    constructor_calldata: vec![
        vec![/* public_key */]
    ],
    class_hash: vec![/* account contract class hash */]
};
 
// Multisig account deployment
let multisig_account = DeployAccountTransactionV1 {
    max_fee: vec![0, 0, 0, 0, 0, 2, 0, 0],
    signature: vec![
        vec![/* r signature component */],
        vec![/* s signature component */]
    ],
    nonce: vec![0, 0, 0, 0],
    contract_address_salt: vec![/* random salt */],
    constructor_calldata: vec![
        vec![/* threshold */],
        vec![/* owner_1 */],
        vec![/* owner_2 */],
        vec![/* owner_3 */]
    ],
    class_hash: vec![/* multisig class hash */]
};

Important Notes

  • First version with explicit account deployment

  • Key features:

    • Fee specification
    • Signature validation
    • Nonce initialization
    • Deterministic addressing
    • Constructor parameters
  • Common use cases:

    • EOA account deployment
    • Multisig account creation
    • Smart contract wallet deployment
    • Custom account implementation

DeployAccountTransactionV3

pub struct DeployAccountTransactionV3 {
    pub signature: Vec<Vec<u8>>,
    pub nonce: Vec<u8>,
    pub contract_address_salt: Vec<u8>,
    pub constructor_calldata: Vec<Vec<u8>>,
    pub class_hash: Vec<u8>,
    pub resource_bounds: Option<ResourceBounds>,
    pub tip: Vec<u8>,
    pub paymaster_data: Vec<Vec<u8>>,
    pub nonce_data_availability_mode: i32,
    pub fee_data_availability_mode: i32,
}

FeeDataAvailabilityMode (nonce_data_availability_mode & fee_data_availability_mode)

pub enum FeeDataAvailabilityMode {
    Unspecified = 0,    // Default mode when not specified
    L1 = 1,             // Fee data stored on L1
    L2 = 2,             // Fee data stored on L2
}

Fields

signature

  • Description: Signature(s) authorizing the deployment
  • Type: Vec<Vec<u8>>
  • Example: Multiple signature components

nonce

  • Description: Initial nonce for the account
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0]

contract_address_salt

  • Description: Salt for deterministic address computation
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of random salt */]

constructor_calldata

  • Description: Arguments for account constructor
  • Type: Vec<Vec<u8>>
  • Example: Account initialization parameters

class_hash

  • Description: Hash of the account contract class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of account class hash */]

resource_bounds

  • Description: Maximum resources allowed for deployment
  • Type: Option<ResourceBounds>
  • Example: Limits on L1 gas, L2 gas

tip

  • Description: Additional fee for sequencer
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 100] (100 wei tip)

paymaster_data

  • Description: Data for fee payment delegation
  • Type: Vec<Vec<u8>>
  • Example: Paymaster contract info and authorization

nonce_data_availability_mode, fee_data_availability_mode

  • Description: DA modes for nonce and fee storage
  • Type: i32
  • Values: 0 (Unknown), 1 (L1), 2 (L2)

Example Use Cases

fn process_deploy_account_v3(
    tx: &DeployAccountTransactionV3
) -> DeployAccountV3Analysis {
    DeployAccountV3Analysis {
        class: format!("0x{}", hex::encode(&tx.class_hash)),
        salt: format!("0x{}", hex::encode(&tx.contract_address_salt)),
        has_paymaster: !tx.paymaster_data.is_empty(),
        resource_bounds: tx.resource_bounds.as_ref().map(analyze_bounds),
        tip_amount: u64::from_be_bytes(tx.tip.try_into().unwrap_or([0; 8])),
        constructor_args: tx.constructor_calldata.len(),
        da_mode: format!("nonce:{}, fee:{}", 
            tx.nonce_data_availability_mode,
            tx.fee_data_availability_mode
        )
    }
}
 
// Example of sponsored account deployment
fn create_sponsored_deployment(
    base_tx: DeployAccountTransactionV3,
    paymaster: &PaymasterInfo
) -> DeployAccountTransactionV3 {
    DeployAccountTransactionV3 {
        paymaster_data: vec![
            paymaster.address.clone(),
            paymaster.signature.clone()
        ],
        fee_data_availability_mode: 1, // L1
        ..base_tx
    }
}

Common Transaction Patterns

// Standard account deployment
let standard_deploy = DeployAccountTransactionV3 {
    signature: vec![/* signature components */],
    nonce: vec![0, 0, 0, 0],
    contract_address_salt: vec![/* random salt */],
    constructor_calldata: vec![
        vec![/* public_key */]
    ],
    class_hash: vec![/* account class hash */],
    resource_bounds: Some(ResourceBounds {
        max_amount: vec![/* resource limits */],
        max_price_per_unit: vec![/* price limits */]
    }),
    tip: vec![0, 0, 0, 0],
    paymaster_data: vec![],
    nonce_data_availability_mode: 1,
    fee_data_availability_mode: 1,
};
 
// Sponsored multisig deployment
let sponsored_multisig = DeployAccountTransactionV3 {
    signature: vec![/* signature components */],
    nonce: vec![0, 0, 0, 0],
    contract_address_salt: vec![/* random salt */],
    constructor_calldata: vec![
        vec![/* threshold */],
        vec![/* owners... */]
    ],
    class_hash: vec![/* multisig class hash */],
    resource_bounds: Some(ResourceBounds { /* ... */ }),
    paymaster_data: vec![/* paymaster info */],
    fee_data_availability_mode: 1,
    ..Default::default()
};

Important Notes

  • Latest account deployment version with advanced features:

    • Resource bounds
    • Fee delegation
    • Flexible DA modes
    • Sequencer tips
    • Enhanced fee model
  • Key improvements:

    • Better resource management
    • Sponsored deployments
    • Customizable DA strategy
    • Advanced fee mechanics

ResourceBounds

pub struct ResourceBounds {
    pub max_amount: Vec<u8>,
    pub max_price_per_unit: Vec<u8>,
}

Fields

max_amount

  • Description: Maximum amount of resource units allowed
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 1, 0, 0] (represents maximum gas units)

max_price_per_unit

  • Description: Maximum price willing to pay per resource unit
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 0, 0, 0, 1, 0] (represents price per gas unit)

Example Use Cases

fn calculate_max_cost(bounds: &ResourceBounds) -> Result<u128, String> {
    let max_amount = u128::from_be_bytes(
        bounds.max_amount.try_into()
            .map_err(|_| "Invalid max_amount")?
    );
    let max_price = u128::from_be_bytes(
        bounds.max_price_per_unit.try_into()
            .map_err(|_| "Invalid max_price")?
    );
    
    Ok(max_amount.checked_mul(max_price)
        .ok_or("Overflow in cost calculation")?)
}
 
// Example of validating resource bounds
fn validate_resource_bounds(
    bounds: &ResourceBounds,
    current_price: &[u8]
) -> Result<(), String> {
    if bounds.max_price_per_unit < current_price {
        return Err("Price too high".to_string());
    }
    
    // Additional validation logic
    Ok(())
}

Common Resource Patterns

// Conservative resource bounds
let conservative_bounds = ResourceBounds {
    max_amount: vec![0, 0, 0, 0, 0, 1, 0, 0],     // 256 units
    max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 1, 0]  // 256 wei/unit
};
 
// Liberal resource bounds for complex operations
let liberal_bounds = ResourceBounds {
    max_amount: vec![0, 0, 0, 0, 0, 10, 0, 0],    // 2560 units
    max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 2, 0]  // 512 wei/unit
};
 
// Resource bounds for different scenarios
let bounds_by_type = vec![
    // For simple transfers
    ResourceBounds {
        max_amount: vec![0, 0, 0, 0, 0, 0, 50, 0],
        max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 1, 0]
    },
    // For contract deployments
    ResourceBounds {
        max_amount: vec![0, 0, 0, 0, 0, 5, 0, 0],
        max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 2, 0]
    },
    // For complex DeFi operations
    ResourceBounds {
        max_amount: vec![0, 0, 0, 0, 0, 20, 0, 0],
        max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 3, 0]
    }
];

Important Notes

  • Used in V3 transactions for:

    • Fee estimation
    • Resource limitation
    • Cost control
    • Price protection
  • Key aspects:

    • Separate amount and price bounds
    • Multiplication for total cost
    • Price protection mechanism
    • Resource usage control

Common Use Cases

Transaction Fee Control

let fee_bounds = ResourceBounds {
    max_amount: vec![0, 0, 0, 0, 0, 1, 0, 0],  // Max gas units
    max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 1, 0]  // Max gas price
};

Resource Usage Limits

let compute_bounds = ResourceBounds {
    max_amount: vec![0, 0, 0, 0, 0, 5, 0, 0],  // Max computation steps
    max_price_per_unit: vec![0, 0, 0, 0, 0, 0, 0, 100]  // Price per step
};

Resource

pub struct Resource {
    pub max_amount: String,
    pub max_price_per_unit: String,
}

Fields

max_amount

  • Description: Maximum amount of the resource that can be used in the transaction
  • Type: String
  • Example: "1000000" (represents maximum resource units)
  • Note: Stored as a string to handle large numbers precisely

max_price_per_unit

  • Description: Maximum price per unit of resource for this transaction
  • Type: String
  • Example: "100000000" (represents price per unit in wei)
  • Note: Stored as a string to handle large numbers precisely

Example Use Cases

fn calculate_max_cost(resource: &Resource) -> Result<String, String> {
    // Using string-based big number arithmetic for precision
    let max_amount = BigInt::from_str(&resource.max_amount)
        .map_err(|_| "Invalid max_amount")?;
    let max_price = BigInt::from_str(&resource.max_price_per_unit)
        .map_err(|_| "Invalid max_price")?;
    
    Ok((max_amount * max_price).to_string())
}
 
// Example of resource validation
fn validate_resource(
    resource: &Resource,
    current_price: &str
) -> Result<(), String> {
    let max_price = BigInt::from_str(&resource.max_price_per_unit)
        .map_err(|_| "Invalid max_price")?;
    let current = BigInt::from_str(current_price)
        .map_err(|_| "Invalid current_price")?;
    
    if max_price < current {
        return Err("Price exceeds maximum".to_string());
    }
    
    Ok(())
}

Common Resource Patterns

// Standard resource limits
let standard_resource = Resource {
    max_amount: "1000000".to_string(),      // 1M units
    max_price_per_unit: "1000000".to_string() // 1M wei per unit
};
 
// High computation resource
let computation_resource = Resource {
    max_amount: "5000000".to_string(),      // 5M units
    max_price_per_unit: "2000000".to_string() // 2M wei per unit
};
 
// Resource configurations for different operations
let resources = vec![
    // For simple operations
    Resource {
        max_amount: "500000".to_string(),
        max_price_per_unit: "1000000".to_string()
    },
    // For complex operations
    Resource {
        max_amount: "2000000".to_string(),
        max_price_per_unit: "3000000".to_string()
    }
];

Important Notes

  • Uses string representation for:

    • Arbitrary precision arithmetic
    • Large number handling
    • Exact value preservation
    • Gas cost calculations
  • Key considerations:

    • String-based numeric operations
    • Precision handling
    • Overflow prevention
    • Cost calculations

Receipt

pub struct Receipt {
    pub actual_fee: String,
    pub execution_resources: Option<ExecutionResources>,
    pub l1_to_l2_consumed_message: Option<L1ToL2Message>,
    pub l2_to_l1_messages: Vec<L2ToL1Message>,
    pub events: Vec<Event>,
    pub execution_status: i32,
    pub revert_error: String,
}

Fields

actual_fee

  • Description: The actual fee charged for the transaction execution
  • Type: String
  • Example: "1234567890" (in wei)

execution_resources

  • Description: Detailed breakdown of resources consumed during execution
  • Type: Option<ExecutionResources>
  • Example: Contains steps, memory usage, and builtin applications

l1_to_l2_consumed_message

  • Description: L1 message that was consumed by this transaction
  • Type: Option<L1ToL2Message>
  • Example: Message from Ethereum that triggered this transaction

l2_to_l1_messages

  • Description: Messages sent from L2 to L1 during execution
  • Type: Vec<L2ToL1Message>
  • Example: State updates, token bridge messages

events

  • Description: Events emitted during transaction execution
  • Type: Vec<Event>
  • Example: Transfer events, state change notifications

execution_status

  • Description: Status code of the transaction execution
  • Type: i32
  • Values:
    • 0: UNSPECIFIED
    • 1: SUCCEEDED
    • 2: REVERTED

revert_error

  • Description: Error message if transaction was reverted
  • Type: String
  • Example: "Insufficient balance"

Example Use Cases

fn analyze_receipt(receipt: &Receipt) -> ReceiptAnalysis {
    ReceiptAnalysis {
        success: receipt.execution_status == 1,
        fee_paid: receipt.actual_fee.clone(),
        message_count: receipt.l2_to_l1_messages.len(),
        event_count: receipt.events.len(),
        has_l1_message: receipt.l1_to_l2_consumed_message.is_some(),
        resources: receipt.execution_resources.as_ref().map(analyze_resources),
        error: if receipt.execution_status == 2 {
            Some(receipt.revert_error.clone())
        } else {
            None
        }
    }
}
 
// Example of processing receipt events
fn process_receipt_events(receipt: &Receipt) -> Vec<EventAnalysis> {
    receipt.events.iter().map(|event| {
        EventAnalysis {
            emitter: format!("0x{}", hex::encode(&event.from_address)),
            keys: event.keys.len(),
            data: event.data.len()
        }
    }).collect()
}

Common Receipt Patterns

// Successful transaction receipt
let success_receipt = Receipt {
    actual_fee: "1000000".to_string(),
    execution_resources: Some(ExecutionResources {
        steps: 1000,
        memory_holes: 10,
        range_check_builtin_applications: 20,
        pedersen_builtin_applications: 2,
        // ... other resource fields
    }),
    l1_to_l2_consumed_message: None,
    l2_to_l1_messages: vec![],
    events: vec![
        Event {
            from_address: vec![/* contract address */],
            keys: vec![/* event keys */],
            data: vec![/* event data */]
        }
    ],
    execution_status: 1,  // SUCCEEDED
    revert_error: "".to_string()
};
 
// Failed transaction receipt
let failed_receipt = Receipt {
    actual_fee: "500000".to_string(),
    execution_resources: Some(ExecutionResources {
        // ... resource usage until failure
    }),
    l1_to_l2_consumed_message: None,
    l2_to_l1_messages: vec![],
    events: vec![],
    execution_status: 2,  // REVERTED
    revert_error: "Insufficient balance".to_string()
};

Important Notes

  • Key transaction outcome record

  • Contains:

    • Execution result
    • Resource usage
    • Cross-layer messages
    • Emitted events
    • Fee information
  • Used for:

    • Transaction verification
    • State tracking
    • Fee calculation
    • Event monitoring
    • Error handling

ActualFee

pub struct ActualFee {
    pub amount: String,
    pub unit: String,
}

Fields

amount

  • Description: The actual amount of fee charged
  • Type: String
  • Example: "1000000" (represents exact fee amount)
  • Note: Stored as string to handle large numbers precisely

unit

  • Description: The currency unit of the fee
  • Type: String
  • Example: "WEI" or "FRI"
  • Note: Indicates the denomination of the fee

Example Use Cases

fn process_actual_fee(fee: &ActualFee) -> FeeAnalysis {
    FeeAnalysis {
        amount: BigInt::from_str(&fee.amount)
            .unwrap_or_default(),
        is_wei: fee.unit.to_uppercase() == "WEI",
        is_fri: fee.unit.to_uppercase() == "FRI",
        formatted: format!("{} {}", fee.amount, fee.unit)
    }
}
 
// Example of fee conversion
fn convert_fee_to_eth(fee: &ActualFee) -> Result<f64, String> {
    if fee.unit.to_uppercase() != "WEI" {
        return Err("Fee not in WEI".to_string());
    }
    
    let wei_amount = BigInt::from_str(&fee.amount)
        .map_err(|_| "Invalid amount")?;
    
    // Convert wei to ETH (1 ETH = 10^18 wei)
    let eth_value = (wei_amount / BigInt::from(10u64.pow(18)))
        .to_f64()
        .ok_or("Conversion error")?;
    
    Ok(eth_value)
}

Common Fee Patterns

// Standard transaction fee
let standard_fee = ActualFee {
    amount: "1000000000000000".to_string(), // 0.001 ETH in wei
    unit: "WEI".to_string()
};
 
// FRI-denominated fee
let fri_fee = ActualFee {
    amount: "5000000".to_string(),
    unit: "FRI".to_string()
};
 
// Fee examples for different transaction types
let fee_examples = vec![
    // Simple transfer fee
    ActualFee {
        amount: "21000000000000".to_string(),
        unit: "WEI".to_string()
    },
    // Contract deployment fee
    ActualFee {
        amount: "500000000000000".to_string(),
        unit: "WEI".to_string()
    },
    // Complex DeFi operation fee
    ActualFee {
        amount: "1500000000000000".to_string(),
        unit: "WEI".to_string()
    }
];

Important Notes

  • Used for precise fee representation

  • Key characteristics:

    • String-based amount storage
    • Explicit unit specification
    • Multi-currency support
    • Exact value preservation
  • Common units:

    • WEI: Ethereum’s smallest unit
    • FRI: Starknet’s fee token
    • Other potential future units

Fee Calculation Examples

// Fee aggregation
fn aggregate_fees(fees: &[ActualFee]) -> Result<ActualFee, String> {
    let mut total = BigInt::from(0);
    let mut unit = String::new();
    
    for fee in fees {
        if unit.is_empty() {
            unit = fee.unit.clone();
        } else if unit != fee.unit {
            return Err("Mixed units not supported".to_string());
        }
        
        total += BigInt::from_str(&fee.amount)
            .map_err(|_| "Invalid amount")?;
    }
    
    Ok(ActualFee {
        amount: total.to_string(),
        unit
    })
}
 
// Fee comparison
fn compare_fees(fee1: &ActualFee, fee2: &ActualFee) -> Result<Ordering, String> {
    if fee1.unit != fee2.unit {
        return Err("Cannot compare different units".to_string());
    }
    
    let amount1 = BigInt::from_str(&fee1.amount)
        .map_err(|_| "Invalid amount in fee1")?;
    let amount2 = BigInt::from_str(&fee2.amount)
        .map_err(|_| "Invalid amount in fee2")?;
    
    Ok(amount1.cmp(&amount2))
}

DataAvailability

pub struct DataAvailability {
    pub l1_gas_price: ResourcePrice,
    pub l1_gas_usage: ResourceBounds,
    pub l1_data_gas_price: ResourcePrice,
    pub l1_data_gas_usage: ResourceBounds,
}

Fields

l1_gas_price

  • Description: Price information for L1 gas
  • Type: ResourcePrice
  • Example: Price in both wei and fri units

l1_gas_usage

  • Description: Bounds for L1 gas consumption
  • Type: ResourceBounds
  • Example: Maximum amount and price per unit for L1 gas

l1_data_gas_price

  • Description: Price information for L1 data gas
  • Type: ResourcePrice
  • Example: Price for data posting on L1

l1_data_gas_usage

  • Description: Bounds for L1 data gas consumption
  • Type: ResourceBounds
  • Example: Maximum amount and price per unit for data posting

Example Use Cases

fn calculate_da_costs(da: &DataAvailability) -> DAAnalysis {
    // Calculate L1 gas costs
    let l1_gas_cost = calculate_resource_cost(
        &da.l1_gas_price,
        &da.l1_gas_usage
    );
 
    // Calculate L1 data gas costs
    let l1_data_cost = calculate_resource_cost(
        &da.l1_data_gas_price,
        &da.l1_data_gas_usage
    );
 
    DAAnalysis {
        total_l1_gas: l1_gas_cost,
        total_data_gas: l1_data_cost,
        total_cost: l1_gas_cost + l1_data_cost
    }
}
 
fn calculate_resource_cost(
    price: &ResourcePrice,
    bounds: &ResourceBounds
) -> u128 {
    let amount = u128::from_be_bytes(
        bounds.max_amount.try_into().unwrap_or([0; 16])
    );
    let price_per_unit = u128::from_be_bytes(
        price.price_in_wei.try_into().unwrap_or([0; 16])
    );
    
    amount * price_per_unit
}

Common Usage Patterns

// Standard DA configuration
let standard_da = DataAvailability {
    l1_gas_price: ResourcePrice {
        price_in_fri: vec![0, 0, 0, 100],  // 100 FRI
        price_in_wei: vec![0, 0, 0, 1000]  // 1000 WEI
    },
    l1_gas_usage: ResourceBounds {
        max_amount: vec![0, 0, 0, 50000],  // 50K gas units
        max_price_per_unit: vec![0, 0, 0, 2000]  // 2000 WEI/unit
    },
    l1_data_gas_price: ResourcePrice {
        price_in_fri: vec![0, 0, 0, 200],  // 200 FRI
        price_in_wei: vec![0, 0, 0, 2000]  // 2000 WEI
    },
    l1_data_gas_usage: ResourceBounds {
        max_amount: vec![0, 0, 0, 10000],  // 10K data gas units
        max_price_per_unit: vec![0, 0, 0, 3000]  // 3000 WEI/unit
    }
};
 
// High data usage configuration
let high_data_da = DataAvailability {
    // ... l1_gas_price and l1_gas_usage ...
    l1_data_gas_usage: ResourceBounds {
        max_amount: vec![0, 0, 0, 100000],  // 100K data gas units
        max_price_per_unit: vec![0, 0, 0, 4000]  // 4000 WEI/unit
    },
    // ... other fields ...
};

Important Notes

  • Key aspects:

    • Separate tracking of gas and data gas
    • Dual pricing in FRI and WEI
    • Resource bounds for both types
    • L1 cost management
  • Used for:

    • DA cost estimation
    • Resource allocation
    • Fee calculation
    • Transaction planning

StateUpdate

pub struct StateUpdate {
    pub block_hash: Vec<u8>,
    pub new_root: Vec<u8>,
    pub old_root: Vec<u8>,
    pub state_diff: Option<StateDiff>,
}

Fields

block_hash

  • Description: Hash of the block this state update belongs to
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of block hash */]

new_root

  • Description: New state root after applying the update
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of new state root */]

old_root

  • Description: Previous state root before the update
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of old state root */]

state_diff

  • Description: Detailed changes made to the state
  • Type: Option<StateDiff>
  • Example: Contains storage updates, deployed contracts, etc.

Example Use Cases

fn process_state_update(update: &StateUpdate) -> StateUpdateAnalysis {
    StateUpdateAnalysis {
        block: format!("0x{}", hex::encode(&update.block_hash)),
        old_state: format!("0x{}", hex::encode(&update.old_root)),
        new_state: format!("0x{}", hex::encode(&update.new_root)),
        has_changes: update.state_diff.is_some(),
        diff_summary: update.state_diff.as_ref().map(summarize_diff)
    }
}
 
fn validate_state_transition(update: &StateUpdate) -> Result<(), String> {
    // Verify root lengths
    if update.new_root.len() != 32 || update.old_root.len() != 32 {
        return Err("Invalid root length".to_string());
    }
 
    // Verify state hasn't changed if no diff present
    if update.state_diff.is_none() && update.new_root != update.old_root {
        return Err("Root changed without state diff".to_string());
    }
 
    Ok(())
}

Common State Update Patterns

// Simple state update with storage changes
let storage_update = StateUpdate {
    block_hash: vec![/* block hash */],
    new_root: vec![/* new state root */],
    old_root: vec![/* old state root */],
    state_diff: Some(StateDiff {
        storage_diffs: vec![
            StorageDiff {
                address: vec![/* contract address */],
                storage_entries: vec![
                    StorageEntry {
                        key: vec![/* storage key */],
                        value: vec![/* new value */]
                    }
                ]
            }
        ],
        deployed_contracts: vec![],
        declared_classes: vec![],
        deprecated_declared_classes: vec![]
    })
};
 
// Contract deployment state update
let deployment_update = StateUpdate {
    block_hash: vec![/* block hash */],
    new_root: vec![/* new state root */],
    old_root: vec![/* old state root */],
    state_diff: Some(StateDiff {
        storage_diffs: vec![],
        deployed_contracts: vec![
            DeployedContract {
                address: vec![/* contract address */],
                class_hash: vec![/* class hash */]
            }
        ],
        declared_classes: vec![
            DeclaredClass {
                class_hash: vec![/* class hash */],
                compiled_class_hash: vec![/* compiled hash */]
            }
        ],
        deprecated_declared_classes: vec![]
    })
};

Important Notes

  • Key state transition record

  • Used for:

    • State verification
    • State synchronization
    • History tracking
    • Root chain updates
  • Verification aspects:

    • Root consistency
    • State transition validity
    • Diff completeness
    • Block correlation

State Diff Analysis Examples

fn analyze_state_changes(update: &StateUpdate) -> StateChanges {
    let diff = match &update.state_diff {
        Some(diff) => diff,
        None => return StateChanges::default()
    };
 
    StateChanges {
        storage_changes: diff.storage_diffs.len(),
        new_contracts: diff.deployed_contracts.len(),
        new_classes: diff.declared_classes.len(),
        deprecated_classes: diff.deprecated_declared_classes.len(),
        root_changed: update.new_root != update.old_root
    }
}
 
fn verify_root_consistency(updates: &[StateUpdate]) -> bool {
    for window in updates.windows(2) {
        if window[0].new_root != window[1].old_root {
            return false;
        }
    }
    true
}

StateDiff

pub struct StateDiff {
    pub storage_diffs: Vec<StorageDiff>,
    pub deployed_contracts: Vec<DeployedContract>,
    pub declared_classes: Vec<DeclaredClass>,
    pub deprecated_declared_classes: Vec<DeprecatedDeclaredClass>,
}

Fields

storage_diffs

  • Description: List of storage changes across contracts
  • Type: Vec<StorageDiff>
  • Example: Changes to contract storage values

deployed_contracts

  • Description: New contracts deployed in this state update
  • Type: Vec<DeployedContract>
  • Example: Newly deployed contract addresses and their class hashes

declared_classes

  • Description: New contract classes declared
  • Type: Vec<DeclaredClass>
  • Example: Newly declared class hashes and their compiled versions

deprecated_declared_classes

  • Description: Contract classes marked as deprecated
  • Type: Vec<DeprecatedDeclaredClass>
  • Example: Class hashes that are no longer supported

Example Use Cases

fn analyze_state_diff(diff: &StateDiff) -> StateDiffAnalysis {
    StateDiffAnalysis {
        storage_changes: summarize_storage_changes(&diff.storage_diffs),
        new_contracts: summarize_deployments(&diff.deployed_contracts),
        new_classes: summarize_declarations(&diff.declared_classes),
        deprecated_classes: diff.deprecated_declared_classes.len(),
        total_changes: calculate_total_changes(diff)
    }
}
 
fn calculate_total_changes(diff: &StateDiff) -> usize {
    let storage_entries: usize = diff.storage_diffs
        .iter()
        .map(|sd| sd.storage_entries.len())
        .sum();
 
    storage_entries 
        + diff.deployed_contracts.len()
        + diff.declared_classes.len()
        + diff.deprecated_declared_classes.len()
}

Common Diff Patterns

// Storage update diff
let storage_diff = StateDiff {
    storage_diffs: vec![
        StorageDiff {
            address: vec![/* contract address */],
            storage_entries: vec![
                StorageEntry {
                    key: vec![/* storage key */],
                    value: vec![/* new value */]
                }
            ]
        }
    ],
    deployed_contracts: vec![],
    declared_classes: vec![],
    deprecated_declared_classes: vec![]
};
 
// Contract deployment with storage initialization
let deployment_diff = StateDiff {
    storage_diffs: vec![
        StorageDiff {
            address: vec![/* new contract address */],
            storage_entries: vec![
                // Initial storage values
                StorageEntry {
                    key: vec![/* owner key */],
                    value: vec![/* owner address */]
                },
                StorageEntry {
                    key: vec![/* balance key */],
                    value: vec![/* initial balance */]
                }
            ]
        }
    ],
    deployed_contracts: vec![
        DeployedContract {
            address: vec![/* contract address */],
            class_hash: vec![/* class hash */]
        }
    ],
    declared_classes: vec![
        DeclaredClass {
            class_hash: vec![/* class hash */],
            compiled_class_hash: vec![/* compiled hash */]
        }
    ],
    deprecated_declared_classes: vec![]
};

Important Notes

  • Comprehensive state change record
  • Used for:
    • State synchronization
    • Change tracking
    • Contract deployment monitoring
    • Storage updates
    • Class management

Diff Analysis Examples

// Group changes by contract
fn group_changes_by_contract(diff: &StateDiff) -> HashMap<Vec<u8>, ContractChanges> {
    let mut changes = HashMap::new();
    
    // Add storage changes
    for storage_diff in &diff.storage_diffs {
        changes.entry(storage_diff.address.clone())
            .or_insert_with(ContractChanges::default)
            .storage_changes += storage_diff.storage_entries.len();
    }
    
    // Add deployments
    for deployment in &diff.deployed_contracts {
        changes.entry(deployment.address.clone())
            .or_insert_with(ContractChanges::default)
            .is_new_deployment = true;
    }
    
    changes
}
 
// Track class changes
fn track_class_changes(diff: &StateDiff) -> ClassChangesSummary {
    ClassChangesSummary {
        new_classes: diff.declared_classes
            .iter()
            .map(|dc| format!("0x{}", hex::encode(&dc.class_hash)))
            .collect(),
        deprecated_classes: diff.deprecated_declared_classes
            .iter()
            .map(|dc| format!("0x{}", hex::encode(&dc.class_hash)))
            .collect()
    }
}

NonceDiff

pub struct NonceDiff {
    pub contract_address: Vec<u8>,
    pub nonce: Vec<u8>,
}

Fields

contract_address

  • Description: Address of the contract whose nonce is being updated
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

nonce

  • Description: New nonce value for the contract
  • Type: Vec<u8>
  • Example: vec![0, 0, 0, 1] (incremented nonce value)

Example Use Cases

fn process_nonce_diff(diff: &NonceDiff) -> NonceDiffAnalysis {
    NonceDiffAnalysis {
        contract: format!("0x{}", hex::encode(&diff.contract_address)),
        new_nonce: u64::from_be_bytes(
            diff.nonce.clone().try_into().unwrap_or([0; 8])
        ),
        is_first_transaction: diff.nonce == vec![0, 0, 0, 1]
    }
}
 
// Example of nonce validation
fn validate_nonce_sequence(
    current: &[u8],
    diff: &NonceDiff
) -> Result<(), String> {
    let current_nonce = u64::from_be_bytes(
        current.try_into().map_err(|_| "Invalid current nonce")?
    );
    
    let new_nonce = u64::from_be_bytes(
        diff.nonce.clone().try_into().map_err(|_| "Invalid new nonce")?
    );
    
    if new_nonce <= current_nonce {
        return Err("Invalid nonce sequence".to_string());
    }
    
    Ok(())
}

Common Nonce Patterns

// First transaction nonce update
let initial_nonce = NonceDiff {
    contract_address: vec![/* contract address */],
    nonce: vec![0, 0, 0, 1]  // First nonce
};
 
// Sequential nonce update
let sequential_nonce = NonceDiff {
    contract_address: vec![/* contract address */],
    nonce: vec![0, 0, 0, 2]  // Next nonce in sequence
};
 
// Batch of nonce updates
let nonce_updates = vec![
    // Account 1 nonce update
    NonceDiff {
        contract_address: vec![/* account 1 address */],
        nonce: vec![0, 0, 0, 5]  // New nonce value
    },
    // Account 2 nonce update
    NonceDiff {
        contract_address: vec![/* account 2 address */],
        nonce: vec![0, 0, 0, 3]  // New nonce value
    }
];

Important Notes

  • Used for:

    • Transaction ordering
    • Replay protection
    • Account state tracking
    • Sequence validation
  • Key aspects:

    • Sequential incrementing
    • Contract-specific tracking
    • State synchronization
    • Transaction validation

Nonce Management Examples

// Track nonce changes by contract
fn track_contract_nonces(
    diffs: &[NonceDiff]
) -> HashMap<Vec<u8>, Vec<u8>> {
    let mut nonce_map = HashMap::new();
    
    for diff in diffs {
        nonce_map.insert(
            diff.contract_address.clone(),
            diff.nonce.clone()
        );
    }
    
    nonce_map
}
 
// Validate nonce transitions
fn validate_nonce_transitions(
    diffs: &[NonceDiff]
) -> Result<(), String> {
    let mut last_nonces = HashMap::new();
    
    for diff in diffs {
        let last_nonce = last_nonces
            .get(&diff.contract_address)
            .unwrap_or(&vec![0, 0, 0, 0]);
            
        validate_nonce_sequence(last_nonce, diff)?;
        
        last_nonces.insert(
            diff.contract_address.clone(),
            diff.nonce.clone()
        );
    }
    
    Ok(())
}

ReplacedClass

pub struct ReplacedClass {
    pub contract_address: Vec<u8>,
    pub class_hash: Vec<u8>,
}

Fields

contract_address

  • Description: Address of the contract whose class is being replaced
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

class_hash

  • Description: Hash of the new contract class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of new class hash */]

Example Use Cases

fn process_class_replacement(
    replacement: &ReplacedClass
) -> ClassReplacementAnalysis {
    ClassReplacementAnalysis {
        contract: format!("0x{}", hex::encode(&replacement.contract_address)),
        new_class: format!("0x{}", hex::encode(&replacement.class_hash)),
        timestamp: chrono::Utc::now()
    }
}
 
// Example of replacement validation
fn validate_class_replacement(
    replacement: &ReplacedClass,
    old_class_hash: &[u8]
) -> Result<(), String> {
    // Ensure addresses are valid
    if replacement.contract_address.len() != 32 {
        return Err("Invalid contract address length".to_string());
    }
    
    // Ensure class hash is valid
    if replacement.class_hash.len() != 32 {
        return Err("Invalid class hash length".to_string());
    }
    
    // Ensure new class is different
    if replacement.class_hash == old_class_hash {
        return Err("New class same as old class".to_string());
    }
    
    Ok(())
}

Common Replacement Patterns

// Standard class replacement
let standard_replacement = ReplacedClass {
    contract_address: vec![/* contract address */],
    class_hash: vec![/* new class hash */]
};
 
// Batch of class replacements
let upgrade_batch = vec![
    // Upgrade contract 1
    ReplacedClass {
        contract_address: vec![/* contract 1 address */],
        class_hash: vec![/* new class 1 hash */]
    },
    // Upgrade contract 2
    ReplacedClass {
        contract_address: vec![/* contract 2 address */],
        class_hash: vec![/* new class 2 hash */]
    }
];
 
// System contract upgrade
let system_upgrade = ReplacedClass {
    contract_address: vec![/* system contract address */],
    class_hash: vec![/* new system class hash */]
};

Important Notes

  • Used for:

    • Contract upgrades
    • Implementation changes
    • Bug fixes
    • Feature additions
  • Key aspects:

    • Contract immutability
    • Class versioning
    • Upgrade tracking
    • State preservation

Replacement Analysis Examples

// Track class replacements over time
struct ClassHistory {
    contract: Vec<u8>,
    replacements: Vec<ClassReplacement>,
}
 
struct ClassReplacement {
    class_hash: Vec<u8>,
    timestamp: DateTime<Utc>,
}
 
fn track_class_history(
    replacements: &[ReplacedClass]
) -> HashMap<Vec<u8>, Vec<Vec<u8>>> {
    let mut history = HashMap::new();
    
    for replacement in replacements {
        history
            .entry(replacement.contract_address.clone())
            .or_insert_with(Vec::new)
            .push(replacement.class_hash.clone());
    }
    
    history
}
 
// Analyze upgrade patterns
fn analyze_upgrade_patterns(
    replacements: &[ReplacedClass]
) -> UpgradeAnalysis {
    let mut analysis = UpgradeAnalysis::default();
    let mut contract_upgrades = HashMap::new();
    
    for replacement in replacements {
        *contract_upgrades
            .entry(replacement.contract_address.clone())
            .or_insert(0) += 1;
    }
    
    analysis.total_upgrades = replacements.len();
    analysis.contracts_upgraded = contract_upgrades.len();
    analysis.max_upgrades = contract_upgrades.values().max().copied().unwrap_or(0);
    
    analysis
}

DeployedContract

pub struct DeployedContract {
    pub address: Vec<u8>,
    pub class_hash: Vec<u8>,
}

Fields

address

  • Description: Address where the contract was deployed
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

class_hash

  • Description: Hash of the contract’s class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of class hash */]

Example Use Cases

fn process_deployment(
    deployment: &DeployedContract
) -> DeploymentAnalysis {
    DeploymentAnalysis {
        contract: format!("0x{}", hex::encode(&deployment.address)),
        class: format!("0x{}", hex::encode(&deployment.class_hash)),
        timestamp: chrono::Utc::now()
    }
}
 
// Example of deployment validation
fn validate_deployment(
    deployment: &DeployedContract,
    existing_contracts: &HashMap<Vec<u8>, bool>
) -> Result<(), String> {
    // Check address length
    if deployment.address.len() != 32 {
        return Err("Invalid address length".to_string());
    }
    
    // Check class hash length
    if deployment.class_hash.len() != 32 {
        return Err("Invalid class hash length".to_string());
    }
    
    // Check for address collision
    if existing_contracts.contains_key(&deployment.address) {
        return Err("Address already in use".to_string());
    }
    
    Ok(())
}

Common Deployment Patterns

// Standard contract deployment
let standard_deployment = DeployedContract {
    address: vec![/* contract address */],
    class_hash: vec![/* class hash */]
};
 
// Batch deployments
let deployment_batch = vec![
    // Deploy token contract
    DeployedContract {
        address: vec![/* token address */],
        class_hash: vec![/* token class hash */]
    },
    // Deploy vault contract
    DeployedContract {
        address: vec![/* vault address */],
        class_hash: vec![/* vault class hash */]
    }
];
 
// Factory deployment pattern
struct ContractFactory {
    deployments: Vec<DeployedContract>,
    class_hash: Vec<u8>,
}
 
impl ContractFactory {
    fn deploy_new_instance(&mut self, salt: &[u8]) -> DeployedContract {
        let address = compute_address(salt, &self.class_hash);
        let deployment = DeployedContract {
            address: address.clone(),
            class_hash: self.class_hash.clone()
        };
        self.deployments.push(deployment.clone());
        deployment
    }
}

Important Notes

  • Used for:

    • Contract creation tracking
    • Address registration
    • Class association
    • Deployment verification
  • Key aspects:

    • Unique addresses
    • Class verification
    • State initialization
    • Deployment tracking

Deployment Analysis Examples

// Track deployments by class
fn analyze_deployments_by_class(
    deployments: &[DeployedContract]
) -> HashMap<Vec<u8>, Vec<Vec<u8>>> {
    let mut class_instances = HashMap::new();
    
    for deployment in deployments {
        class_instances
            .entry(deployment.class_hash.clone())
            .or_insert_with(Vec::new)
            .push(deployment.address.clone());
    }
    
    class_instances
}
 
// Deployment statistics
fn calculate_deployment_stats(
    deployments: &[DeployedContract]
) -> DeploymentStats {
    let mut stats = DeploymentStats::default();
    let mut unique_classes = HashSet::new();
    
    for deployment in deployments {
        unique_classes.insert(deployment.class_hash.clone());
    }
    
    stats.total_deployments = deployments.len();
    stats.unique_classes = unique_classes.len();
    
    stats
}

DeclaredClass

pub struct DeclaredClass {
    pub class_hash: Vec<u8>,
    pub compiled_class_hash: Vec<u8>,
}

Fields

class_hash

  • Description: Hash of the Sierra contract class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of Sierra class hash */]

compiled_class_hash

  • Description: Hash of the compiled CASM class
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of CASM class hash */]

Example Use Cases

fn process_declaration(
    declaration: &DeclaredClass
) -> DeclarationAnalysis {
    DeclarationAnalysis {
        sierra_class: format!("0x{}", hex::encode(&declaration.class_hash)),
        casm_class: format!("0x{}", hex::encode(&declaration.compiled_class_hash)),
        timestamp: chrono::Utc::now()
    }
}
 
// Example of declaration validation
fn validate_declaration(
    declaration: &DeclaredClass,
    existing_classes: &HashMap<Vec<u8>, bool>
) -> Result<(), String> {
    // Validate Sierra class hash
    if declaration.class_hash.len() != 32 {
        return Err("Invalid Sierra class hash length".to_string());
    }
    
    // Validate CASM class hash
    if declaration.compiled_class_hash.len() != 32 {
        return Err("Invalid CASM class hash length".to_string());
    }
    
    // Check for existing declaration
    if existing_classes.contains_key(&declaration.class_hash) {
        return Err("Class already declared".to_string());
    }
    
    Ok(())
}

Common Declaration Patterns

// Standard class declaration
let standard_declaration = DeclaredClass {
    class_hash: vec![/* Sierra class hash */],
    compiled_class_hash: vec![/* CASM class hash */]
};
 
// Batch declarations
let declaration_batch = vec![
    // Declare token contract
    DeclaredClass {
        class_hash: vec![/* token Sierra hash */],
        compiled_class_hash: vec![/* token CASM hash */]
    },
    // Declare vault contract
    DeclaredClass {
        class_hash: vec![/* vault Sierra hash */],
        compiled_class_hash: vec![/* vault CASM hash */]
    }
];
 
// System contract declarations
let system_declarations = vec![
    DeclaredClass {
        class_hash: vec![/* proxy Sierra hash */],
        compiled_class_hash: vec![/* proxy CASM hash */]
    },
    DeclaredClass {
        class_hash: vec![/* registry Sierra hash */],
        compiled_class_hash: vec![/* registry CASM hash */]
    }
];

Important Notes

  • Used for:

    • Class registration
    • Sierra/CASM mapping
    • Contract versioning
    • Class verification
  • Key aspects:

    • Unique class hashes
    • Compilation verification
    • Version tracking
    • Declaration order

Declaration Analysis Examples

// Track class declarations
struct ClassRegistry {
    declarations: HashMap<Vec<u8>, DeclaredClass>,
    declaration_order: Vec<Vec<u8>>,
}
 
impl ClassRegistry {
    fn register_class(&mut self, declaration: DeclaredClass) -> Result<(), String> {
        if self.declarations.contains_key(&declaration.class_hash) {
            return Err("Class already registered".to_string());
        }
        
        self.declaration_order.push(declaration.class_hash.clone());
        self.declarations.insert(declaration.class_hash.clone(), declaration);
        Ok(())
    }
    
    fn get_casm_hash(&self, sierra_hash: &[u8]) -> Option<&Vec<u8>> {
        self.declarations.get(sierra_hash)
            .map(|dec| &dec.compiled_class_hash)
    }
}
 
// Declaration statistics
fn analyze_declarations(
    declarations: &[DeclaredClass]
) -> DeclarationStats {
    DeclarationStats {
        total_declarations: declarations.len(),
        unique_sierra_classes: declarations.iter()
            .map(|d| &d.class_hash)
            .collect::<HashSet<_>>()
            .len(),
        unique_casm_classes: declarations.iter()
            .map(|d| &d.compiled_class_hash)
            .collect::<HashSet<_>>()
            .len()
    }
}

ContractStorageDiff

pub struct ContractStorageDiff {
    pub address: Vec<u8>,
    pub storage_entries: Vec<StorageEntries>,
}

Fields

address

  • Description: Address of the contract whose storage is being modified
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of contract address */]

storage_entries

  • Description: List of storage changes for the contract
  • Type: Vec<StorageEntry>
  • Example: Collection of key-value pairs representing storage changes

Example Use Cases

fn process_storage_diff(
    diff: &ContractStorageDiff
) -> StorageDiffAnalysis {
    StorageDiffAnalysis {
        contract: format!("0x{}", hex::encode(&diff.address)),
        changes: diff.storage_entries.len(),
        entries: diff.storage_entries.iter()
            .map(analyze_storage_entry)
            .collect()
    }
}
 
// Example of storage diff validation
fn validate_storage_diff(
    diff: &ContractStorageDiff
) -> Result<(), String> {
    // Validate contract address
    if diff.address.len() != 32 {
        return Err("Invalid contract address length".to_string());
    }
    
    // Validate storage entries
    for entry in &diff.storage_entries {
        if entry.key.len() != 32 {
            return Err("Invalid storage key length".to_string());
        }
        if entry.value.len() != 32 {
            return Err("Invalid storage value length".to_string());
        }
    }
    
    Ok(())
}

Common Storage Diff Patterns

// Balance update diff
let balance_update = ContractStorageDiff {
    address: vec![/* token contract address */],
    storage_entries: vec![
        StorageEntry {
            key: vec![/* balance mapping key */],
            value: vec![/* new balance */]
        }
    ]
};
 
// Multiple storage updates
let complex_update = ContractStorageDiff {
    address: vec![/* contract address */],
    storage_entries: vec![
        StorageEntry {
            key: vec![/* owner key */],
            value: vec![/* new owner */]
        },
        StorageEntry {
            key: vec![/* status key */],
            value: vec![/* new status */]
        },
        StorageEntry {
            key: vec![/* config key */],
            value: vec![/* new config */]
        }
    ]
};
 
// Batch of contract storage diffs
let batch_diffs = vec![
    // Token contract updates
    ContractStorageDiff {
        address: vec![/* token address */],
        storage_entries: vec![/* token storage changes */]
    },
    // Vault contract updates
    ContractStorageDiff {
        address: vec![/* vault address */],
        storage_entries: vec![/* vault storage changes */]
    }
];

Important Notes

  • Used for:

    • State updates
    • Storage tracking
    • Contract modifications
    • State synchronization
  • Key aspects:

    • Contract-specific changes
    • Multiple entry updates
    • Key-value modifications
    • State transition tracking

Storage Analysis Examples

// Track storage changes by contract
struct StorageChangeTracker {
    changes: HashMap<Vec<u8>, Vec<StorageEntry>>,
    change_count: HashMap<Vec<u8>, usize>,
}
 
impl StorageChangeTracker {
    fn record_changes(&mut self, diff: &ContractStorageDiff) {
        self.changes
            .entry(diff.address.clone())
            .or_default()
            .extend(diff.storage_entries.clone());
            
        *self.change_count
            .entry(diff.address.clone())
            .or_default() += diff.storage_entries.len();
    }
    
    fn get_contract_changes(&self, address: &[u8]) -> Option<&Vec<StorageEntry>> {
        self.changes.get(address)
    }
    
    fn get_change_count(&self, address: &[u8]) -> usize {
        self.change_count.get(address).copied().unwrap_or(0)
    }
}
 
// Analyze storage patterns
fn analyze_storage_patterns(
    diffs: &[ContractStorageDiff]
) -> StoragePatternAnalysis {
    let mut analysis = StoragePatternAnalysis::default();
    
    for diff in diffs {
        analysis.total_changes += diff.storage_entries.len();
        analysis.contracts_modified += 1;
        
        // Analyze key patterns
        for entry in &diff.storage_entries {
            analysis.record_key_pattern(&entry.key);
        }
    }
    
    analysis
}

StorageEntries

pub struct StorageEntries {
    pub key: Vec<u8>,
    pub value: Vec<u8>,
}

Fields

key

  • Description: Storage slot key
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of storage key */]

value

  • Description: Value stored at the key
  • Type: Vec<u8>
  • Example: vec![/* 32 bytes of storage value */]

Example Use Cases

fn process_storage_entry(
    entry: &StorageEntries
) -> StorageEntryAnalysis {
    StorageEntryAnalysis {
        key: format!("0x{}", hex::encode(&entry.key)),
        value: format!("0x{}", hex::encode(&entry.value)),
        is_zero: entry.value.iter().all(|&b| b == 0),
        key_prefix: get_key_prefix(&entry.key)
    }
}
 
// Example of entry validation
fn validate_storage_entry(
    entry: &StorageEntries
) -> Result<(), String> {
    // Validate key length
    if entry.key.len() != 32 {
        return Err("Invalid key length".to_string());
    }
    
    // Validate value length
    if entry.value.len() != 32 {
        return Err("Invalid value length".to_string());
    }
    
    Ok(())
}

Common Storage Entry Patterns

// Simple value storage
let simple_entry = StorageEntries {
    key: vec![/* storage key */],
    value: vec![/* stored value */]
};
 
// Mapping entry (e.g., balances)
let mapping_entry = StorageEntries {
    key: compute_mapping_key(
        "balances",  // mapping name
        &address     // mapping key
    ),
    value: vec![/* balance amount */]
};
 
// Common storage patterns
let storage_examples = vec![
    // Owner storage
    StorageEntries {
        key: vec![/* owner slot */],
        value: vec![/* owner address */]
    },
    // Total supply
    StorageEntries {
        key: vec![/* total supply slot */],
        value: vec![/* supply amount */]
    },
    // Paused status
    StorageEntries {
        key: vec![/* pause slot */],
        value: vec![/* pause status */]
    }
];

Important Notes

  • Used for:

    • State storage
    • Value retrieval
    • State modifications
    • Data persistence
  • Key aspects:

    • Fixed-size keys
    • Fixed-size values
    • Key uniqueness
    • Value immutability

Storage Entry Analysis Examples

// Track value changes
struct ValueChangeTracker {
    previous_values: HashMap<Vec<u8>, Vec<u8>>,
    changes: Vec<ValueChange>,
}
 
impl ValueChangeTracker {
    fn record_change(&mut self, entry: &StorageEntries) {
        let previous = self.previous_values.get(&entry.key).cloned();
        
        self.changes.push(ValueChange {
            key: entry.key.clone(),
            old_value: previous.clone(),
            new_value: entry.value.clone(),
            is_initial: previous.is_none(),
        });
        
        self.previous_values.insert(entry.key.clone(), entry.value.clone());
    }
}
 
// Analyze storage patterns
fn analyze_storage_patterns(
    entries: &[StorageEntries]
) -> StoragePatternAnalysis {
    let mut analysis = StoragePatternAnalysis::default();
    
    for entry in entries {
        // Analyze key patterns
        analysis.record_key_pattern(&entry.key);
        
        // Analyze value patterns
        analysis.record_value_pattern(&entry.value);
        
        // Track zero values
        if entry.value.iter().all(|&b| b == 0) {
            analysis.zero_values += 1;
        }
    }
    
    analysis
}
 
// Key computation utilities
fn compute_mapping_key(
    name: &str,
    key: &[u8]
) -> Vec<u8> {
    let mut hasher = Keccak256::new();
    hasher.update(name.as_bytes());
    hasher.update(key);
    hasher.finalize().to_vec()
}