stake-pool: add redelegate js bindings (#3960)

* - add ts/js binding for redelegate functionality

* - add redelegate instructions

* - refactor

* - force rebuild

* - refactor

* - force rebuild

* - force rebuild
This commit is contained in:
Alexander Ray 2023-01-12 19:56:06 +01:00 committed by GitHub
parent b33bcc055e
commit 6ab15b340e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 434 additions and 30 deletions

View File

@ -51,4 +51,4 @@ console.log(solanaStakePool);
```javascript ```javascript
// `solanaStakePool` is provided in the global namespace by the script bundle. // `solanaStakePool` is provided in the global namespace by the script bundle.
console.log(solanaStakePool); console.log(solanaStakePool);
``` ```

View File

@ -7,6 +7,9 @@ export const STAKE_POOL_PROGRAM_ID = new PublicKey('SPoo1Ku8WFXoNDMHPsrGSTSG1Y47
// Maximum number of validators to update during UpdateValidatorListBalance. // Maximum number of validators to update during UpdateValidatorListBalance.
export const MAX_VALIDATORS_TO_UPDATE = 5; export const MAX_VALIDATORS_TO_UPDATE = 5;
// Seed for ephemeral stake account
export const EPHEMERAL_STAKE_SEED_PREFIX = Buffer.from('ephemeral');
// Seed used to derive transient stake accounts. // Seed used to derive transient stake accounts.
export const TRANSIENT_STAKE_SEED_PREFIX = Buffer.from('transient'); export const TRANSIENT_STAKE_SEED_PREFIX = Buffer.from('transient');

View File

@ -24,6 +24,7 @@ import {
prepareWithdrawAccounts, prepareWithdrawAccounts,
lamportsToSol, lamportsToSol,
solToLamports, solToLamports,
findEphemeralStakeProgramAddress,
} from './utils'; } from './utils';
import { StakePoolInstruction } from './instructions'; import { StakePoolInstruction } from './instructions';
import { import {
@ -36,6 +37,7 @@ import {
} from './layouts'; } from './layouts';
import { MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, STAKE_POOL_PROGRAM_ID } from './constants'; import { MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, STAKE_POOL_PROGRAM_ID } from './constants';
import { create } from 'superstruct'; import { create } from 'superstruct';
import BN from 'bn.js';
export type { StakePool, AccountType, ValidatorList, ValidatorStakeInfo } from './layouts'; export type { StakePool, AccountType, ValidatorList, ValidatorStakeInfo } from './layouts';
export { STAKE_POOL_PROGRAM_ID } from './constants'; export { STAKE_POOL_PROGRAM_ID } from './constants';
@ -66,6 +68,17 @@ export interface StakePoolAccounts {
validatorList: ValidatorListAccount | undefined; validatorList: ValidatorListAccount | undefined;
} }
interface RedelegateProps {
connection: Connection;
stakePoolAddress: PublicKey;
sourceVoteAccount: PublicKey;
destinationVoteAccount: PublicKey;
sourceTransientStakeSeed: number | BN;
destinationTransientStakeSeed: number | BN;
ephemeralStakeSeed: number | BN;
lamports: number | BN;
}
/** /**
* Retrieves and deserializes a StakePool account using a web3js connection and the stake pool address. * Retrieves and deserializes a StakePool account using a web3js connection and the stake pool address.
* @param connection: An active web3js connection. * @param connection: An active web3js connection.
@ -401,7 +414,7 @@ export async function withdrawStake(
val.voteAccountAddress.equals(voteAccount), val.voteAccountAddress.equals(voteAccount),
); );
if (voteAccountAddress && voteAccountAddress !== voteAccount) { if (voteAccountAddress && voteAccountAddress !== voteAccount) {
throw new Error(`Provided withdrawal vote account ${voteAccountAddress} does not match delegation on stake receiver account ${voteAccount}, throw new Error(`Provided withdrawal vote account ${voteAccountAddress} does not match delegation on stake receiver account ${voteAccount},
remove this flag or provide a different stake account delegated to ${voteAccountAddress}`); remove this flag or provide a different stake account delegated to ${voteAccountAddress}`);
} }
if (isValidVoter) { if (isValidVoter) {
@ -668,6 +681,7 @@ export async function increaseValidatorStake(
stakePoolAddress: PublicKey, stakePoolAddress: PublicKey,
validatorVote: PublicKey, validatorVote: PublicKey,
lamports: number, lamports: number,
ephemeralStakeSeed?: number,
) { ) {
const stakePool = await getStakePoolAccount(connection, stakePoolAddress); const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
@ -705,8 +719,14 @@ export async function increaseValidatorStake(
); );
const instructions: TransactionInstruction[] = []; const instructions: TransactionInstruction[] = [];
instructions.push(
StakePoolInstruction.increaseValidatorStake({ if (ephemeralStakeSeed != undefined) {
const ephemeralStake = await findEphemeralStakeProgramAddress(
STAKE_POOL_PROGRAM_ID,
stakePoolAddress,
new BN(ephemeralStakeSeed),
);
StakePoolInstruction.increaseAdditionalValidatorStake({
stakePool: stakePoolAddress, stakePool: stakePoolAddress,
staker: stakePool.account.data.staker, staker: stakePool.account.data.staker,
validatorList: stakePool.account.data.validatorList, validatorList: stakePool.account.data.validatorList,
@ -717,8 +737,25 @@ export async function increaseValidatorStake(
validatorStake, validatorStake,
validatorVote, validatorVote,
lamports, lamports,
}), ephemeralStake,
); ephemeralStakeSeed,
});
} else {
instructions.push(
StakePoolInstruction.increaseValidatorStake({
stakePool: stakePoolAddress,
staker: stakePool.account.data.staker,
validatorList: stakePool.account.data.validatorList,
reserveStake: stakePool.account.data.reserveStake,
transientStakeSeed: transientStakeSeed.toNumber(),
withdrawAuthority,
transientStake,
validatorStake,
validatorVote,
lamports,
}),
);
}
return { return {
instructions, instructions,
@ -733,6 +770,7 @@ export async function decreaseValidatorStake(
stakePoolAddress: PublicKey, stakePoolAddress: PublicKey,
validatorVote: PublicKey, validatorVote: PublicKey,
lamports: number, lamports: number,
ephemeralStakeSeed?: number,
) { ) {
const stakePool = await getStakePoolAccount(connection, stakePoolAddress); const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
const validatorList = await getValidatorListAccount( const validatorList = await getValidatorListAccount(
@ -769,18 +807,41 @@ export async function decreaseValidatorStake(
); );
const instructions: TransactionInstruction[] = []; const instructions: TransactionInstruction[] = [];
instructions.push(
StakePoolInstruction.decreaseValidatorStake({ if (ephemeralStakeSeed != undefined) {
stakePool: stakePoolAddress, const ephemeralStake = await findEphemeralStakeProgramAddress(
staker: stakePool.account.data.staker, STAKE_POOL_PROGRAM_ID,
validatorList: stakePool.account.data.validatorList, stakePoolAddress,
transientStakeSeed: transientStakeSeed.toNumber(), new BN(ephemeralStakeSeed),
withdrawAuthority, );
validatorStake, instructions.push(
transientStake, StakePoolInstruction.decreaseAdditionalValidatorStake({
lamports, stakePool: stakePoolAddress,
}), staker: stakePool.account.data.staker,
); validatorList: stakePool.account.data.validatorList,
transientStakeSeed: transientStakeSeed.toNumber(),
withdrawAuthority,
validatorStake,
transientStake,
lamports,
ephemeralStake,
ephemeralStakeSeed,
}),
);
} else {
instructions.push(
StakePoolInstruction.decreaseValidatorStake({
stakePool: stakePoolAddress,
staker: stakePool.account.data.staker,
validatorList: stakePool.account.data.validatorList,
transientStakeSeed: transientStakeSeed.toNumber(),
withdrawAuthority,
validatorStake,
transientStake,
lamports,
}),
);
}
return { return {
instructions, instructions,
@ -993,3 +1054,82 @@ export async function stakePoolInfo(connection: Connection, stakePoolAddress: Pu
}, // CliStakePoolDetails }, // CliStakePoolDetails
}; };
} }
/**
* Creates instructions required to redelegate stake.
*/
export async function redelegate(props: RedelegateProps) {
const {
connection,
stakePoolAddress,
sourceVoteAccount,
sourceTransientStakeSeed,
destinationVoteAccount,
destinationTransientStakeSeed,
ephemeralStakeSeed,
lamports,
} = props;
const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
const stakePoolWithdrawAuthority = await findWithdrawAuthorityProgramAddress(
STAKE_POOL_PROGRAM_ID,
stakePoolAddress,
);
const sourceValidatorStake = await findStakeProgramAddress(
STAKE_POOL_PROGRAM_ID,
sourceVoteAccount,
stakePoolAddress,
);
const sourceTransientStake = await findTransientStakeProgramAddress(
STAKE_POOL_PROGRAM_ID,
sourceVoteAccount,
stakePoolAddress,
new BN(sourceTransientStakeSeed),
);
const destinationValidatorStake = await findStakeProgramAddress(
STAKE_POOL_PROGRAM_ID,
destinationVoteAccount,
stakePoolAddress,
);
const destinationTransientStake = await findTransientStakeProgramAddress(
STAKE_POOL_PROGRAM_ID,
destinationVoteAccount,
stakePoolAddress,
new BN(destinationTransientStakeSeed),
);
const ephemeralStake = await findEphemeralStakeProgramAddress(
STAKE_POOL_PROGRAM_ID,
stakePoolAddress,
new BN(ephemeralStakeSeed),
);
const instructions: TransactionInstruction[] = [];
instructions.push(
StakePoolInstruction.redelegate({
stakePool: stakePool.pubkey,
staker: stakePool.account.data.staker,
validatorList: stakePool.account.data.validatorList,
stakePoolWithdrawAuthority,
ephemeralStake,
ephemeralStakeSeed,
sourceValidatorStake,
sourceTransientStake,
sourceTransientStakeSeed,
destinationValidatorStake,
destinationTransientStake,
destinationTransientStakeSeed,
validator: destinationVoteAccount,
lamports,
}),
);
return {
instructions,
};
}

View File

@ -12,6 +12,7 @@ import * as BufferLayout from '@solana/buffer-layout';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { STAKE_POOL_PROGRAM_ID } from './constants'; import { STAKE_POOL_PROGRAM_ID } from './constants';
import { InstructionType, encodeData, decodeData } from './utils'; import { InstructionType, encodeData, decodeData } from './utils';
import BN from 'bn.js';
/** /**
* An enumeration of valid StakePoolInstructionType's * An enumeration of valid StakePoolInstructionType's
@ -25,7 +26,10 @@ export type StakePoolInstructionType =
| 'DepositStake' | 'DepositStake'
| 'DepositSol' | 'DepositSol'
| 'WithdrawStake' | 'WithdrawStake'
| 'WithdrawSol'; | 'WithdrawSol'
| 'IncreaseAdditionalValidatorStake'
| 'DecreaseAdditionalValidatorStake'
| 'Redelegate';
const MOVE_STAKE_LAYOUT = BufferLayout.struct<any>([ const MOVE_STAKE_LAYOUT = BufferLayout.struct<any>([
BufferLayout.u8('instruction'), BufferLayout.u8('instruction'),
@ -96,6 +100,40 @@ export const STAKE_POOL_INSTRUCTION_LAYOUTS: {
BufferLayout.ns64('poolTokens'), BufferLayout.ns64('poolTokens'),
]), ]),
}, },
IncreaseAdditionalValidatorStake: {
index: 19,
layout: BufferLayout.struct<any>([
BufferLayout.u8('instruction'),
BufferLayout.ns64('lamports'),
BufferLayout.ns64('transientStakeSeed'),
BufferLayout.ns64('ephemeralStakeSeed'),
]),
},
DecreaseAdditionalValidatorStake: {
index: 20,
layout: BufferLayout.struct<any>([
BufferLayout.u8('instruction'),
BufferLayout.ns64('lamports'),
BufferLayout.ns64('transientStakeSeed'),
BufferLayout.ns64('ephemeralStakeSeed'),
]),
},
Redelegate: {
index: 21,
layout: BufferLayout.struct<any>([
BufferLayout.u8('instruction'),
/// Amount of lamports to redelegate
BufferLayout.ns64('lamports'),
/// Seed used to create source transient stake account
BufferLayout.ns64('sourceTransientStakeSeed'),
/// Seed used to create destination ephemeral account.
BufferLayout.ns64('ephemeralStakeSeed'),
/// Seed used to create destination transient stake account. If there is
/// already transient stake, this must match the current seed, otherwise
/// it can be anything
BufferLayout.ns64('destinationTransientStakeSeed'),
]),
},
}); });
/** /**
@ -141,12 +179,17 @@ export type DecreaseValidatorStakeParams = {
validatorList: PublicKey; validatorList: PublicKey;
validatorStake: PublicKey; validatorStake: PublicKey;
transientStake: PublicKey; transientStake: PublicKey;
// Amount of lamports to split into the transient stake account. // Amount of lamports to split into the transient stake account
lamports: number; lamports: number;
// Seed to used to create the transient stake account. // Seed to used to create the transient stake account
transientStakeSeed: number; transientStakeSeed: number;
}; };
export interface DecreaseAdditionalValidatorStakeParams extends DecreaseValidatorStakeParams {
ephemeralStake: PublicKey;
ephemeralStakeSeed: number;
}
/** /**
* (Staker only) Increase stake on a validator from the reserve account. * (Staker only) Increase stake on a validator from the reserve account.
*/ */
@ -159,12 +202,17 @@ export type IncreaseValidatorStakeParams = {
transientStake: PublicKey; transientStake: PublicKey;
validatorStake: PublicKey; validatorStake: PublicKey;
validatorVote: PublicKey; validatorVote: PublicKey;
// Amount of lamports to split into the transient stake account. // Amount of lamports to split into the transient stake account
lamports: number; lamports: number;
// Seed to used to create the transient stake account. // Seed to used to create the transient stake account
transientStakeSeed: number; transientStakeSeed: number;
}; };
export interface IncreaseAdditionalValidatorStakeParams extends IncreaseValidatorStakeParams {
ephemeralStake: PublicKey;
ephemeralStakeSeed: number;
}
/** /**
* Deposits a stake account into the pool in exchange for pool tokens * Deposits a stake account into the pool in exchange for pool tokens
*/ */
@ -232,6 +280,29 @@ export type DepositSolParams = {
lamports: number; lamports: number;
}; };
export type RedelegateParams = {
stakePool: PublicKey;
staker: PublicKey;
stakePoolWithdrawAuthority: PublicKey;
validatorList: PublicKey;
sourceValidatorStake: PublicKey;
sourceTransientStake: PublicKey;
ephemeralStake: PublicKey;
destinationTransientStake: PublicKey;
destinationValidatorStake: PublicKey;
validator: PublicKey;
// Amount of lamports to redelegate
lamports: number | BN;
// Seed used to create source transient stake account
sourceTransientStakeSeed: number | BN;
// Seed used to create destination ephemeral account
ephemeralStakeSeed: number | BN;
// Seed used to create destination transient stake account. If there is
// already transient stake, this must match the current seed, otherwise
// it can be anything
destinationTransientStakeSeed: number | BN;
};
/** /**
* Stake Pool Instruction class * Stake Pool Instruction class
*/ */
@ -334,7 +405,8 @@ export class StakePoolInstruction {
} }
/** /**
* Creates instruction to increase the stake on a validator. * Creates `IncreaseValidatorStake` instruction (rebalance from reserve account to
* transient account)
*/ */
static increaseValidatorStake(params: IncreaseValidatorStakeParams): TransactionInstruction { static increaseValidatorStake(params: IncreaseValidatorStakeParams): TransactionInstruction {
const { const {
@ -378,7 +450,57 @@ export class StakePoolInstruction {
} }
/** /**
* Creates instruction to decrease the stake on a validator. * Creates `IncreaseAdditionalValidatorStake` instruction (rebalance from reserve account to
* transient account)
*/
static increaseAdditionalValidatorStake(
params: IncreaseAdditionalValidatorStakeParams,
): TransactionInstruction {
const {
stakePool,
staker,
withdrawAuthority,
validatorList,
reserveStake,
transientStake,
validatorStake,
validatorVote,
lamports,
transientStakeSeed,
ephemeralStake,
ephemeralStakeSeed,
} = params;
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.IncreaseAdditionalValidatorStake;
const data = encodeData(type, { lamports, transientStakeSeed, ephemeralStakeSeed });
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: ephemeralStake, isSigner: false, isWritable: true },
{ pubkey: transientStake, isSigner: false, isWritable: true },
{ pubkey: validatorStake, isSigner: false, isWritable: false },
{ pubkey: validatorVote, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: STAKE_CONFIG_ID, 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 `DecreaseValidatorStake` instruction (rebalance from validator account to
* transient account)
*/ */
static decreaseValidatorStake(params: DecreaseValidatorStakeParams): TransactionInstruction { static decreaseValidatorStake(params: DecreaseValidatorStakeParams): TransactionInstruction {
const { const {
@ -415,6 +537,50 @@ export class StakePoolInstruction {
}); });
} }
/**
* Creates `DecreaseAdditionalValidatorStake` instruction (rebalance from
* validator account to transient account)
*/
static decreaseAdditionalValidatorStake(
params: DecreaseAdditionalValidatorStakeParams,
): TransactionInstruction {
const {
stakePool,
staker,
withdrawAuthority,
validatorList,
validatorStake,
transientStake,
lamports,
transientStakeSeed,
ephemeralStakeSeed,
ephemeralStake,
} = params;
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseAdditionalValidatorStake;
const data = encodeData(type, { lamports, transientStakeSeed, ephemeralStakeSeed });
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: validatorStake, isSigner: false, isWritable: true },
{ pubkey: ephemeralStake, 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 a transaction instruction to deposit a stake account into a stake pool. * Creates a transaction instruction to deposit a stake account into a stake pool.
*/ */
@ -603,6 +769,60 @@ export class StakePoolInstruction {
}); });
} }
/**
* Creates `Redelegate` instruction (rebalance from one validator account to another)
* @param params
*/
static redelegate(params: RedelegateParams): TransactionInstruction {
const {
stakePool,
staker,
stakePoolWithdrawAuthority,
validatorList,
sourceValidatorStake,
sourceTransientStake,
ephemeralStake,
destinationTransientStake,
destinationValidatorStake,
validator,
lamports,
sourceTransientStakeSeed,
ephemeralStakeSeed,
destinationTransientStakeSeed,
} = params;
const keys = [
{ pubkey: stakePool, isSigner: false, isWritable: false },
{ pubkey: staker, isSigner: true, isWritable: false },
{ pubkey: stakePoolWithdrawAuthority, isSigner: false, isWritable: false },
{ pubkey: validatorList, isSigner: false, isWritable: true },
{ pubkey: sourceValidatorStake, isSigner: false, isWritable: true },
{ pubkey: sourceTransientStake, isSigner: false, isWritable: true },
{ pubkey: ephemeralStake, isSigner: false, isWritable: true },
{ pubkey: destinationTransientStake, isSigner: false, isWritable: true },
{ pubkey: destinationValidatorStake, isSigner: false, isWritable: false },
{ pubkey: validator, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
{ pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
{ pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
];
const data = encodeData(STAKE_POOL_INSTRUCTION_LAYOUTS.Redelegate, {
lamports,
sourceTransientStakeSeed,
ephemeralStakeSeed,
destinationTransientStakeSeed,
});
return new TransactionInstruction({
programId: STAKE_POOL_PROGRAM_ID,
keys,
data,
});
}
/** /**
* Decode a deposit stake pool instruction and retrieve the instruction params. * Decode a deposit stake pool instruction and retrieve the instruction params.
*/ */

View File

@ -1,7 +1,7 @@
import { PublicKey } from '@solana/web3.js'; import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js'; import BN from 'bn.js';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import { TRANSIENT_STAKE_SEED_PREFIX } from '../constants'; import { EPHEMERAL_STAKE_SEED_PREFIX, TRANSIENT_STAKE_SEED_PREFIX } from '../constants';
/** /**
* Generates the withdraw authority program address for the stake pool * Generates the withdraw authority program address for the stake pool
@ -46,9 +46,24 @@ export async function findTransientStakeProgramAddress(
TRANSIENT_STAKE_SEED_PREFIX, TRANSIENT_STAKE_SEED_PREFIX,
voteAccountAddress.toBuffer(), voteAccountAddress.toBuffer(),
stakePoolAddress.toBuffer(), stakePoolAddress.toBuffer(),
new Uint8Array(seed.toArray('le', 8)), seed.toBuffer('le', 8),
], ],
programId, programId,
); );
return publicKey; return publicKey;
} }
/**
* Generates the ephemeral program address for stake pool redelegation
*/
export async function findEphemeralStakeProgramAddress(
programId: PublicKey,
stakePoolAddress: PublicKey,
seed: BN,
) {
const [publicKey] = await PublicKey.findProgramAddress(
[EPHEMERAL_STAKE_SEED_PREFIX, stakePoolAddress.toBuffer(), seed.toBuffer('le', 8)],
programId,
);
return publicKey;
}

View File

@ -15,6 +15,7 @@ import {
depositSol, depositSol,
withdrawSol, withdrawSol,
withdrawStake, withdrawStake,
redelegate,
getStakeAccount, getStakeAccount,
} from '../src'; } from '../src';
@ -317,4 +318,30 @@ describe('StakePoolProgram', () => {
expect(parsedStakeAccount).toEqual(uninitializedStakeAccount.parsed); expect(parsedStakeAccount).toEqual(uninitializedStakeAccount.parsed);
}); });
}); });
describe('redelegation', () => {
it.only('should call successfully', async () => {
const data = {
connection,
stakePoolAddress,
sourceVoteAccount: PublicKey.default,
sourceTransientStakeSeed: 10,
destinationVoteAccount: PublicKey.default,
destinationTransientStakeSeed: 20,
ephemeralStakeSeed: 100,
lamports: 100,
};
const res = await redelegate(data);
const decodedData = STAKE_POOL_INSTRUCTION_LAYOUTS.Redelegate.layout.decode(
res.instructions[0].data,
);
expect(decodedData.instruction).toBe(21);
expect(decodedData.lamports).toBe(data.lamports);
expect(decodedData.sourceTransientStakeSeed).toBe(data.sourceTransientStakeSeed);
expect(decodedData.destinationTransientStakeSeed).toBe(data.destinationTransientStakeSeed);
expect(decodedData.ephemeralStakeSeed).toBe(data.ephemeralStakeSeed);
});
});
}); });

View File

@ -1,7 +1,7 @@
import { AccountInfo, LAMPORTS_PER_SOL, PublicKey, StakeProgram } from '@solana/web3.js'; import { AccountInfo, LAMPORTS_PER_SOL, PublicKey, StakeProgram } from '@solana/web3.js';
import BN from 'bn.js'; import BN from 'bn.js';
import { ValidatorStakeInfo } from '../src'; import { ValidatorStakeInfo } from '../src';
import { ValidatorStakeInfoStatus, AccountLayout, ValidatorListLayout } from '../src/layouts'; import { AccountLayout, ValidatorListLayout, ValidatorStakeInfoStatus } from '../src/layouts';
export const CONSTANTS = { export const CONSTANTS = {
poolTokenAccount: new PublicKey( poolTokenAccount: new PublicKey(
@ -149,13 +149,12 @@ export const mockRpc = (data: any): any => {
executable: false, executable: false,
rentEpoch: 0, rentEpoch: 0,
}; };
const result = { return {
context: { context: {
slot: 11, slot: 11,
}, },
value: value, value: value,
}; };
return result;
}; };
export const stakeAccountData = { export const stakeAccountData = {