59795 sc low free boosts for levels added after v3

Submitted on Nov 15th 2025 at 20:36:37 UTC by @OxPrince for Audit Comp | Vechain | Stargate Hayabusaarrow-up-right

  • Report ID: #59795

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/tree/main/packages/contracts/contracts/StargateNFT/StargateNFT.sol

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Brief/Intro

Starting with V3 the boost fee per level is configured solely in initializeV3, which is a one-shot reinitializer(3) (packages/contracts/contracts/StargateNFT/StargateNFT.sol:226-243). The only remaining admin entry point for level management is addLevel (packages/contracts/contracts/StargateNFT/StargateNFT.sol:301-305), but this helper never touches boostPricePerBlock. Because boostPricePerBlock is stored in a mapping with the Solidity default of zero and Levels.updateLevelBoostPricePerBlock is no longer reachable from any callable function, every level that is added after initializeV3 permanently inherits a boost price of zero.

MintingLogic calculates the boost fee as (maturityPeriodEndBlock - now) * boostPricePerBlock (packages/contracts/contracts/StargateNFT/libraries/MintingLogic.sol:316-329). When boostPricePerBlock is zero, MintingLogic.boostOnBehalfOf accepts a zero-fee boost: the balance and allowance checks trivially pass, and the VTHO transfer burns zero tokens (packages/contracts/contracts/StargateNFT/libraries/MintingLogic.sol:102-145). Therefore any wallet can immediately mature newly created levels without paying VTHO, bypassing both the intended maturity delay and all boost revenue.

Vulnerability Details

1

Governance can add levels that have no boost price

Governance (or any wallet with LEVEL_OPERATOR_ROLE) can add new levels by calling StargateNFT.addLevel (packages/contracts/contracts/StargateNFT/StargateNFT.sol:301-305). The function delegates to Levels.addLevel, which validates metadata/caps and appends the level, but makes no mention of boost pricing.

2

Boost price is only set during V3 initialization

The only place where Levels.updateLevelBoostPricePerBlock is invoked is inside initializeV3 (packages/contracts/contracts/StargateNFT/StargateNFT.sol:226-243). Because the initializer is marked reinitializer(3), it can run exactly once for the lifetime of the proxy. After deployment, there is no callable function that writes to boostPricePerBlock[_levelId].

3

Newly added levels keep the default zero boost price

For every newly added level _levelId, the mapping entry boostPricePerBlock[_levelId] stays at the default 0. Both boostPricePerBlock and boostAmountOfLevel now report 0 for that level (packages/contracts/contracts/StargateNFT/StargateNFT.sol:403-411).

4

Users can boost for free, skipping maturity and revenue

When a user owns an NFT of that level and calls boost, the call reaches MintingLogic.boostOnBehalfOf through StargateNFT.boost (packages/contracts/contracts/StargateNFT/StargateNFT.sol:392-396). _boostAmount multiplies the remaining maturity blocks by the zero boost price, so requiredBoostAmount is zero (packages/contracts/contracts/StargateNFT/libraries/MintingLogic.sol:316-329). The subsequent balance/allowance checks and the burn transfer all succeed without transferring VTHO (packages/contracts/contracts/StargateNFT/libraries/MintingLogic.sol:112-145). The NFT’s maturity end block is nevertheless set to the current block, fully skipping the maturity period for free.

Impact Details

circle-exclamation

Proof of Concept

Boost.test

References

  • Target contract: https://github.com/immunefi-team/audit-comp-vechain-stargate-hayabusa/tree/main/packages/contracts/contracts/StargateNFT/StargateNFT.sol

  • Minting logic: packages/contracts/contracts/StargateNFT/libraries/MintingLogic.sol

Was this helpful?