Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing Range Validation in initialize Function Allows Setting Out-of-Bounds Tick Bounds and Target Price #17

Open
CipherHawk0 opened this issue Oct 14, 2024 · 0 comments

Comments

@CipherHawk0
Copy link

Summary

The absence of range validation in the initialize function will cause a high impact on the protocol's initialization process as an attacker can set out-of-bounds tick bounds and target price, leading to improper liquidity positioning and potential financial imbalances.

Root Cause

In SolidlyV3AMO.sol, the initialize function sets initial values for tickLower, tickUpper, and targetSqrtPriceX96 without validating whether these initial parameters fall within acceptable or logical ranges. This oversight allows the setting of out-of-bounds or conflicting initial values, which can disrupt the protocol's liquidity management from the outset.

Relevant Code Snippet:

function initialize(
    address admin,
    address boost_,
    address usd_,
    address pool_,
    address boostMinter_,
    int24 tickLower_,
    int24 tickUpper_,
    uint160 targetSqrtPriceX96_,
    uint256 boostMultiplier_,
    uint24 validRangeWidth_,
    uint24 validRemovingRatio_,
    uint24 usdUsageRatio_,
    uint256 boostLowerPriceSell_,
    uint256 boostUpperPriceBuy_
) public initializer {
    super.initialize(admin, boost_, usd_, pool_, boostMinter_);

    _grantRole(SETTER_ROLE, msg.sender);
    setTickBounds(tickLower_, tickUpper_);
    setTargetSqrtPriceX96(targetSqrtPriceX96_);
    setParams(
        boostMultiplier_,
        validRangeWidth_,
        validRemovingRatio_,
        usdUsageRatio_,
        boostLowerPriceSell_,
        boostUpperPriceBuy_
    );
    _revokeRole(SETTER_ROLE, msg.sender);
}

Internal pre-conditions

1-The initialize function is called once during contract deployment.
2-The parameters tickLower_, tickUpper_, and targetSqrtPriceX96_ are provided without prior validation.

External pre-conditions

1-The pool contract must be correctly set up and operational.
2-External actors cannot interfere with the initialization process post-deployment.

Attack Path

1-The attacker deploys the SolidlyV3AMO contract, becoming the initial admin with the SETTER_ROLE.
2-During the initialize function call, the attacker provides out-of-bounds or conflicting values for tickLower_, tickUpper_, and targetSqrtPriceX96_.
3-The contract sets these values without validation, resulting in invalid tick bounds and target price.
4-The invalid initial parameters disrupt liquidity positioning, leading to inefficient liquidity distribution and potential financial imbalances.
5-The BOOST peg becomes destabilized from the outset, causing financial losses and undermining user trust.

Impact

The protocol experiences a high risk of improper liquidity positioning and financial imbalances due to invalid initial parameters. This can lead to reduced liquidity efficiency, increased slippage, and immediate destabilization of the BOOST peg, severely affecting user confidence and financial stability.

PoC

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "./SolidlyV3AMO.sol";

contract InitializationAttack {
    SolidlyV3AMO amo;

    constructor() {
        amo = new SolidlyV3AMO();
    }

    function exploit() public {
        // Initialize with out-of-bounds tick bounds and target price
        amo.initialize(
            msg.sender,            // admin
            address(0xBoost),      // boost_
            address(0xUSD),        // usd_
            address(0xPool),       // pool_
            address(0xMinter),     // boostMinter_
            100,                   // tickLower_ (invalid)
            50,                    // tickUpper_ (invalid, less than tickLower_)
            0,                     // targetSqrtPriceX96_ (invalid, below MIN_SQRT_RATIO)
            0,                     // boostMultiplier_ set to 0 (invalid)
            FACTOR + 1000,         // validRangeWidth_ set beyond FACTOR
            FACTOR - 1000,         // validRemovingRatio_ set below FACTOR
            FACTOR + 500,          // usdUsageRatio_ set beyond FACTOR
            0,                     // boostLowerPriceSell_ set to 0
            type(uint256).max      // boostUpperPriceBuy_ set to max
        );
    }
}

Mitigation

1-Implement Range Validation in initialize:
Ensure that initial parameters like tickLower_, tickUpper_, and targetSqrtPriceX96_ are within acceptable ranges.

function initialize(
    address admin,
    address boost_,
    address usd_,
    address pool_,
    address boostMinter_,
    int24 tickLower_,
    int24 tickUpper_,
    uint160 targetSqrtPriceX96_,
    uint256 boostMultiplier_,
    uint24 validRangeWidth_,
    uint24 validRemovingRatio_,
    uint24 usdUsageRatio_,
    uint256 boostLowerPriceSell_,
    uint256 boostUpperPriceBuy_
) public initializer {
    super.initialize(admin, boost_, usd_, pool_, boostMinter_);

    _grantRole(SETTER_ROLE, msg.sender);
    require(tickLower_ < tickUpper_, "tickLower must be less than tickUpper");
    require(tickLower_ >= MIN_TICK && tickUpper_ <= MAX_TICK, "Tick bounds out of range");
    require(targetSqrtPriceX96_ > MIN_SQRT_RATIO && targetSqrtPriceX96_ < MAX_SQRT_RATIO, "Invalid target sqrtPriceX96");

    setTickBounds(tickLower_, tickUpper_);
    setTargetSqrtPriceX96(targetSqrtPriceX96_);
    setParams(
        boostMultiplier_,
        validRangeWidth_,
        validRemovingRatio_,
        usdUsageRatio_,
        boostLowerPriceSell_,
        boostUpperPriceBuy_
    );
    _revokeRole(SETTER_ROLE, msg.sender);
}

2-Add Validation Checks in Setter Functions:
Ensure that any setter functions called during initialization enforce validation.
3-Implement Multi-Signature Controls:
Require multiple approvals for setting critical parameters during initialization to prevent single-point manipulation.
4-Regular Audits and Monitoring:
Continuously monitor initialization parameters to ensure they are set correctly and within expected ranges.
5-Role Management Best Practices:
Ensure that only trusted addresses are granted the SETTER_ROLE during initialization and beyond.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant