Skip to content

lockup: missing validation for explicit public vesting schedules in new() #245

Description

@Carrotrust

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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