This repository aims at giving the detailed steps to locally work
on Starknet messaging with Anvil
and Katana
.
Please before start, install:
- scarb to build cairo contracts.
- starkli to interact with Katana.
- katana to install Katana, that belongs to dojo.
- foundry to interact with Anvil.
If it's your first time cloning the repository, please install forge dependencies as follow:
cd solidity
forge install
To setup Ethereum part for local testing, please follow those steps:
-
Start Anvil in a new terminal with the command
anvil
. -
In an other terminal, change directory into the solidity folder:
cd solidity # Copies the example of anvil configuration file into .env that is loaded by # foundry automatically. cp anvil.env .env # Ensure all variables are exported for the use of forge commands. source .env
-
Then, we will deploy the
StarknetMessagingLocal
contract that simulates the work done by theStarknetMessaging
core contract on Ethereum. Then we will deploy theContractMsg.sol
to send/receive message. To do so, run the following:forge script script/LocalTesting.s.sol:LocalSetup --broadcast --rpc-url ${ETH_RPC_URL}
-
Keep this terminal open for later use to send transactions on Anvil.
To setup Starknet contract, please follow those steps:
-
Update katana on the 1.0.9 version to use the latest RPC version:
starkliup dojoup -v 1.0.9
-
Then open a terminal and starts katana by passing the messaging configuration where Anvil contract address and account keys are setup:
katana --messaging anvil.messaging.json
Katana will now poll anvil logs exactly as the Starknet sequencer does on the
StarknetMessaging
contract on ethereum. -
In a new terminal, go into cairo folder and use starkli to declare and deploy the contracts:
cd cairo # To ensure starkli env variables are setup correctly. source katana.env # Scarb version is defined by `.tool-versions` # Or use `asdf install scarb 2.6.3` then `asdf local scarb 2.6.3`. scarb build starkli declare ./target/dev/messaging_tuto_contract_msg.contract_class.json --compiler-version 2.8.5 starkli deploy 0x0727468c660613faf8ebfbf149f05a9c3016702c362fccb69e9addb6ed1b934c \ --salt 0x1234
-
Keep this terminal open to later send transactions on Katana.
Once you have both dev nodes setup with contracts deployed, we can start interacting with them.
You can use starkli
and cast
to send transactions. But for the sake of simplicity, some scripts
are already written to replace cast
usage.
# In the terminal that is inside solidity folder you've used to run forge script previously (ensure you've sourced the .env file).
forge script script/SendMessage.s.sol:Value --broadcast --rpc-url ${ETH_RPC_URL}
forge script script/SendMessage.s.sol:Struct --broadcast --rpc-url ${ETH_RPC_URL}
You will then see Katana picking up the messages, and executing exactly as Starknet would do with Ethereum on testnet or mainnet.
Example here where you can see the details of the message and the event being emitted ValueReceivedFromL1
.
2025-01-08T21:47:12.431364Z INFO messaging: L1Handler transaction added to the pool. tx_hash=0x51ab77a5b4fb2188fd270c59f56916bfff4636ca4da8a0a95438e4c2287437c contract_address=0x26558b1ab48a5411f589d8ec66fdef5e6dd9c2f88f7f9274b88997444248aec selector=0x5421de947699472df434466845d68528f221a52fce7ad2934c5dae2e1f1cdc calldata=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512, 0x7b
2025-01-08T21:47:12.431377Z INFO pool: Transaction received. hash="0x51ab77a5b4fb2188fd270c59f56916bfff4636ca4da8a0a95438e4c2287437c"
2025-01-08T21:47:12.431398Z INFO messaging: Collected messages from settlement chain. msg_count=1
2025-01-08T21:47:12.432088Z TRACE executor: Transaction resource usage. usage="steps: 1385 | memory holes: 0 | pedersen_builtin: 12 | range_check_builtin: 19"
You can try to change the payload into the scripts to see how the contract on starknet behaves receiveing the message. Try to set both values to 0 for the struct. In the case of the value, you'll see a warning in Katana saying Invalid value
because the contract is expected 123
.
# In the terminal that is inside the cairo folder you've used to run starkli commands to declare (ensure you've sourced the katana.env file).
starkli invoke 0x26558b1ab48a5411f589d8ec66fdef5e6dd9c2f88f7f9274b88997444248aec \
send_message_value 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 1
starkli invoke 0x26558b1ab48a5411f589d8ec66fdef5e6dd9c2f88f7f9274b88997444248aec \
send_message_struct 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 1 2
You will then see Katana sending transactions to L1 to register the hashes of the messages,
simulating the work done by the StarknetMessaging
contract on L1 on testnet or mainnet.
You've to wait few seconds to see the confirmation of Katana that the messages has been sent to Anvil:
2025-01-08T21:48:17.978664Z INFO pool: Transaction received. hash="0x6aba5937d0ed0ce06486cc554898306cc7670cc85e82d6f39ee1c67bd0ab885"
2025-01-08T21:48:17.990643Z TRACE executor: Transaction resource usage. usage="steps: 5913 | memory holes: 53 | ec_op_builtin: 3 | pedersen_builtin: 20 | range_check_builtin: 136"
2025-01-08T21:48:17.991560Z INFO katana::core::backend: Block mined. block_number=5 tx_count=1
2025-01-08T21:48:18.449588Z INFO messaging: Collected messages from settlement chain. msg_count=0
2025-01-08T21:48:18.450702Z INFO messaging: Message sent to settlement layer. hash=0x37857b83ff01d1f42340b94d28c148939c6a050e6c2f25bfc425cf2d760b6553 from_address=0x26558b1ab48a5411f589d8ec66fdef5e6dd9c2f88f7f9274b88997444248aec to_address=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512 payload=0x1
2025-01-08T21:48:18.450738Z INFO messaging: Sent messages to the settlement chain. msg_count=1
2025-01-08T21:48:43.952621Z INFO pool: Transaction received. hash="0x6753e9c03461a3adeb944294bfb76d256934aeb9fc693082aab8c584445dc9a"
2025-01-08T21:48:43.964609Z TRACE executor: Transaction resource usage. usage="steps: 5937 | memory holes: 53 | ec_op_builtin: 3 | pedersen_builtin: 21 | range_check_builtin: 136"
2025-01-08T21:48:43.965437Z INFO katana::core::backend: Block mined. block_number=6 tx_count=1
2025-01-08T21:48:44.467839Z INFO messaging: Collected messages from settlement chain. msg_count=0
2025-01-08T21:48:44.471201Z INFO messaging: Message sent to settlement layer. hash=0x9a853bfe92bb85e2d377cba8df36ef8af1a1da1c8f8a9c2c966ad737e8f79e8b from_address=0x26558b1ab48a5411f589d8ec66fdef5e6dd9c2f88f7f9274b88997444248aec to_address=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512 payload=0x1, 0x2
2025-01-08T21:48:44.471214Z INFO messaging: Sent messages to the settlement chain. msg_count=1
To then consume the messages, you must send a transaction on Anvil, exactly as you would do on L1 for testnet or mainnet.
# In the terminal used for solidity / forge stuff.
# Try to run a first time, it should pass. Try to run a second time, you should have the
# error INVALID_MESSAGE_TO_CONSUME because the message is already consumed.
# Or try to change the payload value or address in the script, to see how the consumption
# of the message is denied.
forge script script/ConsumeMessage.s.sol:Value --broadcast -vvvv --rpc-url ${ETH_RPC_URL}
# Same here, try to consume a message sent with a struct inside.
forge script script/ConsumeMessage.s.sol:Struct --broadcast -vvvv --rpc-url ${ETH_RPC_URL}
And that's it!
With those examples, you can now try your own messaging contracts, mostly to ensure that your serialization/deserialization of arguments between solidity and cairo is done correctly.