SIMD-0148

MoveStake and MoveLamports Instructions

Author: Hanako Mumei · Category: Core Protocol GitHub →

Feature Gate Status

Mainnet Active E727
Testnet Active E699
Devnet Active E798

7bTK6Jis8Xpfrs8ZoUfiMDPazTcdPcTWheZFJTA5Z6X4

TL;DR

We propose introducing two new instructions to the stake program for moving value between stake accounts with identical `Authorized` and `Lockup`: * `MoveStake`: Move a given `amount` of active stake from one active account to another active account, or from an active account to an inactive one, turning it into an active account. If the entire source account delegation is moved, the source account becomes inactive. In all cases, rent-exempt balance is unaffected and minimum delegations are respected for accounts that end in an active state. * `MoveLamports`: Move a given `amount` of excess lamports from one active or inactive account to another active or inactive account, where "excess lamports" refers to lamports that are neither delegated stake nor required for rent-exemption. For simplicity of implementation, we choose not to support accounts that are activating, deactivating, or partially active. A future SIMD may choose to extend this functionality should it be desirable.

Summary

We propose introducing two new instructions to the stake program for moving value between stake accounts with identical `Authorized` and `Lockup`: * `MoveStake`: Move a given `amount` of active stake from one active account to another active account, or from an active account to an inactive one, turning it into an active account. If the entire source account delegation is moved, the source account becomes inactive. In all cases, rent-exempt balance is unaffected and minimum delegations are respected for accounts that end in an active state. * `MoveLamports`: Move a given `amount` of excess lamports from one active or inactive account to another active or inactive account, where "excess lamports" refers to lamports that are neither delegated stake nor required for rent-exemption. For simplicity of implementation, we choose not to support accounts that are activating, deactivating, or partially active. A future SIMD may choose to extend this functionality should it be desirable.

Motivation

Recently, a feature was activated which mandates that `Split` destinations be prefunded with the rent-exempt reserve, because before that, `Split` could be used to deactivate stake immediately, bypassing the cooldown period. However, this has introduced issues for protocols that manage stake on behalf of users without taking `Withdrawer` authority. Particularly, for one that splits user stake across many validators and periodically redelegates between them, every time they want to split part of a user stake to deactivate, the protocol must fund the rent-exemption themselves. And then when that split account is merged, those lamports cannot be reclaimed by the protocol, instead accumulating (undelegated) in the destination merge accounts. The purpose of the `MoveStake` instruction is to enable a flow whereby moving stake from a user's stake accounts U1 -> U2 from validator V1 to validator V2 may proceed: * `MoveStake` the `amount` of stake from the user stake account U1 to an inactive account T holding sufficient lamports for rent exemption. T instantly becomes a second active stake account delegated to V1 with `amount` stake. * `Deactivate` T and wait an epoch. * `DelegateStake` T to V2 and wait an epoch. T becomes an active stake account delegated to V2 with `amount` stake. * `MoveStake` the `amount` stake from T to U2. T returns to its initial inactive state. Stake has moved from U1 to U2 with no outside lamports required and no new undelegated lamports becoming trapped in delegated stake accounts. The motivation for `MoveLamports` is to enable housekeeping tasks such as reclaiming lamports from `Merge` destinations.

Key Changes

  • An "active" stake is in a Stake state with nonzero delegation, 100% of which
  • An "inactive" stake is in an Initialized or Stake state. There is no
  • Source stake account: Writable, owned by the stake program
  • Destination stake account: Writable, owned by the stake program
  • Stake account authority: Read-only signer
  • 0x10 0x00 0x00 0x00, a fixed-value four-byte little-endian unsigned integer
  • amount, an unaligned eight-byte little-endian unsigned integer indicating
  • amount is 0
  • Source or destination are not writable
  • Source or destination are not owned by the stake program
  • Source and destination have the same address
  • Source and destination do not have identical Authorized
  • If Lockup is in force, source and destination do not have identical Lockup
  • The stake account authority is not the Staker on both accounts
  • The stake account authority is not a signer
  • Source data length is not equal to the current version of StakeState
  • Destination data length is not equal to the current version of StakeState
  • Source is not active
  • Destination is neither active nor inactive
  • If destination is active, source and destination are not delegated to the same

Impact

The primary utility of the proposed instructions is to support protocol developers in moving value between stake accounts with the same authorities without controlling the `Withdrawer`. There is no loss of existing functionality.

Security Considerations

Care must be taken to ensure stakes are active, as moving delegations between accounts in any kind of intermediate state is fraught. Otherwise this change should be fairly low impact, as it does not require changing any existing logic, in particular avoiding making `Split` or `Merge` more permissive.