<!-- canonical: https://0xsimao.com/findings/blast-ido-pools-multiplier-propose-multiple-executing -->

# `MultiplierContract::proposeMultipleUpdates()` updates `maxLevel` before executing the update

Crit/High · Three Sigma · IDO launchpad · 7th August, 2024

Finding H-1 of the Blast IDO Pools security review.

- Protocol: https://docs.blastup.io/blastup-docs
- Report: /reports/blast-ido-pools
- Source: https://cdn.sanity.io/files/qoqld077/production/d2a7ca81740e715b604122c12dafbce599e43f2f.pdf

---

### Description

`MultiplierContract::proposeMultipleUpdates()` updates `maxLevel` without going through the `UPDATE_INTERVAL`, which will affect the multiplier `MultiplierContract::getMultiplier()` right away, without updating the actual thresholds and multipliers. 

If `maxLevel >= prevMaxLevel`, it still works correctly in `MultiplierContract::getMultiplier()` as the levels after `prevMaxLevel` will not yet have been created so the loop will just continue `if (levelThresholds[i] == 0) continue;`.

However, if `maxLevel < prevMaxLevel`, some of the previous levels will be skipped as soon as `MultiplierContract::proposeMultipleUpdates()` is called. For example, if there were 5 levels, but now just 4, if users were elegible for level 5, the maximum they can get is level 4, although `MultiplierContract::executeUpdates()`.

Lastly, `MultiplierContract::cancelUpdate()` does not revert the `maxLevel` update in `MultiplierContract::proposeMultipleUpdates()`, even though the update was cancelled.

### Recommendation

The `maxLevel` should be updated only when `MultiplierContract::executeUpdates()` is called.

---

Related findings:

- [`treasury.updateYieldsFromLiquidatedLrts()` updates the yield in the current chain, but collateral may be in the other chain](https://0xsimao.com/findings/autonomint-yields-lrts-yield-collateral): Autonomint
- [OstiumTrading::updateOpenLimitOrder() Makes Unnecessary Field Updates](https://0xsimao.com/findings/ostium-trading-unnecessary-field-updates): Ostium
