Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · February 2025

Market Maker Looping

for Baseline Markets

Baseline engaged Guardian to review the security of their market making looping updates. From the 18th of January to the 22nd of January, a team of 2 auditors reviewed the source code in scope.

Published
Review window
January 18 to 22, 2025
Language
Solidity
Chains
Base
Sector
Token launches
  • 0 Critical
  • 3 High
  • 1 Medium
  • 9 Low
  • 0 Informational

4 resolved · 1 partially resolved · 8 acknowledged

Scope

Overview

Baseline engaged Guardian to review the security of their market making looping updates. From the 18th of January to the 22nd of January, a team of 2 auditors reviewed the source code in scope.

Issues Detected Throughout the engagement 3 High/Critical issues were uncovered and promptly remediated by the Baseline team.

Findings 13

  1. H-01 High Sqrt Price Compared With Price Logical Error Resolved
    Location
    MarketMaking.sol: 428

    Description

    In the _getUtilizationRate function the priceAdj is computed as:

    FixedPointMathLib.divWad(TickMath.getSqrtRatioAtTick(activeTickAdj), FixedPoint96.Q96);

    Which has units of the square root of the price. However the priceAdj is compared against the result of getBLV to compute the premiumRatio.

    The result of getBLV is a price, instead of a square root price. Therefore the premiumRatio is incorrect.

    Recommendation

    Square the priceAdj to compute the correct price.

    Resolution

    Baseline Team: Resolved.

  2. H-02 High Liquidity Rebalance Arbitrage Gaming Partially resolved
    Location
    MarketMaking.sol

    Description

    The _updateTicks logic intentionally assigns the anchorTick such that new bAssets are not minted within the anchor range when the bAssets minted would be in addition to the liquidity in the discovery range.

    This is to avoid the following arbitrage attack:

    • Anchor liquidity < Discovery liquidity
    • An attacker makes a large sell through the discovery range and into the anchor range
    • Due to the instantaneous large sell, and the leveraging of the anchor liquidity, the anchor liquidity

    becomes greater than the Discovery liquidity

    • Now the attacker can buy back the same amount of bAssets but at a lower average price because

    of the increased Anchor liquidity relative to the liquidity they sold through.

    There is however another similar arbitrage attack which is not protected against:

    • Anchor liquidity < Discovery liquidity
    • Instead of selling through the discovery range, the attacker sells from the top of the Anchor range
    • After the sell, the rebalance causes the higher liquidity discovery range to come down closer to the

    new price

    • Now the attacker can buy back the same amount of bAssets but at a lower average price because

    of the increased Discovery liquidity relative to the liquidity they sold through.

    • As long as the leveraging of the Anchor position is not greater than the liquidity difference between

    the Anchor and Discovery then this arbitrage is profitable.

    Recommendation

    Consider rate limiting the amount of ticks that can be dropped at a time to limit the scale of this arbitrage vector.

    Resolution

    Baseline Team: Partially Resolved.

  3. H-03 High Third Party Liquidity Results In DoS Logical Error Resolved
    Location
    BPOOL.sol: 442

    Description

    The removeAllFrom function in the BPOOL contract reports the entirety of third party liquidity as fees when the liquidityToRemove > currentLiquidity, however the excess liquidity is burned from the msg.sender in the _removeLiquidity function.

    This means that the calling contract will think it has more bAssets than it does because the reported bAssetFees_ includes an amount that was burnt from the sender.

    During rebalances this results in an underflow DoS when ultimately attempting to send more bAssets then the contract holds to the fee receiver for bAssetFees_.

    Recommendation

    Do not burn the bAssets from the msg.sender in the _removeLiquidity function when removing third party liquidity.

    Resolution

    Baseline Team: Resolved.

  4. M-01 Medium Incorrect Bump Calculation Logical Error Acknowledged
    Location
    MarketMaking.sol: 287

    Description

    The criteria for a bump is described as:

    That the total reserves in the system (inclusive of debt), when placed across the anchor position (with no reserves the floor), is enough to buy back the entire circulating supply.

    However, in the _canBump function the capacity is calculated with the activeX96 as the upper to the Anchor range.

    This is however flawed because the activeX96 may not reside within the new Anchor range. Instead the anchorTick may be selected such that the activeX96 is actually within the Discovery range.

    This would not be an issue if the Discovery and Anchor ranges were guaranteed to have the same concentration of reserves.

    However it is possible that the Discovery range liquidity is actually lower than the Anchor range liquidity, in which case assuming that the reserves were evenly spread out across this range would underestimate the capacity of the protocol and errantly indicate that a bump would not be possible when in fact it can be.

    Recommendation

    Consider executing the bump logic after the new anchorTick and liquidities of the Anchor and Discovery ranges have been defined. Then do not allow the bump logic to change the liquidity of the Anchor or discovery.

    Resolution

    Baseline Team: Acknowledged.

  5. L-01 Low Unnecessary Min Optimization Resolved
    Location
    MarketMaking.sol: 395

    Description

    The _getAnchorReserves function uses the min function between anchorReserves_ and totalReserves - _getVirtualReserves() inside the case where it is already determined that totalReserves - _getVirtualReserves() < anchorReserves_.

    Therefore the min computation is unnecessary and the anchorReserves_ can always just be assigned to the totalReserves - _getVirtualReserves() value.

    Recommendation

    Remove the min computation and always assign the anchorReserves_ to totalReserves - _getVirtualReserves().

    Resolution

    Baseline Team: Resolved.

  6. L-02 Low Unused Variable Gas Optimization Resolved
    Location
    MarketMaking.sol: 364

    Description

    In the _getACU function the activeX96 is declared but never used.

    Recommendation

    Remove the activeX96 variable from the _getACU function.

    Resolution

    Baseline Team: Resolved.

  7. L-03 Low Lacking Threshold Liquidity Cap Validation Acknowledged
    Location
    MarketMaking.sol: 303

    Description

    When deploying the threshold liquidity to the Discovery position in the _deployLiquidity function there is no cap on the amount of reserve assets that can be used.

    It may be possible in some rare cases that the active price is within the Discovery range during a rebalance and the corresponding reserves requested by the _getThresholdLiquidity result are greater than the amount sitting in the MarketMaking contract due to most of the reserves being virtual reserves.

    In this scenario the current logic will revert instead of gracefully handling the conditions, thus preventing a rebalance.

    Recommendation

    Consider how this edge case should be handled. If a revert is acceptable then consider explicitly reverting in this case.

    Otherwise gracefully handle the case where the _getThresholdLiquidity result requests more reserves than are available in the MarketMaking contract, similarly to how this is handled in the _getAnchorReserves function.

    Resolution

    Baseline Team: Acknowledged.

  8. L-04 Low _getUtilizationRate Reverts Near Min Tick DoS Acknowledged
    Location
    MarketMaking.sol: 425

    Description

    In the _getUtilizationRate function the active tick is reduced by the BUMPABLE_PREMIUM which is currently set at 1500 ticks.

    In scenarios where the active tick is near the min tick, this will lead to a subsequent revert when attempting to do computations with a resulting tick that is under the min tick.

    Recommendation

    Ensure that system configurations never allow for any active price to be near the min tick.

    Resolution

    Baseline Team: Acknowledged.

  9. L-05 Low Rebalances Inconsistently Responsive Unexpected Behavior Acknowledged
    Location
    MarketMaking.sol

    Description

    In _updateTicks the rebalanceTicks assignment does not take into account where the active price is, but rather purely where the anchorTick was assigned to.

    This can result in scenarios where the active price has to travel a minimum distance of 100 ticks to trigger a rebalance, or a maximum distance of 300 ticks to trigger a rebalance.

    This makes rebalances less or more responsive during different types of price action which may be unexpected and lead to unintended results.

    Recommendation

    Consider taking the activeTick into account when assigning the rebalanceTicks so that liquidity rebalances are triggered in a more uniform manner.

    Resolution

    Baseline Team: Acknowledged.

  10. L-06 Low Lacking Balance Sweeps Defensive Code Acknowledged
    Location
    MarketMaking.sol

    Description

    In the _removeLiquidity function there is no logic to set aside the reserve assets which may be sitting in the MarketMaking contract before the liquidity positions are removed.

    Any reserves which were artificially sent to the MarketMaking contract are able to affect the market making operations because balanceOf is used liberally throughout the logic.

    This can potentially be used to manipulate a number of things, notably the anchorTick can be influenced to be the upper or lower tick based upon the buffer reserves which are based upon the balanceOf

    Recommendation

    Introduce a bufferedReserves approach similar to the previous iteration of the MarketMaking policy:

    https://github.com/0xBaseline/baseline-v2/blob/6434202087be8278f09016f28be7dc9933d1085c/

    src/policies/MarketMaking.sol#L434

    Resolution

    Baseline Team: Acknowledged.

  11. L-07 Low Outdated getBaselineValue Function Warning Acknowledged
    Location
    BPOOL.sol

    Description

    In the BPOOL contract the getBaselineValue function still returns the original baseline value of the lower floor tick instead of the upper floor tick.

    Recommendation

    Update this function to reflect the real baseline value of the upper floor tick.

    Resolution

    Baseline Team: Acknowledged.

  12. L-08 Low getCirculatingSupply Includes BPOOL Assets Unexpected Behavior Acknowledged
    Location
    MarketMaking.sol

    Description

    The getCirculatingSupply function does not subtract the BPOOL contract balance from it’s result and therefore reports any bAssets sitting in the BPOOL as circulating supply when in fact they should not be.

    This does not cause any immediate issues in the market making logic because the BPOOL assets are burned before this function is used. However for integrators and public display via this view function the BPOOL bAsset amount should be removed from the circulating supply result.

    Recommendation

    Deduct the BPOOL bAssets from the result of the getCirculatingSupply function.

    Resolution

    Baseline Team: Acknowledged.

  13. L-09 Low Lacking blvTick Validation Validation Acknowledged
    Location
    MarketMaking.sol

    Description

    The MarketMaking contract does not impose any validation on the starting value of the blvTick, therefore it is possible that a deployment of the market making policy is based on a blvTick that does not agree with the upper tick of the floor position.

    This is currently the case in the TestFoundation as the BaselineInit.launch invocation uses the INITIAL_FLOOR_TICK as the initial floor lower tick while the MarketMaking deployment uses the same INITIAL_FLOOR_TICK as the initial blvTick.

    This deployment allows for a scenario where the liquidity structure cannot absorb all supply since funds can initially be borrowed in the credit and looping facilities at a higher baseline value which is based on the upper tick of the floor position rather than the blvTick.

    Recommendation

    Consider adding validation in the constructor of the MarketMaking policy to ensure that no errant deployments can happen which do not have agreement between the blvTick and the range assigned in the BPOOL module.

    Resolution

    Baseline Team: Acknowledged.

More from Baseline Markets

All 12 reports
  1. Mercury, Round 3

    109 findings4 critical · 9 high 109 findings: 4 critical, 9 high, 28 medium, 33 low, 35 informational
  2. AMM, Round 2

    47 findings4 critical · 14 high 47 findings: 4 critical, 14 high, 8 medium, 13 low, 8 informational
  3. AMM

    54 findings3 critical · 6 high 54 findings: 3 critical, 6 high, 13 medium, 11 low, 21 informational
  4. Fixed Supply

    34 findings4 high 34 findings: 4 high, 10 medium, 20 low

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote