😵How Pool Implementation Mismatches Pose a Security Risk to Decentralized Exchanges (DEXs)

Introduction

Decentralized Exchanges (DEXs) are a cornerstone of the decentralized finance (DeFi) ecosystem, offering the promise of permissionless, secure, and transparent trading. However, this decentralization doesn't necessarily translate into absolute security. One category of vulnerability that has been observed "in the wild" pertains to mismatches between DEX projects and the pool implementations they utilize. This article delves into the generalized risks and implications of such incompatibilities.

The Core Issue: Incompatibility Between Project and Pool Implementation

The Basics

When a DEX or DeFi project uses a pool implementation—like a liquidity pool from Curve, Uniswap, or any other provider—it is expected to adhere to the behavior and rules dictated by that pool. This could range from how the pool maintains token balances, the way prices are calculated, to more complex features like yield farming mechanics.

What Could Go Wrong?

Incompatibilities can manifest in various ways, such as:

  1. Dynamic Balance Discrepancies: The pool might expect static or semi-static balances for its tokens. However, if the token contract is designed to have dynamically changing balances, this will create a mismatch, potentially leading to incorrect pricing or even the possibility of arbitrage attacks.

  2. Functional Mismatches: Features commonly used in pools, like virtualPrice in Curve, may not operate as expected if the DEX or DeFi project's implementation deviates from the standard or accepted behavior.

  3. Interface Inconsistencies: When the functions and returns of a pool implementation are not mirrored exactly by the DEX project, it can lead to failures or vulnerabilities when users or other smart contracts interact with it.

Vulnerability Explained 1: Incompatibility Between Dynamic Token Balances and Curve StableSwap Pool

Code4Arena bug bounty high payout

Overview

The vulnerability emerges from an incompatibility between a token called wibBTC and a Curve StableSwap pool, where wibBTC is intended to operate. Unlike typical ERC20 tokens, wibBTC balances change dynamically and automatically. This design feature clashes with the operational behavior of the Curve StableSwap pool, which is not engineered to handle dynamic balances.

Technical Details

  1. wibBTC's Dynamic Nature: wibBTC is not a traditional, static-balance ERC20 token. Instead, its balance changes dynamically based on factors like pricePerShare.

  2. Curve StableSwap Expectations: Curve StableSwap pools expect token balances to remain fairly static, changing only when tokens are added, removed, or traded within the pool.

  3. Deviation in Balances: The actual dynamic balance of wibBTC can diverge from what the Curve StableSwap pool's smart contract records as the balance. This is especially problematic when pricePerShare increases.

  4. Lack of Sync Functionality: Curve StableSwap does not have a synchronization function equivalent to UNI v2's sync(), which could otherwise force the stored reserves to align with the actual balances.

Proof of Concept (PoC)

Consider the following scenario:

  • Initial State: The Curve pool is new with zero liquidity and a pricePerShare of 1.

  • Alice's Action: Alice adds 100 wibBTC and 100 wBTC to the Curve pool, holding 100% of the pool.

  • After One Month: No activity occurs for a month, and the pricePerShare of wibBTC increases to 1.2.

  • Alice's Withdrawal: Alice decides to withdraw all the liquidity.

Alice expects to receive 150 wibBTC and 100 wBTC based on the new pricePerShare. However, due to the incompatibility, she receives only the original 100 wibBTC and 100 wBTC, resulting in a loss of potential earnings.

Security Implications

This vulnerability can have several consequences:

  • Financial Loss: Users like Alice would face financial losses as they wouldn't receive the expected amount upon withdrawal.

  • Data Integrity: The inaccurate recording of balances could affect other functionalities of the Curve StableSwap pool.

  • System Instability: If exploited en masse, this issue could destabilize the Curve pool and related ecosystems.

Recommendation

Given the severity of the issue, one recommended solution is to create a revised version of the Curve StableSwap contract that can correctly handle dynamic balances. This new implementation should consider the unique behavior of tokens like wibBTC and facilitate accurate and reliable transactions for its users.

Vulnerability Explained 2 : Customizable Precision Multipliers Undermine the Integrity of virtualPrice

Code4Arena bug bounty Payout

Overview

The vulnerability revolves around the virtualPrice feature, commonly used in various protocols like Curve MetaPool and Mim. This feature generally has a monotonically increasing value, but the issue lies in its implementation in customSwap. The use of customPrecisionMultipliers allows the modification of target prices, essentially compromising the integrity and meaning of virtualPrice.

Technical Details

  1. VirtualPrice Feature: virtualPrice is a commonly-used feature in several protocols, designed to monotonically increase irrespective of market conditions.

  2. CustomSwap Implementation: The current implementation allows for dynamic changes in customPrecisionMultipliers, thus impacting the virtualPrice.

  3. Vague Meaning: The changeable nature of customPrecisionMultipliers makes the meaning of virtualPrice vague or unreliable.

  4. Potential for Exploitation: The vulnerability could damage liquidity providers and potentially make the protocol susceptible to hacks.

Proof of Concept (PoC)

To demonstrate this issue, a mockSwap can be set up with an extra function, setPrecisionMultiplier.

javascriptCopy codefunction setPrecisionMultiplier(uint256 multipliers) external {
    swapStorage.tokenPrecisionMultipliers[0] = multipliers; 
}
print(swap.functions.getVirtualPrice().call())
swap.functions.setPrecisionMultiplier(2).transact()
print(swap.functions.getVirtualPrice().call())

Upon running the function, the virtualPrice changes from 1000000000000000000 to 1499889859738721606, demonstrating the vulnerability.

Security Implications

  • Ambiguity and Unreliability: The use of customPrecisionMultipliers makes virtualPrice an unreliable metric.

  • Financial Risk: Liquidity providers are at risk as an attacker might exploit this vulnerability to manipulate prices.

  • Operational Risks: Other protocols relying on virtualPrice might also get exposed to risks, leading to a cascading effect on the ecosystem.

Recommendations

  • Immutable Multiplier: Make the customPrecisionMultipliers immutable after pool setup to maintain the integrity of virtualPrice.

  • Removal of Function: If making it immutable is not an option, then removing the getVirtualPrice function may be considered as a quick fix. However, this is not advisable if other protocols heavily rely on this function.

Conclusion

While the virtualPrice feature serves an essential function in many protocols, its current implementation within customSwap undermines its integrity and poses medium-risk security threats. This case highlights the importance of meticulous design and testing, especially when a function or feature is central to multiple protocols in the ecosystem. It also emphasizes the need to consider the systemic impact of individual components on the larger DeFi landscape.

Vulnerability Explained 3: Inconsistencies in VaderRouterV2's addLiquidity Function

Code4Arena bug bounty payout

Overview

The vulnerability emerges from VaderRouterV2's addLiquidity function, which claims to be designed for Uniswap V2 compatibility. However, the implementation falls short in replicating the interface and behavior of the original Uniswap V2 router. Specifically, the function's returns and the approval process for token allowances are not congruent with the Uniswap V2 specification.

Technical Details

  1. Return Inconsistency: The addLiquidity function in VaderRouterV2 doesn't return the same data as its Uniswap V2 counterpart.

  2. Token Allowances: The function fails to approve the token allowances to the router, another deviation from the Uniswap V2 standard.

Example Code from VaderRouterV2

javascriptCopy codefunction addLiquidity(
    IERC20 tokenA,
    IERC20 tokenB,
    uint256 amountADesired,
    uint256 amountBDesired,
    uint256, // amountAMin = unused
    uint256, // amountBMin = unused
    address to,
    uint256 deadline
) external override returns (uint256 liquidity) {

Proof of Concept (PoC)

Consider an ecosystem that relies on VaderRouterV2 for adding liquidity. Developers and users assume that it behaves similarly to the Uniswap V2 router and build or interact accordingly.

Upon execution, these parties discover the following:

  • The returned value of liquidity doesn't match expectations based on Uniswap V2.

  • Their transactions are failing or behaving unexpectedly because the token allowances are not correctly approved to the router.

Security Implications

  • Unexpected Behavior: The mismatch between expected and actual behavior could lead to smart contract failures or incorrect calculations.

  • Financial Risks: Users and liquidity providers could potentially incur financial losses due to unexpected contract behaviors.

  • Loss of Trust: Deviations from expected behaviors can lead to loss of trust in the VaderRouterV2 or any dApp relying on it for Uniswap V2 compatibility.

Recommendations

  • Function Alignment: Ensure that the addLiquidity function in VaderRouterV2 is fully compatible with the Uniswap V2 router, both in terms of return values and token allowance approvals.

Conclusion

This vulnerability highlights the risks involved when a contract claims compatibility with a well-known standard like Uniswap V2 but deviates in its implementation. Such inconsistencies can lead to a range of problems, from financial losses for users to unexpected behaviors in interconnected smart contracts within the DeFi ecosystem. It underlines the importance of rigorous testing and auditing, particularly when claiming compatibility with established protocols.

General Summary: The Security Risks of Protocol and Pool Implementation Incompatibilities in Decentralized Exchanges (DEXs)

The Crux of the Matter

Decentralized Exchanges and DeFi protocols are complex ecosystems that often rely on interoperability with other smart contracts, protocols, and token standards. While this interconnection is one of the strengths of the DeFi space, it can also be a significant weakness when components are not fully compatible. This class of vulnerabilities arises when there is a mismatch between a project's implementation and the pool or protocol it intends to interact with.

Common Manifestations

  1. Dynamic Balance Discrepancies: Some tokens are designed with dynamically changing balances, which can conflict with pool implementations expecting static or semi-static balances.

  2. Functional Deviations: Features like virtualPrice that are expected to behave in a certain way can be implemented differently, affecting not just the immediate protocol but all interconnected systems relying on that feature.

  3. Interface Inconsistencies: If a function claims to be compatible with a well-established protocol like Uniswap V2 but deviates in implementation, it can lead to unexpected behavior, financial risks, and loss of trust.

Impact and Implications

  1. Financial Risks: Users and liquidity providers may suffer from financial losses due to unexpected system behaviors or hacks.

  2. Data Integrity Risks: Inaccurate data recording can affect other functionalities of a pool or a protocol, leading to broader system instability.

  3. Loss of Trust: Inconsistencies and deviations can erode user trust, which is vital for the growth and sustainability of DeFi projects.

  4. Systemic Risks: Since DeFi protocols are often interconnected, a vulnerability in one can lead to a cascading effect, affecting the broader DeFi ecosystem.

Last updated