diff --git a/stake-pool/js/src/index.ts b/stake-pool/js/src/index.ts index a65274efb4c..faf95a5e363 100644 --- a/stake-pool/js/src/index.ts +++ b/stake-pool/js/src/index.ts @@ -807,10 +807,11 @@ export async function decreaseValidatorStake( ); } else { instructions.push( - StakePoolInstruction.decreaseValidatorStake({ + StakePoolInstruction.decreaseValidatorStakeWithReserve({ stakePool: stakePoolAddress, staker: stakePool.account.data.staker, validatorList: stakePool.account.data.validatorList, + reserveStake: stakePool.account.data.reserveStake, transientStakeSeed: transientStakeSeed.toNumber(), withdrawAuthority, validatorStake, diff --git a/stake-pool/js/src/instructions.ts b/stake-pool/js/src/instructions.ts index 7c1d645ac8c..9891f17b6c7 100644 --- a/stake-pool/js/src/instructions.ts +++ b/stake-pool/js/src/instructions.ts @@ -35,6 +35,7 @@ export type StakePoolInstructionType = | 'WithdrawSol' | 'IncreaseAdditionalValidatorStake' | 'DecreaseAdditionalValidatorStake' + | 'DecreaseValidatorStakeWithReserve' | 'Redelegate'; // 'UpdateTokenMetadata' and 'CreateTokenMetadata' have dynamic layouts @@ -158,8 +159,12 @@ export const STAKE_POOL_INSTRUCTION_LAYOUTS: { BufferLayout.ns64('ephemeralStakeSeed'), ]), }, - Redelegate: { + DecreaseValidatorStakeWithReserve: { index: 21, + layout: MOVE_STAKE_LAYOUT, + }, + Redelegate: { + index: 22, layout: BufferLayout.struct([ BufferLayout.u8('instruction'), /// Amount of lamports to redelegate @@ -225,6 +230,10 @@ export type DecreaseValidatorStakeParams = { transientStakeSeed: number; }; +export interface DecreaseValidatorStakeWithReserveParams extends DecreaseValidatorStakeParams { + reserveStake: PublicKey; +} + export interface DecreaseAdditionalValidatorStakeParams extends DecreaseValidatorStakeParams { reserveStake: PublicKey; ephemeralStake: PublicKey; @@ -601,6 +610,49 @@ export class StakePoolInstruction { }); } + /** + * Creates `DecreaseValidatorStakeWithReserve` instruction (rebalance from + * validator account to transient account) + */ + static decreaseValidatorStakeWithReserve( + params: DecreaseValidatorStakeWithReserveParams, + ): TransactionInstruction { + const { + stakePool, + staker, + withdrawAuthority, + validatorList, + reserveStake, + validatorStake, + transientStake, + lamports, + transientStakeSeed, + } = params; + + const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseValidatorStakeWithReserve; + const data = encodeData(type, { lamports, transientStakeSeed }); + + const keys = [ + { pubkey: stakePool, isSigner: false, isWritable: false }, + { pubkey: staker, isSigner: true, isWritable: false }, + { pubkey: withdrawAuthority, isSigner: false, isWritable: false }, + { pubkey: validatorList, isSigner: false, isWritable: true }, + { pubkey: reserveStake, isSigner: false, isWritable: true }, + { pubkey: validatorStake, isSigner: false, isWritable: true }, + { pubkey: transientStake, isSigner: false, isWritable: true }, + { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, + { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false }, + { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }, + { pubkey: StakeProgram.programId, isSigner: false, isWritable: false }, + ]; + + return new TransactionInstruction({ + programId: STAKE_POOL_PROGRAM_ID, + keys, + data, + }); + } + /** * Creates `DecreaseAdditionalValidatorStake` instruction (rebalance from * validator account to transient account) diff --git a/stake-pool/js/test/instructions.test.ts b/stake-pool/js/test/instructions.test.ts index 9941d07a0c4..1a39ddffb49 100644 --- a/stake-pool/js/test/instructions.test.ts +++ b/stake-pool/js/test/instructions.test.ts @@ -347,7 +347,7 @@ describe('StakePoolProgram', () => { res.instructions[0].data, ); - expect(decodedData.instruction).toBe(21); + expect(decodedData.instruction).toBe(22); expect(decodedData.lamports).toBe(data.lamports); expect(decodedData.sourceTransientStakeSeed).toBe(data.sourceTransientStakeSeed); expect(decodedData.destinationTransientStakeSeed).toBe(data.destinationTransientStakeSeed);