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)
)