OpenZeppelin
Skip to content

1inch Limit Order and Aggregation Protocols Diff Audit

Table of Contents

Summary

Type
DeFi
Timeline
From 2024-02-12
To 2024-02-20
Languages
Solidity
Total Issues
1 (0 resolved)
Critical Severity Issues
0 (0 resolved)
High Severity Issues
0 (0 resolved)
Medium Severity Issues
0 (0 resolved)
Low Severity Issues
0 (0 resolved)
Notes & Additional Information
1 (0 resolved)

Scope

We audited the changes made to:

In scope were the following contracts:

 1inch-contract/contracts/
├── AggregationRouterV6.sol
routers/
    ├── ClipperRouter.sol
    ├── GenericRouter.sol
    └── UnoswapRouter.sol

limit-order-protocol/contracts/
├── LimitOrderProtocol.sol
└── OrderMixin.sol
 

Overview of the Changes

The 1inch team incorporated the following changes:

Limit Order Protocol

The LimitOrderProtocol contract now leverages the Ownable and Pausable libraries from the OpenZeppelin contracts suite (version 5.0.1) in order to:

  • Be able to pause and unpause the contract in order to halt trading activity.
  • Create a new privileged role (owner) that can perform the aforementioned actions in case of an emergency and renounce ownership if necessary after pausing the contract if the team decides the contract should be deprecated.

Note that only order filling can be effectively paused, as order cancellation, transaction simulation, and the permitAndCall entry point from the solidity-utils package (v3.7.1) will remain usable even if the contract is paused.

Aggregation Protocol

The Pausable library has also been added to the AggregationProtocolV6 contract. As such, the old mechanism of using selfdestruct to deprecate the contract in case of an emergency has been substituted with simply pausing the contract (and potentially renouncing ownership of the contract if necessary). The rationale behind this change is to plan for the future when the selfdestruct opcode gets discontinued.

All trading activity gets halted if the contract gets paused, except three entry points:

More information about the consequences and trade-offs of leaving these two callbacks callable during a paused contract state can be found in the next section.

Non-Issue Observations

Regarding the three Limit Order protocol entry points that have been left callable during a paused state, the team confirmed this is a conscious decision which enables users to cancel outstanding orders in unorthodox scenarios where the contract needs to be paused. Transaction simulation does not pose security risks for the system and the PermitAndCall library is not helpful if it cannot be chained with another call to fill an order.

However, if the AggregationRouterV6 contract is paused, presumably due to an exploit or bug, the ERC-20 balances can still be transferred out by anyone despite the contract being paused. This can be achieved by leveraging either the curveSwapCallback or the uniswapV3SwapCallback functions.

The first function directly transfers arbitrary balances to arbitrary recipients, should there be any positive balance in the contract. The second one will revert if called in such a way so that the payer is not the AggregationProtocolV6 contract itself. However, if the payer is set to the contract address itself, it will go ahead and transfer arbitrary token balances to arbitrary recipients as long as the caller is a contract that implements the token0() and token1() functions.

In an emergency scenario (e.g., user funds being stuck on the contract), there is already an onlyOwner function that allows for the safe recovery of those funds, so no publicly accessible function should be available. Moreover, even if the contract is paused and ownership is renounced, malicious third parties may still use this contract to fund exploits on other DeFi protocols. While this in itself is not 1inch's fault, end users will be able to see this contract as the source of funds for the attack and may have negative PR effects for the company. Although, it is worth noting that the same attack can be achieved even when the contract is not paused.

Adding the whenNotPaused modifier to both callbacks could mitigate this situation in case the perceived risk of such scenarios outweighs the extra gas consumption for legitimate swaps on Curve pools with callbacks and Uniswap V3 while the contract is unpaused. Since the storage slot will be considered warm, an approximate extra 100 units of gas per swap involving callbacks will be used for every redundant whenNotPaused modifier used in legitimate trades. However, we did not find a strong reason to raise this as an issue since the same behaviour could happen while the contract remains unpaused.

Security Considerations for Users

In cases of emergency when the contracts are paused, users should immediately cancel all outstanding orders and revoke prior approvals as a safety measure.

Notes & Additional Information

Unused Named Return Variables

Named return variables are a way to declare variables that are meant to be used within a function's body for the purpose of being returned as the function's output. They are an alternative to explicit in-line return statements.

Throughout the codebase, there are multiple instances of unused named return variables:

  • The returnAmount return variable in the clipperSwap function in ClipperRouter.sol
  • The returnAmount return variable in the clipperSwapTo function in ClipperRouter.sol

Consider either using or removing any unused named return variables.

Update: Acknowledged, will resolve. The 1inch team stated:

We will make an effort to unify our usage of named return variable across all our active codebase somewhen later this year.

Conclusion

The audited version of both 1inch Limit Order Protocol and Aggregation Protocol allows the 1inch team to pause and unpause the main contracts and potentially deprecate them by renouncing ownership in case of an emergency.

No major issues were found during the audit, although some insights about the consequences of the changes introduced were added to the introduction. This was done to make both the client and end-users more aware of the full implications of the decisions behind the implemented changes.

The 1inch team was very responsive throughout the engagement, providing us with the necessary insight to expedite our understanding of the changes implemented and their effect on the codebase.

 

Request Audit