Skip to content

fix(ccv): derive Lombard verifier adapter lookup from the padded token form - #2229

Open
SashaMIT wants to merge 1 commit into
smartcontractkit:mainfrom
SashaMIT:fix/lombard-verifier-token-decode-consistency
Open

SashaMIT wants to merge 1 commit into
smartcontractkit:mainfrom
SashaMIT:fix/lombard-verifier-token-decode-consistency

Conversation

@SashaMIT

@SashaMIT SashaMIT commented Aug 6, 2026

Copy link
Copy Markdown

Summary

In LombardVerifier._validatePayload, the supported-token lookup key is derived with an explicit bytes20() conversion, while the token-identity comparison two lines below uses Internal._leftPadBytesToBytes32:

bytes32 expected = Internal._leftPadBytesToBytes32(expectedToken);  // whole value, left-padded
address localToken = address(bytes20(expectedToken));               // FIRST 20 bytes

An explicit bytes20() conversion of a dynamic bytes value keeps the leftmost 20 bytes. For a 32-byte left-padded address (the canonical abi.encode(address) form CCIP uses for EVM addresses) that yields 12 zero bytes plus the first 8 bytes of the real address, so:

  • the adapter lookup silently misses,
  • expected stays the padded token address,
  • but forwardToVerifier deposited through the adapter, so the bridge payload's toToken is the adapter,
  • and verification reverts with InvalidToken.

Net effect: valid transfers for adapter-configured tokens cannot be verified when destTokenAddress arrives in the 32-byte form, with no length guard on the field to rule that representation out.

Fix

Derive the lookup key from the already-padded bytes32:

address localToken = address(uint160(uint256(expected)));

so the adapter lookup and the identity comparison resolve the same address for every input length up to 32 bytes.

Test plan

  • New regression test test_verifyMessage_32ByteEncodedTokenWithAdapter: 32-byte abi.encoded destTokenAddress with a configured adapter; reverts with InvalidToken before this change, passes after
  • Full LombardVerifier suite green: 68/68 (forge test --match-path "*LombardVerifier*")

Made with Cursor

Made with Cursor

…n form

_validatePayload derived the supported-token lookup key with an explicit
bytes20() conversion, which keeps the FIRST 20 bytes of a dynamic bytes
value. For a 32-byte left-padded token address (the canonical CCIP
encoding for EVM addresses) that truncates to the padding, so the
adapter override silently misses while the identity comparison two
lines below still uses the full left-padded value. The bridge payload
for an adapter-routed token encodes the adapter as toToken, so such
messages revert with InvalidToken on verification: valid transfers for
adapter-configured tokens cannot be verified.

Derive the lookup key from the already-padded bytes32 instead
(address(uint160(uint256(expected)))), so the lookup and the identity
comparison agree for every input length up to 32 bytes. Adds a
regression test covering a 32-byte-encoded destTokenAddress with a
configured adapter (fails with InvalidToken before this change).

Signed-off-by: SashaMIT <sash.t.mitchell@gmail.com>
@SashaMIT
SashaMIT requested a review from a team as a code owner August 6, 2026 17:30

This branch has not been deployed

No deployments
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