Skip to content

improve stake account ux #75

@2501babe

Description

@2501babe

Problem

figuring out exactly what state a stake account is in is complex and error-prone:

  1. determining if a stake account is active, activating, deactivating, or inactive is typically done via a combination of matching on StakeStateV2 enum variants and manually comparing Delegation.activation_epoch and Delegation.deactivation_epoch to Clock.epoch and u64::MAX
  2. a common mistake (that i have made myself) is doing the steps in 1 and looking at Delegation.stake. this is not correct: it fails to consider partial activation or deactivation in the case of warmup or cooldown, and the "delegated" amount is left intact for an inactive account that was previously active
  3. the true way to determine stake account state is to call stake_activating_and_deactivating() on Delegation with Clock and StakeHistory. this returns StakeActivationStatus, which is just a type alias for StakeHistoryEntry, which is a triple of effective, activating, and deactivating. this can be used to determine the true state of a stake account, but:
    • it requires end-users to compare values by hand
    • you still need to match on StakeStateV2 for uninitialized and initialized accounts
    • distinguishing between deactivating and partially deactivated also requires looking at Delegation.stake

Solution

add a new enum StakeAccountStatus or similar, with variants: uninitialized, activating, partially active, fully active, deactivating, partially deactivated, fully inactive. abstract over the distinction between an initialized account and a fully deactivated account. carry StakeActivationStatus as a value on variants where it makes sense. have whatever boolean-return helpers are convenient. possibly include helpers for determining things about minimum delegation and excess undelegated lamports

most of the required logic is actually already implemented: its just part of MergeKind, an internal stake program helper for Merge (also now used by MoveStake and MoveLamports because it is so convenient, but not Split, Withdraw, or anything else). we should abstract this out, move it into sdk, and use it across all relevant stake program process functions and the stake pools to replace the ad hoc way we do all this now

until very recently the hard requirement on StakeHistory made this kind of accounting a huge burden for stake operations that didnt truly "need" it. but last week (note: this issue was originally opened in february) we activated get_sysvar on mainnet, which enables StakeHistory access without:

  • needing to include the account in the accounts list
  • needing to deserialize it into an AccountInfo
  • needing to store a 16kb vec on the heap

with the ability to get individual stake history entries via syscall (and only one is needed if there is no warmup/cooldown), we can implement a one true way of doing this now

(this is the new home of anza-xyz/solana-sdk#61)

Metadata

Metadata

Assignees

No one assigned

    Labels

    interfacerelated to the program instruction interface

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions