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
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
-
H-01 High Sqrt Price Compared With Price Logical Error Resolved
Description
In the
_getUtilizationRatefunction thepriceAdjis computed as:FixedPointMathLib.divWad(TickMath.getSqrtRatioAtTick(activeTickAdj), FixedPoint96.Q96);
Which has units of the square root of the price. However the
priceAdjis compared against the result ofgetBLVto compute thepremiumRatio.The result of
getBLVis a price, instead of a square root price. Therefore thepremiumRatiois incorrect.Recommendation
Square the
priceAdjto compute the correct price.Resolution
Baseline Team: Resolved.
-
H-02 High Liquidity Rebalance Arbitrage Gaming Partially resolved
Description
The
_updateTickslogic intentionally assigns theanchorTicksuch that newbAssetsare not minted within the anchor range when thebAssetsminted 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.
-
H-03 High Third Party Liquidity Results In DoS Logical Error Resolved
Description
The
removeAllFromfunction in the BPOOL contract reports the entirety of third party liquidity as fees when theliquidityToRemove > currentLiquidity, however the excess liquidity is burned from themsg.senderin the_removeLiquidityfunction.This means that the calling contract will think it has more
bAssetsthan it does because the reportedbAssetFees_includes an amount that was burnt from the sender.During rebalances this results in an underflow DoS when ultimately attempting to send more
bAssetsthen the contract holds to the fee receiver forbAssetFees_.Recommendation
Do not burn the
bAssetsfrom themsg.senderin the_removeLiquidityfunction when removing third party liquidity.Resolution
Baseline Team: Resolved.
-
M-01 Medium Incorrect Bump Calculation Logical Error Acknowledged
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
_canBumpfunction the capacity is calculated with theactiveX96as the upper to the Anchor range.This is however flawed because the
activeX96may not reside within the new Anchor range. Instead theanchorTickmay be selected such that theactiveX96is 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
anchorTickand 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.
-
L-01 Low Unnecessary Min Optimization Resolved
Description
The
_getAnchorReservesfunction uses the min function betweenanchorReserves_andtotalReserves - _getVirtualReserves()inside the case where it is already determined thattotalReserves - _getVirtualReserves() < anchorReserves_.Therefore the
mincomputation is unnecessary and theanchorReserves_can always just be assigned to thetotalReserves - _getVirtualReserves()value.Recommendation
Remove the
mincomputation and always assign theanchorReserves_tototalReserves -_getVirtualReserves().Resolution
Baseline Team: Resolved.
-
L-02 Low Unused Variable Gas Optimization Resolved
Description
In the
_getACUfunction theactiveX96is declared but never used.Recommendation
Remove the
activeX96variable from the_getACUfunction.Resolution
Baseline Team: Resolved.
-
L-03 Low Lacking Threshold Liquidity Cap Validation Acknowledged
Description
When deploying the threshold liquidity to the Discovery position in the
_deployLiquidityfunction 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
_getThresholdLiquidityresult are greater than the amount sitting in theMarketMakingcontract 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
_getThresholdLiquidityresult requests more reserves than are available in theMarketMakingcontract, similarly to how this is handled in the_getAnchorReservesfunction.Resolution
Baseline Team: Acknowledged.
-
L-04 Low _getUtilizationRate Reverts Near Min Tick DoS Acknowledged
Description
In the
_getUtilizationRatefunction the active tick is reduced by theBUMPABLE_PREMIUMwhich 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.
-
L-05 Low Rebalances Inconsistently Responsive Unexpected Behavior Acknowledged
Description
In
_updateTickstherebalanceTicksassignment does not take into account where the active price is, but rather purely where theanchorTickwas 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
activeTickinto account when assigning therebalanceTicksso that liquidity rebalances are triggered in a more uniform manner.Resolution
Baseline Team: Acknowledged.
-
L-06 Low Lacking Balance Sweeps Defensive Code Acknowledged
Description
In the
_removeLiquidityfunction there is no logic to set aside the reserve assets which may be sitting in theMarketMakingcontract before the liquidity positions are removed.Any reserves which were artificially sent to the
MarketMakingcontract are able to affect the market making operations becausebalanceOfis used liberally throughout the logic.This can potentially be used to manipulate a number of things, notably the
anchorTickcan be influenced to be the upper or lower tick based upon the buffer reserves which are based upon thebalanceOfRecommendation
Introduce a
bufferedReservesapproach similar to the previous iteration of theMarketMakingpolicy:https://github.com/0xBaseline/baseline-v2/blob/6434202087be8278f09016f28be7dc9933d1085c/
Resolution
Baseline Team: Acknowledged.
-
L-07 Low Outdated getBaselineValue Function Warning Acknowledged
Description
In the
BPOOLcontract thegetBaselineValuefunction 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.
-
L-08 Low getCirculatingSupply Includes BPOOL Assets Unexpected Behavior Acknowledged
Description
The
getCirculatingSupplyfunction does not subtract the BPOOL contract balance from it’s result and therefore reports anybAssetssitting 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
bAssetsfrom the result of thegetCirculatingSupplyfunction.Resolution
Baseline Team: Acknowledged.
-
L-09 Low Lacking blvTick Validation Validation Acknowledged
Description
The
MarketMakingcontract does not impose any validation on the starting value of theblvTick, therefore it is possible that a deployment of the market making policy is based on ablvTickthat does not agree with the upper tick of the floor position.This is currently the case in the
TestFoundationas theBaselineInit.launchinvocation uses theINITIAL_FLOOR_TICKas the initial floor lower tick while theMarketMakingdeployment uses the sameINITIAL_FLOOR_TICKas the initialblvTick.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
MarketMakingpolicy to ensure that no errant deployments can happen which do not have agreement between theblvTickand the range assigned in theBPOOLmodule.Resolution
Baseline Team: Acknowledged.
No findings match.
More from Baseline Markets
All 12 reports-
Mercury, Round 3
109 findings4 critical · 9 high 109 findings: 4 critical, 9 high, 28 medium, 33 low, 35 informational -
AMM, Round 2
47 findings4 critical · 14 high 47 findings: 4 critical, 14 high, 8 medium, 13 low, 8 informational -
AMM
54 findings3 critical · 6 high 54 findings: 3 critical, 6 high, 13 medium, 11 low, 21 informational -
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.
