Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Important: If you're upgrading snforge to version 0.48.0 or later, please read the 0.48.0 Migration Guide.

l1_handler

fn new(target: ContractAddress, selector: felt252) -> L1Handler

Returns an L1Handler structure which can be used to mock sending messages from L1 for the contract to handle in function marked with #[l1_handler].

#[derive(Drop, Clone)]
pub struct L1Handler {
    target: ContractAddress,
    selector: felt252,
}

fn execute(self: L1Handler) -> SyscallResult<()>

Mocks an L1 -> L2 message from Ethereum handled by the given L1 handler function.

Example

Let's consider a very simple contract, which receives an L1 message with an array of numbers them:

#[starknet::contract]
mod L1HandlerExample {
    #[storage]
    struct Storage {}

    #[l1_handler]
    fn handle_l1_message(ref self: ContractState, from_address: felt252, numbers: Array<felt252>) {
        assert!(from_address == 0x123456789012345678901234567890123456789, "Unexpected address");
        assert!(numbers.len() == 3, "Expected exactly 3 numbers");
    }
}

Test code:

use snforge_std::cheatcodes::contract_class::DeclareResultTrait;
use snforge_std::{ContractClassTrait, L1HandlerTrait, declare};

#[test]
fn test_l1_handler() {
    // 1. Declare and deploy the Starknet contract
    let example_contract = declare("L1HandlerExample").unwrap().contract_class();
    let (contract_address, _) = example_contract.deploy(@array![]).unwrap();

    // 2. Define the L1 handler to be called
    let l1_handler = L1HandlerTrait::new(contract_address, selector!("handle_l1_message"));

    // 3. Define Ethereum address of the message sender
    let eth_address = 0x123456789012345678901234567890123456789;

    // 4. The payload to be sent to the L1 handler
    let payload = array![1, 2, 3];
    let mut serialized_payload = array![];
    payload.serialize(ref serialized_payload);

    // 5. Execute the L1 handler with the Ethereum address and payload
    // This will trigger the `handle_l1_message` function of the contract
    l1_handler.execute(eth_address, serialized_payload.span()).unwrap();
}

Let's run the test:

$ snforge test test_l1_handler
Output:
Collected 1 test(s) from cheatcodes_reference package
Running 1 test(s) from tests/
[PASS] cheatcodes_reference_integrationtest::test_l1_handler::test_l1_handler ([..])
Running 0 test(s) from src/
Tests: 1 passed, 0 failed, 0 ignored, [..] filtered out