lockup.new() accepts VestingScheduleOrHash::VestingSchedule(vs) and stores it without validating the timestamp relationship, even though VestingSchedule::assert_valid() already exists.
Affected code
What seems to be happening
new() handles Some(VestingScheduleOrHash::VestingSchedule(vs)) by directly storing VestingInformation::VestingSchedule(vs).
- No
vs.assert_valid() call is made on that path.
- Later vesting math assumes the schedule is valid, including
end_timestamp - start_timestamp in get_unvested_amount().
Why this matters
- A malformed explicit public vesting schedule can be accepted at initialization time.
- That can later cause vesting-related reads / balance calculations to panic or behave incorrectly because the stored schedule violates invariants that the rest of the contract assumes.
Example malformed schedule
{
"VestingSchedule": {
"start_timestamp": "100",
"cliff_timestamp": "100",
"end_timestamp": "100"
}
}
Expected behavior
Initialization should reject invalid public vesting schedules using the same invariant checks already defined in VestingSchedule::assert_valid().
Suggested fix
In lockup.new(), call vs.assert_valid() before storing VestingInformation::VestingSchedule(vs).
Additional note
This looks like a regression from the public/private vesting refactor, since the validation helper exists and later logic clearly depends on those invariants holding.
lockup.new()acceptsVestingScheduleOrHash::VestingSchedule(vs)and stores it without validating the timestamp relationship, even thoughVestingSchedule::assert_valid()already exists.Affected code
What seems to be happening
new()handlesSome(VestingScheduleOrHash::VestingSchedule(vs))by directly storingVestingInformation::VestingSchedule(vs).vs.assert_valid()call is made on that path.end_timestamp - start_timestampinget_unvested_amount().Why this matters
Example malformed schedule
{ "VestingSchedule": { "start_timestamp": "100", "cliff_timestamp": "100", "end_timestamp": "100" } }Expected behavior
Initialization should reject invalid public vesting schedules using the same invariant checks already defined in
VestingSchedule::assert_valid().Suggested fix
In
lockup.new(), callvs.assert_valid()before storingVestingInformation::VestingSchedule(vs).Additional note
This looks like a regression from the public/private vesting refactor, since the validation helper exists and later logic clearly depends on those invariants holding.