Assertions

Assert Account Delta

AssertStakeAccount Instruction

The AssertStakeAccount instruction is for making assertions on the various states and fields of a stake account.

This could also be accomplished by using the AssertAccountData instruction, but this instruction is a convenience instruction for stake accounts which checks that the account is owned by the stake program and maps enums to offset / type deserialization.

The stake account is an enum that looks like

pub enum StakeStateV2 {
    Uninitialized,
    Initialized(Meta),
    Stake(Meta, Stake, StakeFlags),
    RewardsPool,
}

And the assertion types for a stake account are as follows:

pub enum StakeAccountAssertion {
    State {
        value: StakeStateType,
        operator: EquatableOperator,
    },
    MetaAssertion(MetaAssertion),
    StakeAssertion(StakeAssertion),
    StakeFlags {
        value: u8,
        operator: IntegerOperator,
    },
}

You can make assertions about the Meta and Stake fields of the stake account, as well as the StakeFlags. StakeAccountAssertionState is an assertion type that lets you assert on the state of the account.

If you make an assertion about the Meta or Stake structs and the stake account is in the Uninitialized or RewardsPool state, the assertion will fail.

If you make an assertion about the StakeFlags field and the account is in the Uninitialized, RewardsPool, or Initialized state, the assertion will fail.

The MetaAssertion and StakeAssertion enums are as follows:

pub enum MetaAssertion {
    RentExemptReserve {
        value: u64,
        operator: IntegerOperator,
    },
    AuthorizedStaker {
        value: Pubkey,
        operator: EquatableOperator,
    },
    AuthorizedWithdrawer {
        value: Pubkey,
        operator: EquatableOperator,
    },
    LockupUnixTimestamp {
        value: i64,
        operator: IntegerOperator,
    },
    LockupEpoch {
        value: u64,
        operator: IntegerOperator,
    },
    LockupCustodian {
        value: Pubkey,
        operator: EquatableOperator,
    },
}
pub enum StakeAssertion {
    DelegationVoterPubkey {
        value: Pubkey,
        operator: EquatableOperator,
    },
    DelegationStake {
        value: u64,
        operator: IntegerOperator,
    },
    DelegationActivationEpoch {
        value: u64,
        operator: IntegerOperator,
    },
    DelegationDeactivationEpoch {
        value: u64,
        operator: IntegerOperator,
    },
    CreditsObserved {
        value: u64,
        operator: IntegerOperator,
    },
}

Example: Asserting on the state of a stake account

In this example, we assert that the stake account is in the Stake state.

Assert state instruction

const tx = await pipe(
  createTransaction({ version: 0 }),
  (tx) =>
    appendTransactionInstructions(
      [
        getAssertTokenAccountMultiInstruction({
          targetAccount: stakeAccount,
          assertions: [
            stakeAccountAssertion('State', {
              value: StakeStateType.Stake,
              operator: EquatableOperator.Equal,
            }),
          ],
        }),
      ],
      tx
    ),
  (tx) => setTransactionFeePayer(userKey, tx),
  (tx) => setTransactionLifetimeUsingBlockhash(recentBlockhash, tx),
  (tx) => signTransaction([userKeyPair], tx)
)

Example: Asserting on the meta of a stake account

Using the solana_sdk and deserializing an example state account in the state of Stake or Initialized, we can make assertions on the stake account. The following assertions will pass:

Assert meta instruction

const tx = await pipe(
  createTransaction({ version: 0 }),
  (tx) =>
    appendTransactionInstructions(
      [
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: metaAssertion('LockupCustodian', {
            value: meta.lockup.custodian,
            operator: EquatableOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: metaAssertion('LockupEpoch', {
            value: meta.lockup.epoch,
            operator: IntegerOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: metaAssertion('LockupUnixTimestamp', {
            value: meta.lockup.unixTimestamp,
            operator: IntegerOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: metaAssertion('AuthorizedStaker', {
            value: meta.authorized.staker,
            operator: EquatableOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: metaAssertion('AuthorizedWithdrawer', {
            value: meta.authorized.withdrawer,
            operator: EquatableOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: metaAssertion('RentExemptReserve', {
            value: meta.rentExemptReserve,
            operator: IntegerOperator.Equal,
          }),
        }),
      ],
      tx
    ),
  (tx) => setTransactionFeePayer(userKey, tx),
  (tx) => setTransactionLifetimeUsingBlockhash(recentBlockhash, tx),
  (tx) => signTransaction([userKeyPair], tx)
)

Example: Asserting on the stake state of a stake account

Using the solana_sdk and deserializing an example state account in the state of Stake, we can make assertions on the stake account. The following assertions will pass:

Assert stake instruction

const tx = await pipe(
  createTransaction({ version: 0 }),
  (tx) =>
    appendTransactionInstructions(
      [
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeAssertion', {
            __kind: 'CreditsObserved',
            value: stake.creditsObserved,
            operator: IntegerOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeAssertion', {
            __kind: 'DelegationStake',
            value: stake.delegation.stake,
            operator: IntegerOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeAssertion', {
            __kind: 'DelegationDeactivationEpoch',
            value: stake.delegation.deactivationEpoch,
            operator: IntegerOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeAssertion', {
            __kind: 'DelegationActivationEpoch',
            value: stake.delegation.activationEpoch,
            operator: IntegerOperator.Equal,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeAssertion', {
            __kind: 'DelegationVoterPubkey',
            value: stake.delegation.voterPubkey,
            operator: EquatableOperator.Equal,
          }),
        }),
      ],
      tx
    ),
  (tx) => setTransactionFeePayer(userKey, tx),
  (tx) => setTransactionLifetimeUsingBlockhash(recentBlockhash, tx),
  (tx) => signTransaction([userKeyPair], tx)
)

Example: Asserting on the stake flags of a stake account

The IntegerOperator allows you to make bitwise assertions on the StakeFlags field of the stake account.

Assuming the StakeFlags of a particular stake account is 0b00000000, the following assertions will pass:

Assert stake flags instruction

const tx = await pipe(
  createTransaction({ version: 0 }),
  (tx) =>
    appendTransactionInstructions(
      [
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeFlags', {
            value: 255,
            operator: IntegerOperator.DoesNotContain,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeFlags', {
            value: 0,
            operator: IntegerOperator.Contains,
          }),
        }),
        getAssertStakeAccountInstruction({
          targetAccount: stakeAccount,
          assertion: stakeAccountAssertion('StakeFlags', {
            value: 0,
            operator: IntegerOperator.Equal,
          }),
        }),
      ],
      tx
    ),
  (tx) => setTransactionFeePayer(userKey, tx),
  (tx) => setTransactionLifetimeUsingBlockhash(recentBlockhash, tx),
  (tx) => signTransaction([userKeyPair], tx)
)
Previous
Token Account