Interactive Solana Program Playground
Test LayerZero Solana programs directly from your browser. Build and send instructions without writing code. Explore key program instructions for message fee calculation, sending, receiving, and configuration management.
For production use, please use the official SDKs which provides proper type-safe instruction builders:
All instructions shown in this playground are real methods available in the LayerZero Solana programs today:
- Endpoint Program: Source Code
- OFT Program: Source Code
We only document OApp-relevant instructions, excluding admin-only functions. State variables are clearly marked as direct account data reads, not instructions.
LayerZero EndpointV2
The main entry point for all cross-chain 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
quote(sendLibraryProgram: AccountInfo, sendLibraryConfig: AccountInfo, defaultSendLibraryConfig: AccountInfo, sendLibraryInfo: AccountInfo, endpoint: AccountInfo, nonce: AccountInfo, sender: Pubkey, dstEid: u32, receiver: bytes32, message: bytes, options: bytes, payInLzToken: bool)send() - Send Messages
send(sender: Signer, sendLibraryProgram: AccountInfo, sendLibraryConfig: AccountInfo, defaultSendLibraryConfig: AccountInfo, sendLibraryInfo: AccountInfo, endpoint: AccountInfo, nonce: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, dstEid: u32, receiver: bytes32, message: bytes, options: bytes, nativeFee: u64, lzTokenFee: u64)clear() - Clear Payload
clear(signer: Signer, oappRegistry: AccountInfo, nonce: AccountInfo, payloadHash: AccountInfo, endpoint: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, receiver: Pubkey, srcEid: u32, sender: bytes32, nonce: u64, guid: bytes32, message: bytes)On Solana, the clear() 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
This architectural difference means Solana developers need to implement the CPI call to 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
sendCompose(from: Signer, payer: Signer, composeMessage: AccountInfo, systemProgram: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, to: Pubkey, guid: bytes32, index: u16, message: bytes)clearCompose() - Clear Compose Message
clearCompose(to: Signer, composeMessage: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, from: Pubkey, guid: bytes32, index: u16, message: bytes)If you're looking for lzReceive 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)
This is different from EVM where the Endpoint calls back to the OApp's _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
registerOapp(payer: Signer, oapp: Signer, oappRegistry: AccountInfo, systemProgram: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, delegate: Pubkey)setDelegate() - Set Delegate Address
setDelegate(oapp: Signer, oappRegistry: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, delegate: Pubkey)setSendLibrary() - Configure Send Library
setSendLibrary(signer: Signer, oappRegistry: AccountInfo, sendLibraryConfig: AccountInfo, messageLibInfo: AccountInfo?, eventAuthority: AccountInfo, program: AccountInfo, sender: Pubkey, eid: u32, newLib: Pubkey)setReceiveLibrary() - Configure Receive Library
setReceiveLibrary(signer: Signer, oappRegistry: AccountInfo, receiveLibraryConfig: AccountInfo, messageLibInfo: AccountInfo?, eventAuthority: AccountInfo, program: AccountInfo, receiver: Pubkey, eid: u32, newLib: Pubkey, gracePeriod: u64)setConfig() - Set Configuration Parameters
setConfig(signer: Signer, oappRegistry: AccountInfo, messageLibInfo: AccountInfo, messageLib: AccountInfo, messageLibProgram: AccountInfo, oapp: Pubkey, eid: u32, configType: u32, config: bytes)initNonce() - Initialize Nonce
initNonce(delegate: Signer, oappRegistry: AccountInfo, nonce: AccountInfo, pendingInboundNonce: AccountInfo, systemProgram: AccountInfo, localOapp: Pubkey, remoteEid: u32, remoteOapp: bytes32)initVerify() - Initialize Verification
initVerify(payer: Signer, nonce: AccountInfo, payloadHash: AccountInfo, systemProgram: AccountInfo, srcEid: u32, sender: bytes32, receiver: Pubkey, nonce: u64)initSendLibrary() - Initialize Send Library
initSendLibrary(delegate: Signer, oappRegistry: AccountInfo, sendLibraryConfig: AccountInfo, systemProgram: AccountInfo, sender: Pubkey, eid: u32)initReceiveLibrary() - Initialize Receive Library
initReceiveLibrary(delegate: Signer, oappRegistry: AccountInfo, receiveLibraryConfig: AccountInfo, systemProgram: AccountInfo, receiver: Pubkey, eid: u32)initConfig() - Initialize Configuration
initConfig(delegate: Signer, oappRegistry: AccountInfo, messageLibInfo: AccountInfo, messageLib: AccountInfo, messageLibProgram: AccountInfo, oapp: Pubkey, eid: u32)setReceiveLibraryTimeout() - Set Library Timeout
setReceiveLibraryTimeout(signer: Signer, oappRegistry: AccountInfo, receiveLibraryConfig: AccountInfo, messageLibInfo: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, receiver: Pubkey, eid: u32, lib: Pubkey, expiry: u64)Message Recovery & Security
Functions for handling message exceptions, security threats, and recovery scenarios.
burn() - Permanently Block Message
burn(signer: Signer, oappRegistry: AccountInfo, nonce: AccountInfo, payloadHash: AccountInfo, endpoint: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, receiver: Pubkey, srcEid: u32, sender: bytes32, nonce: u64, payloadHash: bytes32)skip() - Skip Inbound Nonce
skip(signer: Signer, oappRegistry: AccountInfo, nonce: AccountInfo, pendingInboundNonce: AccountInfo, payloadHash: AccountInfo, endpoint: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, receiver: Pubkey, srcEid: u32, sender: bytes32, nonce: u64)nilify() - Mark Message as Nil
nilify(signer: Signer, oappRegistry: AccountInfo, nonce: AccountInfo, pendingInboundNonce: AccountInfo, payloadHash: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, receiver: Pubkey, srcEid: u32, sender: bytes32, nonce: u64, payloadHash: bytes32)withdrawRent() - Withdraw Rent
withdrawRent(admin: Signer, endpoint: AccountInfo, receiver: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, amount: u64)Status Checks
Functions for querying current configuration settings, library assignments, nonce tracking, and message states.
eid() - Get Endpoint ID
eid(endpoint: AccountInfo)endpointAdmin() - Get Endpoint Admin
endpointAdmin(endpoint: AccountInfo)oappDelegate() - Get OApp Delegate
oappDelegate(oappRegistry: AccountInfo)outboundNonce() - Get Outbound Nonce
outboundNonce(nonce: AccountInfo)inboundNonce() - Get Inbound Nonce
inboundNonce(nonce: AccountInfo)Omnichain Fungible Token (OFT)
Omnichain Fungible Token (OFT) enables seamless cross-chain 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.
For Solana Mainnet, we use PENGU OFT as the default example:
- Program:
EfRMrTJWU2CYm52kHmRYozQNdF8RH5aTi3xyeSuLAX2Y - OFT Store:
qMNo1RFo11J9ZLGuq7dVmWAssuCZaNsSamk8g2q4UZA
You can replace these with your own OFT deployment addresses.
The lzReceive 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.)
The flow is: Executor → OFT.lzReceive → Endpoint.clear (via CPI) → Continue OFT logic
Send Tokens
quoteSend() - Get Transfer Fees
quoteSend(oftStore: AccountInfo, peer: AccountInfo, tokenMint: AccountInfo, dstEid: u32, to: bytes32, amountLd: u64, minAmountLd: u64, options: bytes, composeMsg: bytes?, payInLzToken: bool)quoteOft() - Get Detailed Transfer Quote
quoteOft(oftStore: AccountInfo, peer: AccountInfo, tokenMint: AccountInfo, dstEid: u32, to: bytes32, amountLd: u64, minAmountLd: u64, options: bytes, composeMsg: bytes?, payInLzToken: bool)send() - Transfer Tokens
send(signer: Signer, peer: AccountInfo, oftStore: AccountInfo, tokenSource: AccountInfo, tokenEscrow: AccountInfo, tokenMint: AccountInfo, tokenProgram: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, dstEid: u32, to: bytes32, amountLd: u64, minAmountLd: u64, options: bytes, composeMsg: bytes?, nativeFee: u64, lzTokenFee: u64)lzReceiveTypes() - Get Receive Account Types
lzReceiveTypes(oftStore: AccountInfo, tokenMint: AccountInfo, srcEid: u32, sender: bytes32, nonce: u64, guid: bytes32, message: bytes, extraData: bytes)lzReceive() - Receive Tokens
lzReceive(payer: Signer, peer: AccountInfo, oftStore: AccountInfo, tokenEscrow: AccountInfo, toAddress: AccountInfo, tokenDest: AccountInfo, tokenMint: AccountInfo, mintAuthority: AccountInfo?, tokenProgram: AccountInfo, associatedTokenProgram: AccountInfo, systemProgram: AccountInfo, eventAuthority: AccountInfo, program: AccountInfo, srcEid: u32, sender: bytes32, nonce: u64, guid: bytes32, message: bytes, extraData: bytes)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
oftAdmin(oftStore: AccountInfo)tokenMint() - Get Token Mint
tokenMint(oftStore: AccountInfo)tokenEscrow() - Get Token Escrow
tokenEscrow(oftStore: AccountInfo)sharedDecimals() - Get Shared Decimals
sharedDecimals(oftStore: AccountInfo)decimalConversionRate() - Get Decimal Conversion Rate
decimalConversionRate(oftStore: AccountInfo)oftVersion() - Get OFT Version
oftVersion()tvlLd() - Get Total Value Locked
tvlLd(oftStore: AccountInfo)isPaused() - Check Pause State
isPaused(oftStore: AccountInfo)defaultFeeBps() - Get Default Fee
defaultFeeBps(oftStore: AccountInfo)Peer Configuration
These functions read peer-specific configuration from PeerConfig accounts:
peerAddress() - Get Peer Address
peerAddress(peerConfig: AccountInfo)enforcedOptions() - Check Enforced Options
enforcedOptions(peerConfig: AccountInfo)peerFeeBps() - Get Peer Fee
peerFeeBps(peerConfig: AccountInfo)outboundRateLimiter() - Check Outbound Rate Limiter
outboundRateLimiter(peerConfig: AccountInfo)inboundRateLimiter() - Check Inbound Rate Limiter
inboundRateLimiter(peerConfig: AccountInfo)The PeerConfig account is a PDA (Program Derived Address) derived from:
- OFT program ID
- Seeds:
[b"peer_config", oft_store.key().as_ref(), &dst_eid.to_be_bytes()]
You'll need to derive this address using the OFT store account and the destination chain's endpoint ID.
Management Functions
initOft() - Initialize OFT
initOft(payer: Signer, oftStore: AccountInfo, lzReceiveTypesAccounts: AccountInfo, tokenMint: AccountInfo, tokenEscrow: Signer, tokenProgram: AccountInfo, systemProgram: AccountInfo, oftType: u8, admin: Pubkey, sharedDecimals: u8, endpointProgram: Pubkey?)setPeerConfig() - Configure Remote Peer
setPeerConfig(admin: Signer, peer: AccountInfo, oftStore: AccountInfo, systemProgram: AccountInfo, remoteEid: u32, configType: u8, configData: bytes)setOftConfig() - Update OFT Settings
setOftConfig(admin: Signer, oftStore: AccountInfo, configType: u8, configData: bytes)setPause() - Pause/Unpause OFT
setPause(signer: Signer, oftStore: AccountInfo, paused: bool)withdrawFee() - Withdraw Collected Fees
withdrawFee(admin: Signer, oftStore: AccountInfo, tokenMint: AccountInfo, tokenEscrow: AccountInfo, tokenDest: AccountInfo, tokenProgram: AccountInfo, feeLd: u64)Events and Errors
Endpoint Events
Key events emitted by the Endpoint program during cross-chain operations.
PacketSentEvent - Message Sent
Emitted when a packet is sent through the endpoint. Contains the encoded packet data and execution options for tracking cross-chain 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 cross-chain 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.