Why
The product is not a bridge, and reading it as one hides the interesting part. LayerZero is a message layer: an application inherits OApp and sends an arbitrary payload from its contract on one chain to its contract on another, with OFT and ONFT as the token-shaped wrappers over that. The design choice underneath is that verification is modular — a Decentralized Verifier Network set that the application selects and composes, rather than a security assumption fixed by the protocol.
That modularity is genuinely better and it relocates a decision onto you, silently. A protocol with fixed security has one trust assumption and everyone inherits it, for good and ill. A protocol with selectable verification has as many assumptions as there are applications — and an application that never makes the choice does not escape it, it accepts a default. The failure is not that the default is bad. It is that the default is invisible: nothing in the repository says who verifies your messages, so the most security-relevant fact about the integration is absent from every code review of it.
Which is why the practical habit is worth more than the tutorial. Run the config query after the first deploy and paste the output where people read it. The question who am I trusting right now has an answer at every moment; the only variable is whether anyone has written it down. Compare third-party-blast-radius, which asks the same thing about dependencies, and storage-collision-admin-takeover, where the load-bearing fact also lived outside any single file.
The second trap is a silent one, and worth stating precisely. The sender pre-pays destination gas by encoding it in options. Under-provision it and the send looks successful while execution fails on the destination — a message that appears delivered and did nothing. Any production path over this needs a retry story written before it is needed, because the failure does not announce itself at the call site.
And the strategic note belongs to a different card. ATLAS moves LayerZero from infrastructure to market infrastructure, which changes who its competitors are — no longer Wormhole and Axelar but chains that own an exchange. headless-exchange-engines carries that argument. What belongs here is the engineering residue: the four-way split ATLAS publishes — matching, clearing, settlement, risk — is a usable module boundary, and separating risk from settlement is the part worth copying whether or not the product is ever used.
How it works
The first contact, and the three lines that matter
Endpoint address, destination EID, and options encoding — everything else is ordinary Solidity.
import { OApp, Origin, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { OptionsBuilder } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";
contract PingPong is OApp {
using OptionsBuilder for bytes;
string public lastMessage;
constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {}
function send(uint32 dstEid, string calldata text) external payable {
bytes memory payload = abi.encode(text);
// destination gas is chosen by the sender — the UX core and the first trap
bytes memory options = OptionsBuilder.newOptions()
.addExecutorLzReceiveOption(80_000, 0);
_lzSend(dstEid, payload, options, MessagingFee(msg.value, 0), payable(msg.sender));
}
function _lzReceive(
Origin calldata, bytes32, bytes calldata payload, address, bytes calldata
) internal override {
lastMessage = abi.decode(payload, (string));
}
}
npx hardhat lz:oapp:config:get # read the defaults — this is the trust assumption
npx hardhat lz:oapp:send --dst-eid 40161 --text "hello"
The two traps, and why both are silent
| Trap | What it looks like | Why nothing catches it |
|---|---|---|
| Under-provisioned destination gas | Send succeeds, destination execution fails | The failure is on another chain; the call site returns fine |
| Untouched DVN configuration | Everything works | Nothing in the repo names the verifier, so review has nothing to object to |
Both are the same class: a decision made by omission, recorded nowhere. The habit that fixes both costs one command and one paragraph in a README.
Cost, and where it varies
| Component | Paid to | Note |
|---|---|---|
| Source-chain gas | The source chain | Ordinary |
| Destination execution gas | Pre-paid at send | Quoted at send time — a congested destination moves the quote a lot |
| DVN fees | The verifier set you chose | Varies with the set; a reason to know what it is |
| Protocol subscription | — | None |
What to take for a settlement design
Use the message layer, minimise the bridge. For a market whose collateral sits on several chains, the common first design is to make the collateral token omnichain — and the principle worth keeping is that settlement finality happens on exactly one chain, with everything else restricted to display and deposit paths. A message layer widens what you can reach; it does not widen where truth lives. And ATLAS's module boundary — risk separated from settlement — is worth copying independently of the product, because it is the split plumbing-skills-buyback argues most systems never make.
Where it lands in Jayverse
- Bridge: write down who you trust, in the README. If Bridge ever adds a third-party message layer, run the verifier-config query right after first deploy and paste the trust assumption into the repo, so it isn't an invisible default the way an unset DVN config is.
- Bridge/relayer: name destination-gas underprovisioning as a failure mode. Write the retry story for "message sent, destination execution failed silently" before the relayer ships — the send looking successful while nothing happened is exactly the trap this piece describes.
- OFA: copy the four-way module split. Keep matching, clearing, settlement and risk as separate boundaries in the auction design, with risk kept out of settlement specifically, independent of whether ATLAS itself is ever used.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| trap | 함정 · 설계 안에 숨어 있는 위험 요소를 가리킴. "That is the real feature and the real trap" |
| inherit | (위험이나 가정을) 물려받다, 승계하다 · 기본값을 그대로 받아들이는 것. "everyone inherits it, for good and ill" |
| relocate a decision onto | 결정을 ~에게로 떠넘기다/이전시키다 · 책임 소재가 은연중에 옮겨지는 것. "relocates a decision onto you, silently" |
| under-provision | (자원을) 부족하게 할당하다 · 가스비 등을 충분히 안 잡는 것. "Under-provision it and the send looks successful" |
| the call site | 함수 호출이 일어나는 지점 · 에러가 겉으로 드러나지 않는 위치를 설명할 때. "the call site returns fine" |
| residue | (핵심 논의 후) 실무적으로 남는 것 · 전략 논의를 걷어내고 남는 엔지니어링적 교훈. "the engineering residue" |
| module boundary | 모듈 경계 · 시스템을 나누는 구획 기준. "a usable module boundary" |
| widen (what you can reach) | (도달 범위를) 넓히다, 확장시키다 · 메시지 레이어가 닿을 수 있는 대상을 늘리는 것. "widens what you can reach" |
| by omission | 하지 않음으로써, 누락에 의해 · 결정을 내리지 않아서 생기는 문제를 가리킴. "a decision made by omission" |
| pre-pay | 선지급하다 · 목적지 체인의 가스비를 미리 지불하는 구조. "pre-pays destination gas by encoding it in options" |
| OApp | 옴니체인 애플리케이션(Omnichain Application) · LayerZero 메시지를 주고받는 컨트랙트의 기본 단위. "Deploy one OApp and send a single message" |
| OFT | 옴니체인 대체가능토큰(Omnichain Fungible Token) · OApp 위에 얹은 토큰 전용 래퍼. "with OFT and ONFT as the token-shaped wrappers" |
| ONFT | 옴니체인 NFT(Omnichain Non-Fungible Token) · OApp 위에 얹은 NFT 전용 래퍼. "OFT and ONFT as the token-shaped wrappers" |
| DVN | 분산 검증자 네트워크(Decentralized Verifier Network) · 애플리케이션이 직접 선택·조합하는 메시지 검증 집합. "a Decentralized Verifier Network set that the application selects" |
| EID | 엔드포인트 식별자(Endpoint ID) · 목적지 체인을 가리키는 LayerZero의 체인 식별 값. "Endpoint address, destination EID, and options encoding" |
| ATLAS | LayerZero의 시장 인프라 제품명 · 매칭·청산·결제·리스크 4단 구조를 공개한 신규 서비스. "ATLAS moves LayerZero from infrastructure to market infrastructure" |
| ZRO | LayerZero의 네이티브 토큰 · 수수료 일부가 바이백·소각에 쓰이는 토큰. "part of fees routed to ZRO buyback and burn" |
| DTCC, ARK Invest, ICE | 예탁결제·투자·거래소 분야의 미국 기관들 · ATLAS 발표에 이름이 언급된 전통 금융 기관들. "Citadel Securities, DTCC, ARK Invest and ICE named" |