Assessment reports>BPF Stake Program>Threat Model>Instruction: Withdraw

Instruction: Withdraw

This instruction withdraws unstaked lamports from a stake account.

Input structure

pub enum StakeInstruction { /// # Account references /// 0. `[WRITE]` Stake account from which to withdraw /// 1. `[WRITE]` Recipient account /// 2. `[]` Clock sysvar /// 3. `[]` Stake history sysvar that carries stake warmup/cooldown history /// 4. `[SIGNER]` Withdraw authority /// 5. Optional: `[SIGNER]` Lockup authority, if before lockup expiration /// /// The u64 is the portion of the stake account balance to be withdrawn, /// must be `<= StakeAccount.lamports - staked_lamports`. Withdraw(u64), } fn process_withdraw(accounts: &[AccountInfo], withdraw_lamports: u64) -> ProgramResult {

Parameters

  • withdraw_lamports: The amount of unstaked lamports to withdraw.

Accounts

  • source_stake_account: The stake account from which to withdraw.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Writable: Yes.

    • Rent checks: None.

    • Ownership checks: The account must be owned by the program.

    • Address checks: None.

  • destination: The recipient account.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Writable: Yes.

    • Rent checks: None.

    • Ownership checks: None — but only lamports' balance is updated.

    • Address checks: None.

  • clock: The account must be a clock sysvar.

  • stake_history: Unused.

  • withdraw_authority: The withdraw authority account who is authorized to withdraw from the stake account.

    • Signer: Yes.

    • Init: No.

    • PDA: No.

    • Writable: No.

    • Rent checks: None.

    • Ownership checks: None.

    • Address checks: None.

  • option_lockup_authority (optional): The lockup authority account if before lockup expiration.

    • Signer: Yes.

    • Init: No.

    • PDA: No.

    • Writable: No.

    • Rent checks: None.

    • Ownership checks: None.

    • Address checks: None.

Additional checks and behavior

  • withdraw_authority must be a signer.

  • option_lockup_authority must be a signer if provided.

  • Signers must contain the withdraw authority and optionally the lockup authority if provided.

  • The stake account must have sufficient lamports to cover the withdrawal amount plus any required reserve.

  • If the stake account is in the Stake state, and if the current epoch is greater than or equal to the deactivation epoch, the stake amount is calculated using the stake history and cooldown. Otherwise, the stake amount is the delegation stake.

  • If the stake account is in the Uninitialized state, the source_stake_account must be a signer.

  • The lockup must have expired or the custodian must be a signer if the lockup is in force.

  • If the withdrawal amount is equal to the stake account balance and the account is still active, the withdrawal is rejected.

  • If the withdrawal amount is equal to the stake account balance, the account is deinitialized.

  • If the withdrawal amount is less than the stake account balance, the withdrawal amount must not deplete the reserve.

Zellic © 2025Back to top ↑