Yaamlabs
Case study 20

Reward inflation in a governance token

Web3

A lending protocol was launching a governance token with a holding-reward feature that granted a multiplier for longer-held balances. We were asked to find a way to manipulate the reward logic before it went live with real liquidity.

Smart contract audit, DeFi protocol, severity CRITICAL, reported 2025

At a glance

  • Challenge. A custom transfer hook called an external contract before updating the holder's state, so rewards could be claimed against a balance not yet settled.
  • Approach. We read the reward path against checks-effects-interactions, traced each external call before a state update, and modelled the inflation on a fork.
  • Result. State now settles before any external call, re-entrancy guards cover state changes, rewards use a time-weighted average balance, and we retested on a fork.
  • Impact. Once live with real liquidity, a holder could have claimed the long-hold reward multiplier with a balance that existed for a single transaction.
  • Classification. CWE-1265 Unintended Reentrant Invocation of Non-reentrant Code Via Nested Calls, SWC Registry: SWC-107 Reentrancy. Component: Governance token reward-claim path.

The challenge

Most of the contract used standard, well-reviewed libraries. The reward logic did not. A custom hook notified an external contract during a transfer, and the holder’s recorded state was updated after that external call returned. That ordering is the whole vulnerability.

The checks-effects-interactions pattern exists because an external call hands control to code the contract does not own, and if state has not been settled before that hand-off, the external code observes a version of reality the contract intends to overwrite a moment later. A reward that is calculated from a balance the contract still believes it holds, at a moment the contract has not yet reconciled, can be claimed against value that is only present for the length of a single transaction. The individual functions are correct. The order in which they run is not, and order is not something a library can enforce for you.

Our approach

A smart contract audit is a reading exercise before it is a testing one. We read the reward path against the pattern it deviated from, then modelled the deviation on a fork so the finding was demonstrated, not asserted.

  • Trace every path where an external call precedes a state update
  • Confirm which reward calculations could observe unsettled balances during that window
  • Model the economic outcome on a fork, to distinguish a theoretical ordering flaw from one with real consequence
  • Check whether re-entrancy protection existed on the state-changing functions at all

Delivered with the modelled transaction and the resulting balances, so the development team could reproduce the outcome and confirm the fix against the same test.

From finding to fix

  1. Read the reward-claim path
  2. Found an external call before the state update
  3. Modelled reward inflation on a fork
  4. Reordered to settle first, retested

The outcome

The reward path was reordered to settle state before any external call, re-entrancy protection was applied to the state-changing functions, and the reward was rebased on a time-weighted average balance so a balance that exists for a single transaction can no longer earn a holding multiplier. The last change makes the flaw structurally impossible rather than merely guarded.

We retested the reward path on a fork after the fix. Reported as CRITICAL in 2025. Retest included in the engagement.

Check your own system

  • List every function that makes an external call, including token hooks and callbacks, and check that all state writes happen before it.
  • Add a re-entrancy guard to every state-changing function that reaches an external call, not only the obvious withdrawal path.
  • Base holding rewards on a time-weighted average balance rather than the balance at the moment of the claim.
  • Reproduce the ordering flaw on a fork with a contract that calls back in from the hook, and keep that test in the suite.

Read more case studies, see Smart Contract Audits, or tell us about your system on the contact page.