LayerZero EndpointV2
The main entry point for all crosschain messaging operations on Solana. This program handles message routing, fee calculation, and configuration management.Message Routing
Core functions for sending and receiving messages between smart contracts.quote() - Get Fee Estimates
send() - Send Messages
clear() - Clear Payload
Why is clear() under Message Routing instead of Message Recovery?
On Solana, theclear() instruction placement differs from EVM:- EVM: The Endpoint handles clearing payloads directly during message delivery
- Solana: The OApp must explicitly call
clear()via CPI in itslzReceiveimplementation
clear() within their OApp’s message handling logic, giving them more control over the message lifecycle but requiring explicit implementation. See the architectural note at the top of this page for the complete message flow.sendCompose() - Send Compose Messages
clearCompose() - Clear Compose Message
Architectural Difference: lzReceive
If you’re looking forlzReceive or lzCompose instructions in the Endpoint (as you might expect from EVM), note that on Solana these are implemented directly in the OApp (e.g., OFT program) due to architectural differences.On Solana:- The executor calls
lzReceivedirectly on the OApp/OFT program - The OApp then makes a CPI (Cross-Program Invocation) call to the Endpoint’s
clearinstruction to validate and clear the payload - After validation, the OApp continues with its business logic (e.g., minting tokens)
_lzReceive function. On Solana, the flow is inverted with the OApp calling into the Endpoint.See the OFT lzReceive implementation for an example.Configuration Management
Functions for setting custom verification, execution, and pathway management.registerOapp() - Register OApp
setDelegate() - Set Delegate Address
setSendLibrary() - Configure Send Library
setReceiveLibrary() - Configure Receive Library
setConfig() - Set Configuration Parameters
initNonce() - Initialize Nonce
initVerify() - Initialize Verification
initSendLibrary() - Initialize Send Library
initReceiveLibrary() - Initialize Receive Library
initConfig() - Initialize Configuration
setReceiveLibraryTimeout() - Set Library Timeout
Message Recovery & Security
Functions for handling message exceptions, security threats, and recovery scenarios.burn() - Permanently Block Message
skip() - Skip Inbound Nonce
nilify() - Mark Message as Nil
withdrawRent() - Withdraw Rent
Status Checks
Functions for querying current configuration settings, library assignments, nonce tracking, and message states.eid() - Get Endpoint ID
endpointAdmin() - Get Endpoint Admin
oappDelegate() - Get OApp Delegate
outboundNonce() - Get Outbound Nonce
inboundNonce() - Get Inbound Nonce
Omnichain Fungible Token (OFT)
Omnichain Fungible Token (OFT) enables seamless crosschain token transfers. Deploy once and bridge your SPL tokens to any supported blockchain. Since Solana uses a rent-based storage model rather than EVM’s gas-per-bytecode deployment costs, and has no restrictive contract size limits (like EVM’s 24KB limit), we can include all of these extensions in the same program. While some OFT instances may not utilize all features (like fees or rate limits), having them built-in provides maximum flexibility without the contract splitting requirements common in EVM development.Default OFT Program
For Solana Mainnet, we use PENGU OFT as the default example:- Program:
EfRMrTJWU2CYm52kHmRYozQNdF8RH5aTi3xyeSuLAX2Y - OFT Store:
qMNo1RFo11J9ZLGuq7dVmWAssuCZaNsSamk8g2q4UZA
lzReceive Implementation
ThelzReceive instruction is implemented here in the OFT program (not in the Endpoint). This is a key architectural difference from EVM:- On Solana, executors call
lzReceivedirectly on the OApp/OFT - The OFT program then makes a CPI call to the Endpoint’s
clearinstruction to validate the message - After successful validation, the OFT continues with its logic (minting tokens, updating balances, etc.)
Send Tokens
quoteSend() - Get Transfer Fees
quoteOft() - Get Detailed Transfer Quote
send() - Transfer Tokens
lzReceiveTypes() - Get Receive Account Types
lzReceive() - Receive Tokens
Token Details
The OFT Store account is a Program Derived Address (PDA), not the token mint itself. This account stores essential OFT related state variables.oftAdmin() - Get OFT Admin
tokenMint() - Get Token Mint
tokenEscrow() - Get Token Escrow
sharedDecimals() - Get Shared Decimals
decimalConversionRate() - Get Decimal Conversion Rate
oftVersion() - Get OFT Version
tvlLd() - Get Total Value Locked
isPaused() - Check Pause State
defaultFeeBps() - Get Default Fee
Peer Configuration
These functions read peer-specific configuration from PeerConfig accounts:peerAddress() - Get Peer Address
enforcedOptions() - Check Enforced Options
peerFeeBps() - Get Peer Fee
outboundRateLimiter() - Check Outbound Rate Limiter
inboundRateLimiter() - Check Inbound Rate Limiter
Management Functions
initOft() - Initialize OFT
setPeerConfig() - Configure Remote Peer
setOftConfig() - Update OFT Settings
setPause() - Pause/Unpause OFT
withdrawFee() - Withdraw Collected Fees
Events and Errors
Endpoint Events
Key events emitted by the Endpoint program during crosschain operations.PacketSentEvent - Message Sent
Emitted when a packet is sent through the endpoint. Contains the encoded packet data and execution options for tracking crosschain messages.PacketVerifiedEvent - Message Verified
Emitted when an inbound message has been verified by the DVNs and is ready for execution. Indicates the message passed all security checks.PacketDeliveredEvent - Message Delivered
Emitted when a message is successfully delivered to the destination OApp. This confirms the crosschain transaction completed.ComposeSentEvent - Compose Message Queued
Emitted when a compose message is queued for sequential execution after the primary message. Used for complex multi-step operations.ComposeDeliveredEvent - Compose Message Executed
Emitted when a compose message is successfully executed. Indicates the secondary operation completed successfully.DelegateSetEvent - Delegate Updated
Emitted when an OApp delegate is set or changed. The delegate can configure settings on behalf of the OApp.SendLibrarySetEvent - Send Library Configured
Emitted when the send library is configured for a specific destination. Tracks library changes for outbound messages.ReceiveLibrarySetEvent - Receive Library Configured
Emitted when the receive library is configured for a specific source. Tracks library changes for inbound messages.OAppRegisteredEvent - OApp Registration
Emitted when a new OApp is registered with the endpoint. This establishes the OApp’s ability to send and receive messages.Endpoint Errors
Common errors returned by the Endpoint program.Unauthorized - Permission Denied
Thrown when the caller lacks required permissions for the operation. Only authorized addresses can perform certain actions.InvalidNonce - Nonce Mismatch
Thrown when processing a message with an invalid nonce. Ensures messages are processed in the correct sequential order.InvalidSender - Unauthorized Sender
Thrown when receiving a message from an unauthorized sender. Only configured peers can send messages to the OApp.InvalidReceiver - Invalid Destination
Thrown when the specified receiver address is invalid or not configured properly for the destination chain.LzTokenUnavailable - LayerZero Token Error
Thrown when LayerZero token operations fail or tokens are unavailable for fee payment.OFT Events
Key events emitted by the OFT program during token operations. (Source)OFTSent - Tokens Sent Crosschain
Emitted when tokens are sent to another chain. Contains the message GUID, destination chain ID, sender and recipient addresses, and the amount sent in both shared and local decimals.OFTReceived - Tokens Received
Emitted when tokens are received from another chain. Contains the source chain ID, sender address, and the amount received after decimal conversion.OFT Errors
Common errors returned by the OFT program. (Source)Paused - OFT Operations Paused
Thrown when attempting operations while the OFT is paused. No transfers can be initiated until unpaused by the designated unpauser.SlippageExceeded - Insufficient Received Amount
Thrown when the received amount after crosschain transfer falls below the minimum acceptable amount due to decimal conversions or fees.RateLimitExceeded - Transfer Rate Limit Hit
Thrown when a transfer exceeds the configured rate limits for the peer connection. Wait for the rate limit window to reset.InvalidOptions - Invalid Message Options
Thrown when the provided LayerZero message options are invalid or incompatible with the OFT configuration.InvalidAmount - Invalid Transfer Amount
Thrown when the transfer amount is zero, exceeds limits, or is otherwise invalid for the operation.InvalidPeer - Peer Not Configured
Thrown when attempting to interact with a destination chain where no peer OFT has been configured. Use setPeerConfig() first.Usage Tips
Getting Started
- Connect Your Wallet: Click “Connect Phantom Wallet” to connect your Solana wallet
- Select Network: Choose between Solana Mainnet and Devnet
- Custom RPC (Optional): If you encounter rate limits (403 errors), add a custom RPC URL:
Common Workflows
Sending Tokens Crosschain (OFT)
- Initialize your OFT with
initOft() - Configure peers with
setPeerConfig() - Get a quote with
quoteOft()orquoteSend() - Send tokens with
send()
Setting Up Messaging (Endpoint)
- Register your OApp with
registerOapp() - Initialize nonce tracking with
initNonce() - Set up libraries with
initSendLibrary()andinitReceiveLibrary() - Configure DVNs/executors with
setConfig() - Get quotes with
quote()and send messages withsend()
Troubleshooting
- 403 Errors: Use a custom RPC URL instead of public endpoints
- “Account does not exist”: Ensure all required accounts have been initialized
- “Invalid arguments”: Check that byte arrays are properly formatted (0x prefix)
- Simulation failures: This playground uses simplified encoding - use official SDKs for production