Abstract
To maintain accounting consistency with the Aave vault on the main chain, the OverlayerWrapCore contract overrides the underlying cross-chain logic after inheriting the OFT standard and introduces a totalBridgedOut variable to track outbound token amounts. However, due to the lack of environment filtering (i.e., block.chainid == hubChainId) in the overridden logic, this arithmetic—intended only for the source (hub) chain—is indiscriminately executed across all non-hub (spoke) chains.
On non-hub (spoke) chains, totalBridgedOut is initialized to 0 at deployment. Any attempt to bridge tokens to a spoke chain via LayerZero will forcibly trigger the operation 0 - amountReceivedLD (an unsigned integer subtracting a positive value). Due to Solidity 0.8+ built-in underflow protection, all minting transactions on the destination spoke chain will revert with Panic(0x11) without exception.
Root Cause Analysis
In OverlayerWrapCore.sol, the following override of the core LayerZero OFT.sol function exists (Line 538–544):
// OverlayerWrapCore.sol: overridden _credit function
function _credit(
address to_,
uint256 amountLD_,
uint32 srcEid_
) internal virtual override returns (uint256 amountReceivedLD) {
// [1] Standard logic: mint (credit) tokens on the destination chain
amountReceivedLD = super._credit(to_, amountLD_, srcEid_);
// [2] Critical vulnerable logic: unconditionally subtract from totalBridgedOut
totalBridgedOut -= amountReceivedLD;
}
The developer explicitly states in the source comments (Line 533–534):
@notice Tracks tokens returning to the hub chain from cross-chain transfers @dev Mints tokens on the destination chain; this override decrements totalBridgedOut to keep the effective supply invariant consistent.
In other words, the increment/decrement logic of totalBridgedOut is designed specifically for the hub (main) chain. However, the developer overlooked the fact that this contract is also deployed directly on multiple non-hub (spoke) chains.
In the core design of OverlayerWrapCore, all subnetworks must mint tokens via the hub chain and then bridge them cross-chain. Therefore, contracts deployed on spoke chains neither perform minting independently nor initiate outbound transfers.
As a result, for all contracts operating on spoke chains, totalBridgedOut is initialized and remains strictly uint256(0) from deployment onward.
Deployment Configuration:
OverlayerWrap with totalBridgedOut = 0. As the hub chain, it can mint tokens directly using collateral.OverlayerWrap with totalBridgedOut = 0. Due to the onlyHubChain modifier, Arbitrum cannot mint tokens natively.Cross-Chain Execution:
send() transaction on the Ethereum hub chain to transfer 100,000 OverlayerWrap tokens to Arbitrum._debit: tokens are burned, and totalBridgedOut on Ethereum increases from 0 to 100,000 (expected behavior).Spoke Chain Failure (Vulnerability Triggered):
The LayerZero relayer delivers the cross-chain message to the Arbitrum spoke chain and invokes the target contract.
The Arbitrum contract executes _credit, where super._credit attempts to mint 100,000 tokens to Alice.
Immediately after, the logic proceeds to the unconditional statement:
totalBridgedOut -= 100000;
Since totalBridgedOut on Arbitrum is initialized to 0, the operation uint256(0) - uint256(100000) triggers an arithmetic underflow.
Result:
Panic(0x11) (underflow), causing the transaction to revert.