Skip to content

Default delivery gas, float drain guard, LayerZero and Hyperlane fixes - #57

Merged
pegahcarter merged 5 commits into
mainfrom
fix/delivery-gas
Oct 8, 2026
Merged

pegahcarter merged 5 commits into
mainfrom
fix/delivery-gas

Conversation

@pegahcarter

Copy link
Copy Markdown
Contributor

Stacked on #54. Decisions D3 and D4 from the chain checks.

Measured on real lanes: CCIP, LayerZero, and Hyperlane quote 1,000,000 gas on every configured pair (deploy/CHECKS.md).

Fixes #50, #52, #55, #56. 775 tests; lint clean on both profiles; every transceiver under EIP-170.

OApp's _lzSend requires msg.value to equal the fee, so a LayerZero account
paying from its balance reverted. LzMessage.send and quote are public and
linked, which also frees 1.2 KB on every LayerZero transceiver. Every
binding now runs a send through a real transmitter.

Fixes #55
Without a gas attribute a bootstrap now gets 1,000,000 gas, a report
250,000, and a payload 200,000 (DeliveryGas), chosen from the payload so a
quote and its send agree. The provider defaults were 50,000 to 200,000
against a 590,000-650,000 account creation, and LayerZero's empty options
reverted on every endpoint.

Fixes #50
Fixes #52
A reporting destination pays the report from its float, so a zero
bootstrap fee let anyone drain it. The bootstrap and its quote now revert
NoBootstrapFee there, and a fuzz test pins that a delivery cut short at any
gas leaves the float untouched.
The Mailbox's fallback hook quotes 0 for a domain it does not route, and
the dispatch is never delivered. HyperlaneMessage's quote now reverts
NoHyperlaneRoute on zero and dispatch runs it first. The mock charges at
least 1 wei on a routed domain, so shared send tests pay their quote.

Fixes #56
Copilot AI balanced review requested due to automatic review settings October 7, 2026 09:21

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.

Copilot review overview

🔵 Needs a closer look

It reworks fee/gas-sensitive send and quote paths and the LayerZero payment flow across all five providers and changes bootstrap-acceptance behavior, so these cross-cutting, security-sensitive changes warrant final human review.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

This PR applies decisions D3/D4 from the chain checks (stacked on #54), introducing per-message-kind default destination gas and fixing three provider-specific delivery bugs across the native messaging bindings. It adds a DeliveryGas library (BOOTSTRAP 1,000,000 / REPORT 250,000 / PAYLOAD 200,000) and a new _defaultGas(payload) seam on OutboundBase, so a send and its quote always agree on gas chosen from the payload alone. It rewrites LayerZero's send/quote to pay the endpoint directly through a linked LzMessage library (fixing #55 and the empty-options revert #50), refuses zero Hyperlane quotes (#56), and guards against float drain by rejecting free bootstraps to reporting destinations.

Changes:

  • New DeliveryGas constants + _defaultGas virtual threaded through every provider's send/quote (replacing per-provider gateway defaults).
  • LayerZero binding pays the endpoint directly via linked LzMessage.send/quote with type-3 lzReceive options; Hyperlane refuses zero quotes (NoHyperlaneRoute); transceiver refuses zero-fee bootstraps to reporting chains (NoBootstrapFee).
  • New shared specs (ProviderTransmitterSendSpec, ProviderDefaultGasSpec), a float-drain fuzz test, and docs/spec updates.
File Description
src/​messaging/​DeliveryGas.sol New constants for bootstrap/report/payload default gas
src/​messaging/​outbound/​OutboundBase.sol New _defaultGas pure virtual
src/​messaging/​outbound/​TransmitterBase.sol _defaultGas → PAYLOAD
src/​messaging/​transceiver/​TransceiverBase.sol _defaultGas (report/bootstrap); NoBootstrapFee guard
src/​messaging/​Envelope.sol isReceiverReport helper
src/​protocols/​layerzero/​LzMessage.sol Public linked send/quote; type-3 default options
src/​protocols/​layerzero/​Lz{Transmitter,Transceiver}.sol Route through LzMessage; drop _payNative/_lzSend
src/​protocols/​hyperlane/​HyperlaneMessage.sol NoHyperlaneRoute on zero quote; defaultGas param
src/​protocols/​{ccip,op-stack,wormhole}/​* Thread defaultGas through send/quote, drop local defaults
test/​protocols/​* New ProviderGasFixture, send/default-gas specs, per-binding gas hooks
test/​ReceiverReport.t.sol, test/​InboundAuth.t.sol Float-drain fuzz test, NoBootstrapFee tests, fee wiring
docs/​*.md, deploy/​*.md, README.md Spec/doc updates for default gas, LZ/Hyperlane fixes, linking

I verified the core logic: the _defaultGas quote/send agreement holds per binding, the LayerZero type-3 options encoding matches OptionsBuilder's executor lzReceive layout and the fixtures decode it correctly, removed constants/imports have no lingering references, the NoBootstrapFee guard covers all bootstrap paths uniformly, and only TransmitterBase/TransceiverBase extend OutboundBase (both implement the new virtual). The one finding is a documentation omission (ProviderTransmitterSendSpec missing from the §8 suite table).


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

Comment thread docs/provider-spec.md
@pegahcarter
pegahcarter changed the base branch from docs/chain-checks to main October 8, 2026 04:56
@pegahcarter
pegahcarter merged commit 33041f6 into main Oct 8, 2026
1 check passed
@pegahcarter
pegahcarter deleted the fix/delivery-gas 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: empty options revert on every real endpoint, so default sends and every report fail

2 participants