#47010 [SC-Low] `CollateralPool::donateNat` manipulation enables arbitrary pool‐token value inflation and fee‐debt evasion

Submitted on Jun 7th 2025 at 20:17:14 UTC by @NHristov for Audit Comp | Flare | FAssets

  • Report ID: #47010

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/flare-foundation/fassets/blob/main/contracts/assetManager/implementation/CollateralPool.sol

  • Impacts:

    • Theft of unclaimed yield

    • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Brief/Intro

In CollateralPool::enter, new pool‐tokens are minted in proportion to

tokenShare ≃ poolTokenSupply × (depositNat / poolNatBalance)

Yet CollateralPool::donateNat lets anyone add up to ≈1% of the current poolNatBalance without minting tokens. By repeatedly donating just under that 1% cap, an attacker can inflate poolNatBalance while leaving poolTokenSupply fixed, so that

1 poolToken → poolNatBalance / poolTokenSupply

grows arbitrarily large. A single token can end up “worth” millions of NAT, breaking the economic invariants of the pool.

Vulnerability Details

The core of the issue is that CollateralPool::donateNat does not mint any pool tokens while new pool tokens are minted in CollateralPool::enter in proportion to the amount of NAT deposited, but the pool's NAT balance can be inflated without minting any new tokens. This means that the value of a single pool token can be manipulated by repeatedly donating just under the 1% cap.

For example attack can be executes as follows based on the ratio depositNat / poolNatBalance.

  • By repeatedly calling donateNat() with up to ~1% of the current poolNatBalance, an attacker can inflate poolNatBalance without increasing poolTokenSupply. Each donation multiplies the collateral base by ~1.01×, and after N donations:

so that

grows exponentially. Once the ratio is enormous, an attacker can:

  1. Exit 99% of their tokens (leaving ≥1 token) via exit(tokens * 99/100) and burns nearly all tokens, reducing poolTokenSupply to ~1–2, but leaves totalCollateral huge.

  2. Redeem fees for “free”:

  • After the manipulation loop, fAssetFeeDebtOf(attacker)==0, so calling enter(0, true) with a tiny deposit mints collateral-pool tokens at the inflated ratio, evading any owed f-asset fees.

  1. That final 1 token now represents millions of NAT, which can never be withdrawn (exit requires ≥1 token after exit), locking enormous funds.

Impact Details

  • The last locked token in the pool can be worth millions of NAT, which can never be withdrawn.

  • The attacker can redeem fees for “free” by entering the pool with a tiny deposit after inflating the pool's NAT balance.

  • The economic invariants of the pool are broken, allowing for manipulation of the value of pool tokens.

References

Proof of Concept

Proof Of Concept

The following unit test demonstrates the exploit:

To run the test paste the code in the CollateralPool.ts unit test file and execute it

Was this helpful?