Across Protocol OFT Integration Differential Audit

·

The following is a comprehensive security audit report on the Across Protocol, focusing specifically on its integration of the LayerZero Omnichain Fungible Token (OFT) standard. The analysis evaluates code changes, identifies security risks across severity levels, and provides actionable recommendations for improving robustness, maintainability, and trust assumptions. This report serves as an essential technical resource for developers, auditors, and stakeholders involved in cross-chain interoperability systems.

Summary of Findings

This differential audit was conducted on the Across Protocol's Solidity codebase between May 19 and May 23, 2025. A total of 32 issues were identified, categorized as follows:

No critical vulnerabilities were found. However, several medium and low-risk findings highlight areas for improvement in testing coverage, input validation, documentation clarity, and defensive programming practices.

👉 Discover how leading blockchain platforms ensure secure cross-chain transactions with advanced auditing techniques.

Audit Scope

The audit focused on changes introduced in the across-protocol/contracts repository at commit c5d75410, compared to base commit c88ac8ad. Two pull requests were also reviewed:

Key files under review included core components such as SpokePool.sol, AdapterStore.sol, OFTTransportAdapter.sol, and chain-specific adapters like Arbitrum_Adapter.sol.

System Overview

Across is a cross-chain liquidity protocol built around a central HubPool contract on Ethereum and per-chain SpokePool contracts deployed across supported Layer 2 networks. When users initiate cross-chain transfers, relayers provide instant liquidity on destination chains. These actions are later validated via data worker proofs, enabling settlement through the HubPool.

This audit examines the integration of LayerZero’s OFT standard into Across’s transport layer, allowing native bridging of OFT assets like USDT0. The new logic resides primarily in the OFTTransportAdapter library, used bidirectionally:

  1. L1 → L2 Transfers: Adapters (e.g., Arbitrum_Adapter) inherit from OFTTransportAdapterWithStore, leveraging a global AdapterStore to map tokens to their OFT messengers.
  2. L2 → L1 Transfers: Each SpokePool inherits OFTTransportAdapter, maintaining local token-to-messenger mappings.

The _transferViaOFT function ensures correct fee quoting, applies a maximum fee cap (FEE_CAP), and invokes the OFT messenger's send method. Importantly, this mechanism is used internally for protocol accounting—such as rebalancing liquidity or compensating relayers—not for direct user asset transfers.

PR #1031 removed legacy functionality that allowed setting output token addresses to zero to indicate equivalent tokens, due to unreliable routing logic. PR #1032 added support for EIP-7702 wallets receiving ETH directly instead of wrapped tokens like WETH.

Security Model and Trust Assumptions

SpokePool Administrator Trust

Administrators of each SpokePool are trusted to act honestly when configuring OFT messengers via the setOftMessenger function. There is no validation that the provided messenger actually corresponds to the intended token. A malicious or negligent admin could map a messenger to an incorrect or non-token address, risking fund loss or inconsistent behavior.

Additionally, changing messenger mappings while active transfers are pending may lead to reverts or inconsistencies. Admins also control relay configuration—potentially overriding preferred bridges like CCTP in favor of OFT—even after alternative routes become available.

AdapterStore Administrator Trust

The AdapterStore administrator must correctly configure IOFT messengers. Misconfigurations here could result in invalid cross-chain message paths.

LayerZero Backend Trust

The system implicitly trusts LayerZero's backend implementation:

EIP-7702 Wallet Assumptions

Support for EIP-7702 introduces new assumptions:

General Trust Assumptions

Security Model Note

The _is7702DelegatedWallet check uses OpenZeppelin’s deprecated isContract utility (v4.x), which has known limitations and is removed in v5.x. This poses potential risks given EIP-7702 wallets can mimic contract behavior.

Integration Considerations

Future integrations should consider:

Design Choices Analysis

Several architectural decisions impact flexibility and security:

👉 Learn how top DeFi protocols mitigate smart contract risks with real-time monitoring tools.

High Severity Issue

Failed Messenger Disables Standard Methods

A critical flaw exists where a malfunctioning OFT messenger can block all transfers for a given token on chains like Arbitrum. The transfer flow checks for an active messenger first; if present, it attempts _transferViaOFT. If this fails (e.g., due to a frozen route), the transaction reverts—and no fallback mechanism is triggered.

Since asset transfers and root hash propagation occur in the same call, failed OFT attempts also prevent root updates on spoke pools. This creates a potential deadlock: funds cannot be rebalanced until the messenger issue is resolved or manually disabled.

Although the team acknowledges this risk, they argue that silent fallbacks (e.g., using try-catch) would mask systemic issues requiring immediate human intervention. Their mitigation plan involves deploying patched adapters and backfilling missing balances post-resolution.

Medium Severity Issues

Insufficient Validation of Sent Amount

The _transferViaOFT function only validates the amount received (amountReceivedLD) matches the input _amount. It does not verify the amount sent (amountSentLD). This opens a theoretical attack vector where a malicious messenger could debit more than intended but deliver the correct amount, passing validation.

While mitigated by forced approvals, full protection requires validating both sent and received values.

Resolved in PR #1027.

Compromised Messengers Cannot Be Removed

There is no way to remove an OFT messenger once set—only to replace it. Setting it to zero reverts due to token validation checks. This limits response time during compromise scenarios.

Resolved in PR #1034.

Non-Zero ZRO Token Fee Causes Revert

If a messenger returns a non-zero ZRO token fee during quoteSend, the transfer may revert unexpectedly. The protocol assumes native gas payment but doesn't enforce zero ZRO fees.

Resolved in PR #1029.

Inadequate Test Coverage

Testing gaps include:

Comprehensive multi-layer testing (unit, integration, fork) is recommended.

Partially resolved in PR #1038.

Decimal Mismatch Causes Revert

If source and destination chains use different decimal precisions, the amount comparison in _transferViaOFT will fail unless conversion logic is applied.

📌 Unresolved — team relies on default OFT behavior where decimals are normalized.

Inconsistent Use of __gap

Storage slot management using __gap varies across contracts—some reserve 1000 slots regardless of actual usage, leading to potential layout conflicts. Proper documentation and standardization are advised.

Resolved in PR #1039.

EIP-7702 Wallets May Enable Reentrancy

When sending ETH to EIP-7702 wallets via low-level .call, full gas is forwarded, enabling complex callback logic. Though some functions are reentrancy-guarded, reducing gas limits or sending WETH instead could reduce risk.

📌 Unresolved — team considers protocol-wide reentrancy resilience necessary regardless.

Low Severity Issues

Missing Messenger Interface Validation

No EIP-165 interface check confirms that messengers support IOFT. Relying solely on .token() presence allows spoofing by non-OFT contracts.

Partially resolved — added .token() check in AdapterStore.

Misleading Documentation

Some comments inaccurately describe functionality (e.g., claiming only CCTP is used when OFT is also supported). Docs should reflect current behavior.

Partially resolved — updated Universal_Adapter docs.

Logic Not Fully Deprecated

OFT-related parameters are passed even in non-OFT chains, increasing unnecessary attack surface. Unused logic should be pruned or better isolated.

📌 Unresolved — team prioritizes upgrade simplicity.

Abstract Contracts Allow Direct State Modification

Public state variables like oftMessengers allow direct manipulation by child contracts, bypassing event emission and checks.

📌 Unresolved — visibility retained for Etherscan readability.

Missing Zero Address Checks

Several functions lack zero-address validation (e.g., _setMessenger, _setOftMessenger). While restricted to admins, explicit checks improve safety.

📌 Unresolved — deemed excessive by team.

Missing Docstrings

Many functions lack NatSpec documentation. Comprehensive docstring coverage is recommended for public APIs.

Partially resolved — added to key OFT-related files.

Floating Pragma Versions

Multiple files use floating Solidity versions (e.g., ^0.8.0). Fixed pragmas enhance compilation consistency.

📌 Unresolved — team prefers flexibility.

Inconsistent Pragma Directives

Files like AlephZero_SpokePool.sol use different versions than imported files (e.g., SpokePool.sol), risking compatibility issues.

📌 Unresolved — same rationale as above.

Adapter Implementation Could Be Misused

Adapters used via delegateCall could theoretically be exploited if accidentally holding funds. Direct invocation protection should be considered.

📌 Unresolved — considered low priority.

No Upgrade Path for Increased OFT Fees

The immutable OFT_FEE_CAP cannot be adjusted without redeploying contracts. While high caps reduce urgency, an upgrade mechanism or documented emergency plan is advisable.

📌 Unresolved — team expects rare need.

Fee-on-Transfer Tokens Revert

Tokens charging transfer fees will fail _transferViaOFT due to amount mismatch between input and receipt.

📌 Unresolved — team plans to support only non-fee tokens.

Dust Removal May Cause Revert

LayerZero’s _removeDust function may reduce received amounts slightly, causing validation failure unless input amounts are pre-rounded.

📌 Unresolved — rounding enforced via dataworker requirements.

Function Selectors Not Locked After Deprecation

Deleted functions leave their selectors reusable. Future functions with same selector could be unintentionally invoked.

Resolved in PR #1048.

Additional Notes & Observations

Zero Address Validation Bypass in SpokePool

Admins can set a messenger with a zero _token, potentially leading to edge-case failures.

📌 Unresolved — trust placed in admin discretion.

Typographical Errors

Spelling mistakes ("Desination", "trasnfer") found in comments.

Fixed in PR #1035.

Possible Duplicate Event Emissions

SetOftMessenger events fire even when value unchanged, creating noise.

📌 Unresolved — relies on admin discipline.

Redundant Getter Functions

_getOftMessenger duplicates auto-generated getter for public oftMessengers.

📌 Unresolved — retained for developer safety.

Overly Permissive Function Visibility

Functions like _setOftMessenger (internal) could be private; setOftMessenger (public) should be external.

Resolved in PR #1041.

Non-Explicit Imports

Global imports reduce clarity; named imports preferred.

Resolved in PR #1036.

Multiple Contracts Per File

Small libraries like MessengerTypes coexist with main contracts.

📌 Unresolved — team values compactness.

Missing Named Parameters in Mappings

Mappings lack named keys/values; newer syntax improves readability.

Resolved in PR #1040.

Missing Security Contact

No @custom:security-contact annotations present initially.

Resolved in PR #1037.

Custom Errors in Require Statements

Modern Solidity supports custom errors in require; replacing if-revert patterns improves gas efficiency and clarity.

Pending resolution based on Solidity version adoption.


Frequently Asked Questions (FAQ)

Q: What is the primary purpose of integrating LayerZero OFT into Across?
A: The integration enables native cross-chain movement of OFT-compliant tokens (like USDT0) for internal protocol operations—such as liquidity rebalancing and relayer compensation—without relying solely on third-party bridges.

Q: Why wasn’t a try-catch block used to handle failed OFT transfers?
A: The team believes silent fallbacks could hide critical failures requiring immediate attention. Instead, they prefer explicit failure alerts that trigger manual intervention and emergency patching procedures.

Q: Can users directly send tokens via the new OFT bridge?
A: No. The OFT transport layer is used internally by Across for accounting purposes. User deposits are still handled via relayers using traditional bridging mechanisms.

Q: How does Across handle decimal differences between chains?
A: Currently, it assumes consistent decimal handling via default OFT implementations. For tokens with custom decimal logic, manual rounding at the dataworker level is required to prevent reverts.

Q: Are there plans to improve test coverage?
A: Yes—partial improvements have been made with added unit and fork tests. A comprehensive testing strategy including fuzzing and integration tests is recommended for future releases.

Q: Is Across vulnerable to reentrancy through EIP-7702 wallets?
A: While low-level .call forwards full gas, the protocol assumes inherent reentrancy resistance across key functions. The team sees this as a systemic requirement rather than a per-feature fix.

👉 Explore cutting-edge blockchain security tools that help detect vulnerabilities before deployment.