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;
Summary
claim_rewardscomputes claimable tokens as:Integer division truncates toward zero. For a user with a small
total_earnedand a longvesting_duration, the numerator can be smaller than the denominator for an extended period, producingvested_total = 0even 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)This continues until enough time passes that
total_earned * elapsed >= vesting_duration.Fix
Use a scaling factor to preserve precision: