Skip to content

[bug] rewards-distributor: vested_total integer division truncates to 0 for small rewards with long vesting — tokens permanently unclaimable until threshold is crossed #729

Description

@gboigwe

Summary

claim_rewards computes claimable tokens as:

let vested_total = (rewards.total_earned as u128 * vesting_fraction as u128
    / rewards.vesting_duration as u128) as i128;

Integer division truncates toward zero. For a user with a small total_earned and a long vesting_duration, the numerator can be smaller than the denominator for an extended period, producing vested_total = 0 even though mathematically some tokens have vested.

Example: total_earned = 5 tokens, vesting_duration = 365 days (31,557,600 seconds), called at day 30:

  • 5 * 2,592,000 / 31,557,600 = 12,960,000 / 31,557,600 = 0 (integer truncation)
  • The user receives nothing despite 30/365 = 8.2% of their tokens being vested.

This continues until enough time passes that total_earned * elapsed >= vesting_duration.

Fix

Use a scaling factor to preserve precision:

let vested_bps = rewards.total_earned as u128 * vesting_fraction as u128 * 10_000
    / rewards.vesting_duration as u128;
let vested_total = (vested_bps / 10_000) as i128;

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions