Summary
compute_vested() uses paused_at as the freeze point when paused:
let effective_now = if config.paused { config.paused_at } else { now };
config.paused_at is a u64 initialized to 0 in initialize(). If somehow config.paused == true but config.paused_at == 0 (which should not happen via normal flow, but could if a storage migration or future code path sets paused = true without setting paused_at), effective_now would be 0, making elapsed = 0.saturating_sub(start_time) = 0, and returning 0 vested — freezing all tokens at zero permanently.
Unlike forge-stream which correctly uses Option<u64> for paused_at, forge-vesting uses a plain u64 with 0 as sentinel.
Tasks
Labels: bug, forge-vesting
Summary
compute_vested()usespaused_atas the freeze point when paused:config.paused_atis au64initialized to0ininitialize(). If somehowconfig.paused == truebutconfig.paused_at == 0(which should not happen via normal flow, but could if a storage migration or future code path setspaused = truewithout settingpaused_at),effective_nowwould be0, makingelapsed = 0.saturating_sub(start_time) = 0, and returning0vested — freezing all tokens at zero permanently.Unlike
forge-streamwhich correctly usesOption<u64>forpaused_at,forge-vestinguses a plainu64with0as sentinel.Tasks
paused_at: u64topaused_at: Option<u64>inVestingConfigpause()to setpaused_at = Some(env.ledger().timestamp())unpause()to readpaused_at.unwrap_or(now)and reset toNonecompute_vested()to useconfig.paused_at.unwrap_or(now)when pausedLabels:
bug,forge-vesting