Mocking interaction with L1#
Abstract#
In order to test interaction with L1 contracts, devnet client provides a way to mock the L1 interaction. Before taking a look at the examples, please get familiar with the devnet postman docs and messaging mechanism:
L1 network setup#
First of all you should deploy messaging contract on ethereum network or load the existing one.
from starknet_py.devnet_utils.devnet_client import DevnetClient
client = DevnetClient(node_url="http://127.0.0.1:5050")
# Deploying the messaging contract on ETH network
# e.g. anvil eth devnet https://github.com/foundry-rs/foundry/tree/master/crates/anvil
await client.postman_load(network_url="http://127.0.0.1:8545")
L2 -> L1#
Deploying L2 interaction contract#
Interaction with L1 is done by sending a message using send_message_to_l1_syscall function. So in order to test it, you need to deploy a contract that has this functionality. Example contract: l1_l2.cairo
from starknet_py.contract import Contract
# Address of your contract that is emitting messages
contract_address = "0x12345"
contract = await Contract.from_address(address=contract_address, provider=account)
await contract.functions["increase_balance"].invoke_v3(
user=account.address,
amount=100,
l1_resource_bounds=ResourceBounds(
max_amount=50000, max_price_per_unit=int(1e12)
),
)
# Invoking function that is emitting message
await contract.functions["withdraw"].invoke_v3(
user=account.address,
amount=100,
l1_address=eth_account_address,
l1_resource_bounds=ResourceBounds(
max_amount=50000, max_price_per_unit=int(1e12)
),
)
Consuming message#
After deploying the contract, you need to flush the messages to the L1 network. And then you can consume the message on the L1 network.
# Sending messages from L2 to L1.
flush_response = await client.postman_flush()
message = flush_response.messages_to_l1[0]
message_hash = await client.consume_message_from_l2(
from_address=message.from_address,
to_address=message.to_address,
payload=message.payload,
)
L1 -> L2#
Sending mock transactions from L1 to L2 does not require L1 node to be running.
await client.send_message_to_l2(
l2_contract_address=contract_address,
entry_point_selector=get_selector_from_name("deposit"),
l1_contract_address="0xa000000000000000000000000000000000000001",
payload=[account.address, 100],
nonce="0x0",
paid_fee_on_l1="0xfffffffffff",
)
# Sending messages from L1 to L2.
flush_response = await client.postman_flush()