Skip to content

feat(layerzero): pin one DVN on pathways whose default is dead - #58

Merged
pegahcarter merged 3 commits into
mainfrom
feat/lz-dvn
Oct 8, 2026
Merged

pegahcarter merged 3 commits into
mainfrom
feat/lz-dvn

Conversation

@pegahcarter

Copy link
Copy Markdown
Contributor

Stacked on #57. Decision D1 from the chain checks (#51).

Every LayerZero pathway touching zkSync defaults to the dead DVN, which refuses every message.

  • Transceivers follow LayerZero's defaults, except that setDvn(eid, dvn) pins one DVN for a pathway, both directions, on today's default libraries, write-once. A transceiver can be born with it for the governor home's eid (initialize(..., governorHomeDvn), LZ_GOVERNOR_HOME_DVN in DeployLz), since the bootstrap that creates its owner arrives over that pathway.
  • The transceiver's delegate is fixed. OApp's setDelegate (not virtual) is refused in _checkOwner; before this, the governor's account could reassign the delegate and reconfigure any pathway.
  • Receivers get the transceiver's DVN for their home's eid at creation, before their payload runs, and change it only by their own payload (they have no owner).
  • Transmitters: the owner names itself delegate through OApp's existing setDelegate and configures the endpoint directly; no new function.
  • LzMessage.pinSendDvn / pinReceiveDvn are public and linked. Every LayerZero transceiver stays under EIP-170 (Tron's has 399 bytes left).

Verified on an Ethereum fork: test/fork/LzDvnFork.t.sol (skipped without ETH_RPC_URL) shows Ethereum to zkSync refusing the quote on the default and quoting once LayerZero Labs' DVN is pinned. The zkSync side cannot be forked (EraVM) and needs a zkSync Sepolia run; tracked in docs/todo.md.

Docs: spec R6.4, deploy/CHECKS.md §5 (with each chain's LayerZero Labs DVN), deploy/README.md, provider-research §8.

782 tests pass, 1 skipped (the fork test); lint clean on both profiles.

Closes #51

zkSync's pathways default to LayerZero's dead DVN. A transceiver can now pin
a DVN per eid, both ways and write-once, and at birth for the governor
home's pathway; receivers inherit it for their home's eid at creation and
change it only by their own payload. The transceiver's delegate is fixed,
so its config changes only through setDvn. A fork test (skipped without
ETH_RPC_URL) shows the pinned zkSync pathway quoting on Ethereum.

Refs #51
Copilot AI balanced review requested due to automatic review settings October 7, 2026 19:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It alters the LayerZero message-authentication security model with irreversible write-once on-chain DVN/delegate configuration whose motivating zkSync path cannot be verified in the test suite, so it warrants human sign-off.

0 open findings

What changed in this PR

This PR resolves issue #51, where every LayerZero pathway touching zkSync Era defaults to the LayerZero "dead DVN" that refuses all messages, and the transceiver — being its own, immovable delegate — previously had no way to reconfigure. It adds a write-once DVN-pinning mechanism so a pathway can be pinned to a single real DVN (both send and receive, on today's default libraries) while otherwise preserving LayerZero's defaults. It fits into the src/protocols/layerzero/ binding, extending the shared LzMessage library (linked, to stay under EIP-170) and the transceiver/receiver initializers.

Changes:

  • Adds setDvn(eid, dvn) (owner-gated, write-once, pins both directions) plus birth-time pinning via a new governorHomeDvn initializer arg; LzMessage.pinSendDvn/pinReceiveDvn perform the endpoint setSendLibrary/setReceiveLibrary/setConfig calls.
  • Fixes the transceiver's delegate: OApp's setDelegate is refused in _checkOwner (DelegateIsFixed); receivers inherit dvnOf[homeEid] at creation; transmitters' owners self-delegate instead.
  • Updates all initializer call sites, deploy script/library (LZ_GOVERNOR_HOME_DVN), the mock endpoint, tests (incl. a skip-gated Ethereum fork test), and docs (spec R6.4, CHECKS §5, README, research, todo).
File Description
src/​protocols/​layerzero/​LzTransceiver.sol Adds dvnOf, setDvn/_pinDvn, governorHomeDvn init arg, and _checkOwner override refusing setDelegate.
src/​protocols/​layerzero/​LzMessage.sol Adds UlnConfig, pinSendDvn/pinReceiveDvn/_onlyDvn and ULN config constants.
src/​protocols/​layerzero/​LzReceiver.sol Adds homeDvn init arg; pins receive-side DVN for the home eid at creation.
src/​protocols/​layerzero/​LzDivergentTransceiver.sol Threads governorHomeDvn through zkSync/Tron initializers; _checkOwner overrides resolve to LzTransceiverBase.
script/​DeployLz.s.sol, script/​deploy/​LzDeploy.sol Pass LZ_GOVERNOR_HOME_DVN; _checkHome asserts the pinned home DVN.
test/​protocols/​layerzero/​MockLzEndpoint.sol Adds library/config surface with oapp-or-delegate authorization.
test/​protocols/​layerzero/​LzTransceiver.t.sol, LzBinding.t.sol, LzFixture.sol New DVN/delegate/receiver/transmitter tests; updated init signatures.
test/​fork/​LzDvnFork.t.sol New skip-gated fork test of Ethereum→zkSync quote before/after pinning.
test/​{CloneDerivation,DestinationNaming,deploy/​DeployChecks,deploy/​ChainConfig}.t.sol Updated initializer call sites for the new arg.
deploy/​CHECKS.md, deploy/​README.md, docs/​{provider-spec,provider-research,todo}.md Document the pinning mechanism, per-chain DVNs, and verification status.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@pegahcarter
pegahcarter changed the base branch from fix/delivery-gas to main October 8, 2026 04:56
@pegahcarter
pegahcarter merged commit 929ab3b into main Oct 8, 2026
1 check passed
@pegahcarter
pegahcarter deleted the feat/lz-dvn branch October 13, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LayerZero: zkSync pathways need DVN config the transceiver cannot set

2 participants