Vulnerability: Unfunded Referral Reward
Location
register_with_referral (L4228) → L4251: meter.balance = meter.balance.saturating_add(REFERRAL_REWARD_UNITS)
Description
register_with_referral adds REFERRAL_REWARD_UNITS = 10 to meter.balance without depositing corresponding tokens to the contract. register_meter_with_mode (L4499) correctly requires user.require_auth(), but the referral reward at L4251 is added after meter creation without any token transfer.
Impact
meter.balance represents the meter's claimable token balance. When a provider later calls claim, the contract transfers tokens from its shared pool based on meter.balance. The referral reward of 10 units is unfunded — it draws from the contract's shared token pool, which includes other users' legitimate deposits via top_up.
Attack: An attacker creates multiple accounts, each registering with a referral, inflating their meter.balance by 10 units per registration. When they claim, the contract pays out from the shared pool, effectively stealing 10 units per account from legitimate depositors.
Severity: MEDIUM
- Requires user auth (each registration needs
user.require_auth())
- Each instance only steals 10 units (small per-transaction)
- Scalable across many accounts
Fix
Either:
- Deposit actual tokens for the referral reward (transfer from a treasury)
- Track referral rewards separately from
meter.balance
- Only grant referral rewards if the contract has sufficient unallocated funds
Vulnerability: Unfunded Referral Reward
Location
register_with_referral(L4228) → L4251:meter.balance = meter.balance.saturating_add(REFERRAL_REWARD_UNITS)Description
register_with_referraladdsREFERRAL_REWARD_UNITS = 10tometer.balancewithout depositing corresponding tokens to the contract.register_meter_with_mode(L4499) correctly requiresuser.require_auth(), but the referral reward at L4251 is added after meter creation without any token transfer.Impact
meter.balancerepresents the meter's claimable token balance. When a provider later callsclaim, the contract transfers tokens from its shared pool based onmeter.balance. The referral reward of 10 units is unfunded — it draws from the contract's shared token pool, which includes other users' legitimate deposits viatop_up.Attack: An attacker creates multiple accounts, each registering with a referral, inflating their
meter.balanceby 10 units per registration. When theyclaim, the contract pays out from the shared pool, effectively stealing 10 units per account from legitimate depositors.Severity: MEDIUM
user.require_auth())Fix
Either:
meter.balance