Skip to content

feat: OffRamp-derived CCV selection for live CCIP 2.0 fork routing - #67

Closed
magiodev-cll wants to merge 1 commit into
smartcontractkit:devrel-205/cl-local-v3from
magiodev-cll:feat/v3-offramp-derived-ccvs
Closed

magiodev-cll wants to merge 1 commit into
smartcontractkit:devrel-205/cl-local-v3from
magiodev-cll:feat/v3-offramp-derived-ccvs

Conversation

@magiodev-cll

Copy link
Copy Markdown

Context

Follow-up to #54. The refresh (#66) has landed on devrel-205/cl-local-v3, and this branch is now rebased onto the resulting merge commit, so the diff is only this work. It supersedes the fork-side draft magiodev-cll#3.

Why

#54's V2 routing decodes MessageV1 locally to derive the CCV list and to call executeSingleMessage(MessageV1, ...). Today's live lanes encode finality as bytes4 (chainlink-ccip #1898, 2026-04-08) while the pinned dependency still decodes uint16, so live V2 fork tests fail with InvalidDataLength(MESSAGE_FINAL_OFFSET).

This ports the approach we validated in production rehearsal: let the destination OffRamp select the CCVs (getCCVsForMessage(encodedMessage)) and execute the raw encoded message through the permissionless execute entrypoint. No local message decoding, so routing keeps working as the wire format evolves.

What

  • V2VerificationMode.OFFRAMP_DERIVED (new, fork-only):
    • destination chain resolved from the CCIPMessageSent topics, no MessageV1 decode
    • required CCV list read from the destination OffRamp
    • permissionless execute(encodedMessage, ccvs, verifierResults, 0), candidates tried in reverse router order, processed only on success
  • IOffRampExecuteV2 gains the bytes-based execute entrypoint (next to executeSingleMessage).
  • Test helpers ported onto V3: getOffRampForLane, setLaneDefaultCCVs, IOffRampSourceConfigV2Fork, and the CCVNoOpVerifier test double (src/test/ccip/CCVNoOpVerifier.sol), so a lane's default CCV can be mocked with a no-op on a fork.
  • New e2e: test/e2e/ccip/CCIPv2Fork.t.sol — Sepolia → Arbitrum Sepolia message + token transfer over the live 2.0 lane, with the no-op CCV as the single counterfactual (validation, quorum walk, token release/mint, receiver call all production code).

Evidence

  • forge test --match-path "test/unit/**" — 42/42
  • forge test --match-path "test/e2e/ccip/CCIPv2Fork.t.sol" (public RPCs) — 2/2
    • Note: the other live-lane V2 fork tests in test/e2e/ccip still fail on the pinned codec path (STRICT/SYNTHETIC_ONLY modes); they pass once the dependency bump lands or once switched to OFFRAMP_DERIVED.
  • Downstream rehearsal consuming this work: smartcontractkit/utb-avalanche-bridge#52 (e2e 5/5; its pin needs bumping from the pre-rebase 917cd63 to 1a4c265).

Adds V2VerificationMode.OFFRAMP_DERIVED: the required CCV list comes from the
destination OffRamp (getCCVsForMessage) and the raw encoded message is executed
through the permissionless execute entrypoint, so fork routing does not depend
on the local MessageV1 codec. Keeps V2 fork tests working when the on-chain wire
format moves ahead of the pinned chainlink-ccip (today: finality uint16 -> bytes4,
chainlink-ccip #1898).

- CCIPLocalSimulatorFork: new mode + _routeV2MessageOffRampDerived /
  _executeOffRampDerivedV2; destination chain resolved from the event topics with
  no MessageV1 decode; falls back across candidate OffRamps and marks processed
  only on success.
- Fork-only test helpers ported onto V3: getOffRampForLane, setLaneDefaultCCVs,
  IOffRampSourceConfigV2Fork, plus the CCVNoOpVerifier test double.
- IOffRampExecuteV2 gains the bytes-based execute entrypoint.
- New e2e: test/e2e/ccip/CCIPv2Fork.t.sol (Sepolia -> Arb Sepolia message and
  token transfer over the live 2.0 lane with a no-op default CCV).
- Unit 42/42; live e2e 2/2 with public RPCs.
@magiodev-cll

Copy link
Copy Markdown
Author

superseded by #68

@magiodev-cll
magiodev-cll deleted the feat/v3-offramp-derived-ccvs branch September 23, 2026 14:41
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.

1 participant