LayerZero Integration
LayerZero is an omnichain messaging protocol that allows smart contracts in different blockchains to communicate directly. Not just token bridge — generalized message passing protocol. OFT (Omnichain Fungible Token), ONFT (Omnichain NFT), cross-chain governance, cross-chain liquidity protocols are built on it.
Key difference from classic bridges: no centralized custodian holding funds. There are DVN (Decentralized Verifier Networks) — independent verifiers confirming message delivery. Security through verifier independence.
V2 Architecture
LayerZero V2 (current version) simplified architecture compared to V1. Key components:
Endpoint — singleton contract in each network. All interactions go through it. Address same across all supported networks: 0x1a44076050125825900e736c501f859c50fE728c.
DVN (Decentralized Verifier Network) — set of verifiers reading source chain events and confirming them on destination. Developer chooses DVN configuration: minimum verifier count, required vs optional DVN. Google Cloud, Polyhedra, Axelar are DVN providers.
Executor — agent calling lzReceive on destination chain after DVN confirmation. Either LayerZero executor or custom.
OApp: Basic Integration Pattern
OApp (Omnichain Application) — base contract for any LayerZero integration:
import { OApp, Origin, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
contract CrossChainMessenger is OApp {
event MessageReceived(uint32 srcEid, bytes32 sender, string message);
constructor(address _endpoint, address _owner)
OApp(_endpoint, _owner) {}
// Send message to another network
function sendMessage(
uint32 dstEid, // destination endpoint ID (e.g., 30101 = Ethereum)
string calldata message,
bytes calldata options // gas limit on destination
) external payable {
bytes memory payload = abi.encode(message);
MessagingFee memory fee = _quote(dstEid, payload, options, false);
require(msg.value >= fee.nativeFee, "Insufficient fee");
_lzSend(dstEid, payload, options, fee, payable(msg.sender));
}
// Receive message (called by Executor)
function _lzReceive(
Origin calldata origin,
bytes32 /*guid*/,
bytes calldata payload,
address /*executor*/,
bytes calldata /*extraData*/
) internal override {
string memory message = abi.decode(payload, (string));
emit MessageReceived(origin.srcEid, origin.sender, message);
}
// Fee quote before sending
function quoteSend(
uint32 dstEid,
string calldata message,
bytes calldata options
) external view returns (MessagingFee memory) {
return _quote(dstEid, abi.encode(message), options, false);
}
}
options is important parameter. Encodes lzReceive gas limit on destination, drop ETH on destination address (airdrop), ordered delivery. Using OptionsBuilder:
bytes memory options = OptionsBuilder.newOptions()
.addExecutorLzReceiveOption(200000, 0); // 200k gas, 0 ETH airdrop
Insufficient gas limit → destination transaction reverts. Too much → user overpays. Need to profile actual gas consumption through tests.
OFT: Omnichain Fungible Token
OFT is main LayerZero use case. Instead of bridge (lock-and-mint) token exists natively in each network. On cross-chain transfer: burn on source + mint on destination. No custodian, no locked liquidity.
import { OFT } from "@layerzerolabs/oft-evm/contracts/OFT.sol";
contract MyOFT is OFT {
constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _owner
) OFT(_name, _symbol, _lzEndpoint, _owner) {}
}
This is literally the entire contract for basic OFT. Cross-chain transfer logic in parent OFT contract. Deploy on each target network and link via setPeer:
// On Ethereum: tell that counterparty on Arbitrum is this address
myOFT.setPeer(30110, bytes32(uint256(uint160(arbitrumOFTAddress))));
setPeer is critical security operation. Wrong peer specified — messages go to wrong contract or ignored.
OFTAdapter for Existing Tokens
If token already exists on one network and need cross-chain — use OFTAdapter. It lock-and-mint: original tokens locked in Adapter, OFT version minted on other networks:
import { OFTAdapter } from "@layerzerolabs/oft-evm/contracts/OFTAdapter.sol";
contract MyTokenAdapter is OFTAdapter {
constructor(address _token, address _lzEndpoint, address _owner)
OFTAdapter(_token, _lzEndpoint, _owner) {}
}
Deploy OFTAdapter on home chain, regular OFT on others. OFTAdapter is only custodian.
DVN Configuration and Security
DVN choice is key security decision. Configuration via ILayerZeroEndpointV2.setConfig:
// Set required DVN (need all) and optional DVN (need minimum threshold)
const configParams = [{
eid: dstEid,
configType: CONFIG_TYPE_ULN,
config: ethers.AbiCoder.defaultAbiCoder().encode(
['tuple(uint64,uint8,uint8,uint8,address[],address[])'],
[[
0, // confirmations (0 = default)
2, // requiredDVNCount
1, // optionalDVNCount
0, // optionalDVNThreshold
[dvn1, dvn2], // requiredDVNs
[dvn3] // optionalDVNs
]]
)
}]
await endpoint.setConfig(oappAddress, sendLibAddress, configParams)
Minimum safe configuration: 2 independent DVN in required. Compromise of one doesn't break system. Popular: LayerZero Labs DVN + Google Cloud DVN.
Testing and DevTools
Hardhat/Foundry: official @layerzerolabs/devtools-evm-hardhat packages contain tasks for wire (setPeer across all networks), DVN config, deploy.
Foundry testing: TestHelper from @layerzerolabs/test-devtools-evm-foundry allows testing cross-chain logic locally:
contract OFTTest is TestHelper {
function setUp() public virtual override {
super.setUp();
// Creates two endpoints and connects them
setUpEndpoints(2, LibraryType.UltraLightNode);
}
}
lzScan — official explorer for LayerZero messages. First tool for debugging cross-chain issues.
Typical Integration Issues
Insufficient gas on destination — lzReceive reverts from small gas limit in options. Solution: increase gas limit in OptionsBuilder, measured through tests.
Unordered delivery — messages may arrive out of send order by default. If order matters — use ordered delivery option (more expensive).
Fee estimation — _quote must be called immediately before transaction. Fee depends on destination gas price and changes.
Stack and Timelines
| Task | Tool |
|---|---|
| Smart contracts | Solidity + OApp/OFT SDK |
| Deploy and wire | Hardhat + lz-devtools |
| DVN configuration | LayerZero SDK + Dashboard |
| Testing | Foundry + TestHelper |
| Monitoring | lzScan |
Basic OFT integration (existing token + cross-chain transfer): 2-3 weeks. Includes contracts, deploy to 2-3 networks, DVN configuration, tests.
Cross-chain application with custom messaging logic, multiple networks, UI: 6-8 weeks. Audit recommended for OFT with significant liquidity — setPeer configuration critical.







