Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Static Deadline Management in DEX Adapters Threatens Protocol's Fee Distribution Mechanism and Revenue Stream

Summary

The DEX adapter implementation in Zaros uses a static, owner-controlled deadline for all swap operations across UniswapV2 and UniswapV3 integrations. This design creates a single point of failure where all DEX operations could potentially fail if the deadline becomes stale, requiring active management to maintain system functionality.

Vulnerability Details

The vulnerability manifests in the interaction between FeeDistributionBranch.sol's fee conversion mechanism and the underlying DEX adapters.

// In FeeDistributionBranch.sol
function convertAccumulatedFeesToWeth(address asset) public {
// ... validation checks
_performMultiDexSwap(customSwapPath[asset], assetAmount);
}

_performMultiDexSwap in FeeDistributionBranch.sol: This function iterates through multiple swaps, creating a SwapExactInputSinglePayload for each hop but doesn't include a per-transaction deadline:
FeeDistributionBranch.sol#L402-L439

function _performMultiDexSwap(
AssetSwapPath.Data memory swapPath,
uint256 assetAmount
)
internal
returns (uint256)
{
// ...
for (uint256 i; i < assets.length - 1; i++) {
// ...
SwapExactInputSinglePayload memory swapCallData = SwapExactInputSinglePayload({
tokenIn: assets[i],
tokenOut: assets[i + 1],
amountIn: amountIn,
recipient: address(this)
});
// ...
}
// ...
}

The deadline is instead managed globally in BaseAdapter.sol and set by the owner:
BaseAdapter.sol#L153-L162

uint256 public deadline;
function setDeadline(uint256 _deadline) public onlyOwner {
// ...
deadline = _deadline;
// ...
}

Both UniswapV2Adapter.sol and UniswapV3Adapter.sol contracts inherit from BaseAdapter and rely on this single deadline value for swap execution via the swap router.
UniswapV2Adapter.sol#L96-L102

// UniswapV2Adapter.sol
uint256[] memory amountsOut = IUniswapV2Router02(uniswapV2SwapStrategyRouterCache).swapExactTokensForTokens({
amountIn: swapPayload.amountIn,
amountOutMin: amountOutMinimum,
path: path,
to: swapPayload.recipient,
deadline: deadline
});
// UniswapV3Adapter.sol
return swapRouter.exactInputSingle(
IUniswapV3RouterInterface.ExactInputSingleParams({
tokenIn: swapPayload.tokenIn,
tokenOut: swapPayload.tokenOut,
fee: feeBps,
recipient: swapPayload.recipient,
deadline: deadline,
amountIn: swapPayload.amountIn,
amountOutMinimum: amountOutMin,
sqrtPriceLimitX96: 0
})
);

The core issue is that deadline parameter is static and there is no automatic deadline refresh mechanism in the protocol. It is managed through a single owner-controlled variable rather than dynamically calculated per transaction.

Fee conversion relies on custom swap paths configured via configureAssetCustomSwapPath. Each hop in the conversion process uses the same static deadline. Keeper operations for fee conversion can fail if deadline expires. This creates a dependency on active management that could affect system availability.

Impact

Keeper operations to convert accumulated fees to WETH may fail due to expired deadline

Tools Used

Manual Review

Recommendations

Implement automatic deadline calculation in BaseAdapter and use it while performing multi dex swaps:

function getDeadline() public view returns (uint256) {
return block.timestamp + DEADLINE_WINDOW;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

0xshoonya Submitter
5 months ago
inallhonesty Lead Judge
5 months ago
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.