l1_handler_execute
fn execute(self: L1Handler) -> SyscallResult<()>
Executes a #[l1_handler]
function to mock a
message
arriving from Ethereum.
📝 Note
Execution of the
#[l1_handler]
function may panic like any other function. It works like a regularSafeDispatcher
would with a function call. For more info about asserting panic data check out handling panic errors
struct L1Handler {
contract_address: ContractAddress,
function_selector: felt252,
from_address: felt252,
payload: Span::<felt252>,
}
where:
contract_address
- The target contract addressfunction_selector
- Selector of the#[l1_handler]
functionfrom_address
- Ethereum address of the contract that sends the messagepayload
- The message payload that may contain any Cairo data structure that can be serialized with Serde
It is important to note that when executing the l1_handler
,
the from_address
may be checked as any L1 contract can call any L2 contract.
For a contract implementation:
// ...
#[storage]
struct Storage {
l1_allowed: felt252,
//...
}
//...
#[l1_handler]
fn process_l1_message(ref self: ContractState, from_address: felt252, data: Span<felt252>) {
assert(from_address == self.l1_allowed.read(), 'Unauthorized l1 contract');
}
// ...
We can use execute
method to test the execution of the #[l1_handler]
function that is
not available through contracts dispatcher:
use snforge_std::L1Handler;
#[test]
fn test_l1_handler_execute() {
// ...
let data: Array<felt252> = array![1, 2];
let mut payload_buffer: Array<felt252> = ArrayTrait::new();
// Note the serialization here.
data.serialize(ref payload_buffer);
let mut l1_handler = L1HandlerTrait::new(
contract_address,
selector!("process_l1_message")
);
l1_handler.from_address = 0x123;
l1_handler.payload = payload.span();
l1_handler.execute().unwrap();
//...
}