What is an OApp on Starknet?
An OApp on Starknet is a Cairo contract that:- Integrates with LayerZero via the OAppCoreComponent
- Sends messages through the Endpoint’s
sendfunction - Receives messages by implementing the
OAppHookstrait - Manages peers (trusted remote OApps on other chains)
Differences from EVM OApps
Installation
Step 1: Install LayerZero Cairo Contracts
Step 2: Configure Scarb.toml
Tool versionsUse Scarb 2.14.0 and Starknet Foundry 0.53.0. Mismatched versions can cause class hash mismatch errors during
sncast declare.Step 3: Create Project Structure
lib.cairo
Step 4: Configure snfoundry.toml
Create asnfoundry.toml with your account name and RPC URL. See Starknet Guidance for the full configuration reference and RPC version compatibility notes.
Deployment
Step 1: Build
target/dev/ by default.
Step 2: Declare
Step 3: Deploy
Network flagIf you set
url in snfoundry.toml, omit --network (sncast will reject it).Step 4: Verify
Step 5: Configure
Bytes32 EncodingPeer addresses are stored as
Bytes32 (a struct containing a u256). For EVM addresses (20 bytes), left-pad with zeros to 32 bytes.Calldata format for set_peer(eid: u32, peer: Bytes32):eid- endpoint ID as hex (e.g.,0x7595= 30101 for Ethereum Mainnet)peer.value.low- lower 128 bits of the padded addresspeer.value.high- upper 128 bits of the padded address
--calldata with space-separated hex values (not --arguments) for complex types like Bytes32.Working Example: Minimal OApp
A minimal OApp on Starknet:Required Components
OAppCoreComponent
The core LayerZero integration:OwnableComponent
OpenZeppelin’s ownership management:How OApp Messaging Works
Peer Configuration: Establishing Trust
Peers must be set bidirectionally for two OApps to communicate:Setting a Peer
TheOAppCoreComponent provides set_peer automatically when you embed OAppCoreImpl. You call it directly on your deployed contract:
Peer Address Format
Peers are stored asBytes32 for cross-VM compatibility:
Bidirectional Setup
Sending Messages
Step 1: Quote the Fee
Step 2: Build Options
Options specify execution parameters on the destination chain:Step 3: Send the Message
The_lz_send function handles fee payment internally. It expects the caller to have approved the OApp contract (not the endpoint) to spend their tokens. The function will:
- Transfer tokens from caller to the contract
- Approve the endpoint to spend the tokens
- Send the message via the endpoint
Complete Send Example
Receiving Messages
Implementing OAppHooks
TheOAppHooks trait defines how your OApp handles incoming messages:
Origin Verification
The OAppCore ensures only the Endpoint can calllz_receive and that the sender matches the trusted peer:
Events
Standard OApp Events
DelegateSet EventThe
DelegateSet event is emitted by the Endpoint contract (not the OApp) when set_delegate is called. Listen for it on the Endpoint address, not your OApp.Custom Events
Add your own events for tracking:Network Addresses
Next Steps
- OFT Overview - Token transfers
- Protocol Overview - Message lifecycle
- Configuration Guide - DVN setup
- Troubleshooting - Common errors