Clave
Clagg Adapters

Diff audit of Clagg's refactored adapter architecture, covering the new Swapper contract and ERC4626-based Morpho and Spark integrations.
report id
0570
category
Infra & Wallets
language
Solidity
final report
July 1, 2025
lines of code
1954
Content

Download audit report

1

Executive Summary

This document presents the results of a security review conducted by Nethermind Security for Clave Clagg-contracts. The Clave Clagg contracts offer a streamlined interface for users to deposit funds and earn DeFi rewards from the protocols that are integrated with the Clave protocol. Clagg smart contracts can automatically handle reward compounding by claiming accrued rewards and reinvesting.

This audit focuses on recent code refactoring and enhancements. Previously, a single entry point contract managed admin operations via Timelock. These responsibilities are now distributed among individual adapters, which the protocol owner can add to or update. The Swapper contract has replaced the Syncswap contract for token swapping. The Swapper contract now integrates with UniswapV2/V3 and AerodromeV2/V3 for swapping tokens. Additionally, a new ERC4626-based adapter has been introduced to facilitate integrations with Morpho and Spark protocols.

This is a diff audit comprising 1954 lines of the Solidity code. Unlike a full-fledged audit, the focus was on the changes between two commits for the files listed in the scope.

Audit assessment
Audit TypeDiff Audit
Initial ReportJune 27, 2025
Final ReportJuly 1, 2025
Repositoriesclagg-contracts
Initial Commita1ade32b1f4
Final Commitcae1fd46a3
DocumentationCode natspec
Documentation AssessmentLow
Test Suite AssessmentHigh
Total findings
4
Fixed
4
Acknowledged
0
Mitigated
0
Unresolved
0

Findings by severity

  • Critical0
  • High0
  • Medium1
  • Low2
  • Informational0
  • Best Practices1

2

Audited Files

#ContractLoCCommentsRatioBlankTotal
1ClaggMain.sol573256.1%17106
2IncentiveVault.sol451124.4%1571
3interfaces/IIncentiveVault.sol824300.0%537
4interfaces/IClaveRegistry.sol55100.0%212
5interfaces/IAdapter.sol2989306.9%22140
6interfaces/aave/IRewards.sol1653331.2%574
7interfaces/aave/IPool.sol2982282.8%8119
8interfaces/ztake/IZtake.sol9888.9%623
9interfaces/venus/IRewardsDistributor.sol47175.0%112
10interfaces/venus/IVToken.sol8787.5%520
11interfaces/venus/IComptroller.sol47175.0%112
12interfaces/merkl/IDistributor.sol47175.0%112
13adapters/ClaggMainAdapter.sol422764.3%1483
14adapters/ClaggMerklAdapter.sol11981.8%323
15adapters/Clagg4626BaseAdapter.sol54916.7%1982
16adapters/ClaggSparkAdapter.sol27933.3%743
17adapters/ClaggAaveAdapter.sol1032423.3%35162
18adapters/ClaggBaseAdapter.sol35310529.7%107565
19adapters/ClaggVenusAdapter.sol731520.5%29117
20adapters/ClaggZtakeAdapter.sol54916.7%1982
21adapters/ClaggRescueAdapter.sol412048.8%1475
22adapters/ClaggMorphoAdapter.sol27933.3%743
23utils/Constants.sol22100.0%15
24utils/EnforceOwnership.sol16743.8%427
25utils/Swapper.sol1905126.8%33274
26utils/ETHWrapper.sol141178.6%429
27utils/TokenCallbackHandler.sol29620.7%540
28utils/interfaces/IAerodromeV2Router.sol25832.0%538
29utils/interfaces/IWETH.sol6583.3%314
30utils/interfaces/IAerodromeV3Router.sol26519.2%536
31utils/interfaces/IUniswapV2Router.sol13538.5%220
32utils/interfaces/IUniswapV3Router.sol25520.0%535
33libraries/LinkedList.sol271103.7%38319
34libraries/Errors.sol431944.2%971
35libraries/WETHHelper.sol201680.0%440
36libraries/protocols/AaveAddressHelper.sol322681.2%563
37libraries/protocols/MerklAddressHelper.sol161593.8%334
38libraries/protocols/VenusAddressHelper.sol322784.4%564
39libraries/storage/MainStorageLib.sol1342921.6%41204
40libraries/storage/BaseStorageLib.sol57610.5%1275
Total195482142.0%5263301

Note: This is a diff audit, primarily focused on comparing the changes in the files between two versions of the code base. It was not a full-fledged audit of all the files listed above.

4

System Overview

The ClaggMain contract is the primary entry point contract. The design utilizes the delegate call mechanism to enable flexible architecture.

Logic is implemented in adapter contracts. The protocol owner can add, remove, or replace adapters, hence provisions for incremental addition of functionality.

The adapter contracts can be categorized into two main classes. Admin Adapters facilitate owner-specific administrative operations, such as configuring FeeVaults, Incentive Vaults, registries, rescuing tokens or even managing adapters. The second class consists of Protocol Integration Adapters, which are specifically designed to interact with DeFi protocols. These adapters abstract the unique interaction flows of each DeFi protocol, providing a unified and generic interface for seamless integration.

The Swapper contract is responsible for swapping of tokens. It acts as a routing mechanism, extracting routing instructions from call data parameters to direct calls to UniswapV2/V3 and AerodromeV2/V3 protocols for token swapping. This implementation also incorporates chain-specific routing based on the current blockchain id. Furthermore, to support protocols like Morpho and Spark, a new base adapter extending ERC4626 has been integrated into the protocol.

The ownership tracking is now moved into the main storage. Additionally, an operator role was also added.

The following diagram provides a high-level illustration of the Clave - Clave Protocol.

Clave Clagg-Contracts
Fig. 2: Clave Clagg-Contracts

4.1 Clagg Admin Components

4.2 ClaggMain

The ClaggMain contract was refactored to separate administrative responsibilities into separate adapters. The ClaggMain is now an entry point contract with no knowledge about admin functions making it a generic entry point contract. As a result of the reorganization, the smart contracts in the following were revised.

  • MainStorageLib: The variables are added to the store registry, owner, operator and rescueToken in the main storage contract. All the ownership verification was based on the owner in the MainStorageLib contract.
  • ClaggMainAdapter: An earlier version of ClaggMainAdapter was handling the rescue token related admin operations. The refactoring was done to assign adapter management related responsibilities to ClaggMainAdapter.
  • ClaggRescueAdapter: Token Rescue related responsibilities were segregated into the ClaggRescueAdapter. This includes admin functions such adding or removing rescue tokens, as well as performing the rescue operation.

4.3 Protocol Integration Components

4.4 ClaggBaseAdapter

The ClaggBaseAdapteris the main interfacing contract that implements the common functionality for all protocol adapters. This contract handles the swapping related functionality, and hence was revised for the new swapper contract.

  • Clagg4626BaseAdapter: A new Base Adapter that extends ClaggBaseAdapter and interacts with pools based on ERC4626 vault standard.
  • ClaggMorphoAdapter: A new adapter to integrate with Morpho protocol extending Clagg4626BaseAdapter . In the case of Morpho protocol, rewards cannot be claimed on chain automatically as the rewards are distributed through the Merkle tree. Clave protocol has an off-chain component that claims rewards once a week, which are then distributed to the depositors.
  • ClaggSparkAdapter: A new adapter to integrate with Spark protocol extending Clagg4626BaseAdapter. Spark Protocol does not support reward tokens.

4.5 Swapper

Swapper contract replaces the SyncSwaper contract in the earlier version. The Swapper contract interacts with UniswapV2/V3 and AerodromeV2/V3. The Swapper is chainid aware to retrieve the correct addresses for UniswapV2/V3 and AerodromeV2/V3 based on the current chain id.

5

Risk Rating Methodology

The risk rating methodology used by Nethermind Security follows the principles established by the OWASP Foundation. The severity of each finding is determined by two factors: Likelihood and Impact.

Likelihood measures how likely the finding is to be uncovered and exploited by an attacker. This factor will be one of the following values:

  1. High: the issue is trivial to exploit and has no specific conditions that need to be met;
  2. Medium: the issue is moderately complex and may have some conditions that need to be met;
  3. Low: the issue is very complex and requires very specific conditions to be met.

When defining the likelihood of a finding, other factors are also considered. These can include but are not limited to motive, opportunity, exploit accessibility, ease of discovery, and ease of exploit.

Impact is a measure of the damage that may be caused if an attacker exploits the finding. This factor will be one of the following values:

  1. High: the issue can cause significant damage, such as loss of funds or the protocol entering an unrecoverable state;
  2. Medium: the issue can cause moderate damage, such as impacts that only affect a small group of users or only a particular part of the protocol;
  3. Low: the issue can cause little to no damage, such as bugs that are easily recoverable or cause unexpected interactions that cause minor inconveniences.

When defining the impact of a finding, other factors are also considered. These can include but are not limited to data and state integrity, loss of availability, financial loss, and reputation damage. After defining the likelihood and impact of an issue, the severity is determined according to the table below.

Impact / LikelihoodLowMediumHigh
HighMediumHighCritical
MediumLowMediumHigh
LowInfo / Best PracticesLowMedium
UndeterminedUndeterminedUndeterminedUndetermined

To address issues that do not fit a High, Medium or Low severity, Nethermind Security also uses three more finding severities: Informational, Best Practices, and Undetermined.

  1. Informational findings do not pose any risk to the application, but they carry some information that the audit team intends to pass to the client formally;
  2. Best Practice findings are used when some piece of code does not conform with smart contract development best practices;
  3. Undetermined findings are used when we cannot predict the impact or likelihood of the issue.

6

Issues

6.1 ETH can never be rescued from ClaggRescueAdapter

FileFix commitTypeStatus
/adapters/ClaggRescueAdapter.solbff7c30MediumFixed

The ClaggRescueAdapter contract includes a rescue function designed to allow recovery of tokens from the contract after they have been whitelisted. The function aims to support rescuing both ERC20 tokens and ETH:

function rescue(address token, uint256 amount) external onlyOperatorOrOwner {
1==> if (token == address(0)) revert Errors.INVALID_TOKEN();

if (!MainStorageLib.rescueTokenExists(token)) revert Errors.INVALID_RESCUE_TOKEN();

2==> if (token == address(0)) {
(bool success,) = payable(msg.sender).call{value: amount}("");
if (!success) revert Errors.ETH_TRANSFER_FAILED();
} else {
IERC20(token).safeTransfer(msg.sender, amount);
}
}

There is a contradictory logic in the implementation:

  • First (1), the function rejects a zero address token and immediately reverts with INVALID_TOKEN error;
  • However, later (2), it attempts to handle the case where token == address(0) by sending ETH to the caller;

Due to the initial check, the ETH rescue code is unreachable, effectively preventing ETH from ever being rescued from the contract.

Recommendation

Consider removing or modifying the initial zero address check (highlighted at point 1) to allow the function to handle ETH rescue correctly

6.2 Storage collision between ClaggRescueAdapter and ClaggMainAdapter

The ClaggMain contract acts as the protocol’s entry point and delegates all calls to appropriate adapter contracts via a fallback function:

fallback() external payable {
uint256 dataLength = msg.data.length - 20;
address adapter = address(bytes20(msg.data[dataLength:]));

if (!MainStorageLib.adapterExists(adapter)) revert Errors.INVALID_ADAPTER();

bytes calldata data = msg.data[:dataLength];

==> (bool success, bytes memory result) = adapter.delegatecall(data);
if (success) {
assembly {
return(add(result, 32), mload(result))
}
}

assembly {
revert(add(result, 32), mload(result))
}
}

Because delegatecall is used, the adapter contracts execute in the context of the ClaggMain contract, meaning they share the same storage space.

Both ClaggRescueAdapter and ClaggMainAdapter declare a state variable named timelock at the same storage slot (slot 0):

contract ClaggMainAdapter is EnforceOwnership {

event MainTimelockSet(uint96 timelock);

uint96 public timelock;
// --SNIP
}

contract ClaggRescueAdapter is EnforceOwnership {
using SafeERC20 for IERC20;

event RescueTimelockSet(uint96 timelock);

uint96 public timelock;
// --SNIP
}

Due to the shared storage layout during delegatecall execution, updating timelock in one adapter will unintentionally overwrite the timelock value in the other.

Recommendation

From natspec, it seems the timelock should be set once, consider making them immutable so they will be encoded in the bytecode directly.

6.3 Clagg4626BaseAdapter::getStakeLimit always returns incorrect value

FileFix commitTypeStatus
/adapters/getStakeLimit.solcae1fd4LowFixed

The getStakeLimit function is designed to return the remaining deposit capacity on the underlying ERC4626 vault (pool). The implementation calls the vault’s maxDeposit method as follows:

function getStakeLimit(address pool) external view override returns (uint256) {
PoolConfig storage poolConfig = _getPoolConfig(pool);

address token = poolConfig.token;

return IERC4626(pool).maxDeposit(token);
}

However, the maxDeposit function in the ERC4626 standard expects the receiver’s address as its parameter, representing the account intending to deposit tokens, not the underlying asset’s address. Passing the token address instead leads to incorrect return values from maxDeposit, causing getStakeLimit to report an inaccurate remaining deposit limit in all cases, depending on the pool implementation.

Recommendation

Since ClaggMain is the contract making deposits on behalf of users, the address to be passed to maxDeposit should be the contract's address instead.

6.4 Initialization of path variable is redundant for IUniswapV3Router::exactInputSingle

FileFix commitTypeStatus
/utils/Swapper.solb6988ecBest PracticesFixed

The _swapFrom_UNISWAP_V3 function in the Swapper contract handles token swaps using UniswapV3. It decodes SwapData to get specific UniswapV3 parameters, including an intermediateToken.

When a swap request does not involve an intermediate token (i.e., uniswapV3SwapData.intermediateToken == address(0)), the function proceeds with a direct swap using exactInputSingle. In this scenario, the path variable is initialized with the encoded data received. However, the exactInputSingle function does not utilize the path variable.

function _swapFrom_UNISWAP_V3(address _from, address _to, uint256 _amountIn, SwapData memory _swapData)
internal
returns (uint256 _amountOut)
{
UniswapV3SwapData memory uniswapV3SwapData = abi.decode(_swapData.data, (UniswapV3SwapData));

bytes memory path;
if (uniswapV3SwapData.intermediateToken == address(0)) {
// @audit-issue This path variable is initialized but never used in the exactInputSingle call.
path = abi.encodePacked(_from, uniswapV3SwapData.fee, _to);

_amountOut = IUniswapV3Router(_swapData.router).exactInputSingle(
IUniswapV3Router.ExactInputSingleParams({
tokenIn: _from,
tokenOut: _to,
fee: uniswapV3SwapData.fee,
recipient: address(this),
amountIn: _amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
})
);
} else {
// ...
}
}

There is no impact on the functioning of the _swapFrom_UNISWAP_V3 function. Initializing the path variable in this specific condition is unnecessary as the exactInputSingle function does not use it. This redundancy does not impact the function's operation but represents unused code/variable.

Recommendation

Remove the path initialization.

7

Documentation Evaluation

Software documentation refers to the written or visual information that describes the functionality, architecture, design, and implementation of software. It provides a comprehensive overview of the software system and helps users, developers, and stakeholders understand how the software works, how to use it, and how to maintain it. Software documentation can take different forms, such as user manuals, system manuals, technical specifications, requirements documents, design documents, and code comments. Software documentation is critical in software development, enabling effective communication between developers, testers, users, and other stakeholders. It helps to ensure that everyone involved in the development process has a shared understanding of the software system and its functionality. Moreover, software documentation can improve software maintenance by providing a clear and complete understanding of the software system, making it easier for developers to maintain, modify, and update the software over time. Smart contracts can use various types of software documentation. Some of the most common types include:

  • Technical whitepaper: A technical whitepaper is a comprehensive document describing the smart contract’s design and technical details. It includes information about the purpose of the contract, its architecture, its components, and how they interact with each other;
  • User manual: A user manual is a document that provides information about how to use the smart contract. It includes step-by-step instructions on how to perform various tasks and explains the different features and functionalities of the contract;
  • Code documentation: Code documentation is a document that provides details about the code of the smart contract. It includes information about the functions, variables, and classes used in the code, as well as explanations of how they work;
  • API documentation: API documentation is a document that provides information about the API (Application Programming Interface) of the smart contract. It includes details about the methods, parameters, and responses that can be used to interact with the contract;
  • Testing documentation: Testing documentation is a document that provides information about how the smart contract was tested. It includes details about the test cases that were used, the results of the tests, and any issues that were identified during testing;
  • Audit documentation: Audit documentation includes reports, notes, and other materials related to the security audit of the smart contract. This type of documentation is critical in ensuring that the smart contract is secure and free from vulnerabilities.

These types of documentation are essential for smart contract development and maintenance. They help ensure that the contract is properly designed, implemented, and tested, and they provide a reference for developers who need to modify or maintain the contract in the future.

8

Remarks & Test Suite

The Clave team has provided a file-diff for the changes made in the new commit.

Based on understanding the protocol from the previous audit, the Nethermind Security team conducted the audit for the changes.

The Clave team addressed the questions and concerns raised by the Nethermind Security team, providing reasoning for changes related to the project's technical aspects.

Test suite
43Tests passed0Failed

The complete test output is in the full report.

As auditors, we recommend that any changes or updates made to the audited codebase undergo a re-audit or security review to address potential vulnerabilities or risks introduced by the modifications. By conducting a re-audit or security review of the modified codebase, you can significantly enhance the overall security of your system and reduce the likelihood of exploitation. However, we do not possess the authority or right to impose obligations or restrictions on our clients regarding codebase updates, modifications, or subsequent audits. Accordingly, the decision to seek a re-audit or security review lies solely with you.

This report is based on the scope of materials and documentation provided by you to Nethermind in order that Nethermind could conduct the security review outlined in 1. Executive Summary and 2. Audited Files. The results set out in this report may not be complete nor inclusive of all vulnerabilities. Nethermind has provided the review and this report on an as-is, where-is, and as-available basis. You agree that your access and/or use, including but not limited to any associated services, products, protocols, platforms, content, and materials, will be at your sole risk. Blockchain technology remains under development and is subject to unknown risks and flaws. The review does not extend to the compiler layer, or any other areas beyond the programming language, or other programming aspects that could present security risks. This report does not indicate the endorsement of any particular project or team, nor guarantee its security. No third party should rely on this report in any way, including for the purpose of making any decisions to buy or sell a product, service or any other asset. To the fullest extent permitted by law, Nethermind disclaims any liability in connection with this report, its content, and any related services and products and your use thereof, including, without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. Nethermind does not warrant, endorse, guarantee, or assume responsibility for any product or service advertised or offered by a third party through the product, any open source or third-party software, code, libraries, materials, or information linked to, called by, referenced by or accessible through the report, its content, and the related services and products, any hyperlinked websites, any websites or mobile applications appearing on any advertising, and Nethermind will not be a party to or in any way be responsible for monitoring any transaction between you and any third-party providers of products or services. As with the purchase or use of a product or service through any medium or in any environment, you should use your best judgment and exercise caution where appropriate. FOR AVOIDANCE OF DOUBT, THE REPORT, ITS CONTENT, ACCESS, AND/OR USAGE THEREOF, INCLUDING ANY ASSOCIATED SERVICES OR MATERIALS, SHALL NOT BE CONSIDERED OR RELIED UPON AS ANY FORM OF FINANCIAL, INVESTMENT, TAX, LEGAL, REGULATORY, OR OTHER ADVICE.