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:
parent
b33bcc055e
commit
6ab15b340e
|
@ -51,4 +51,4 @@ console.log(solanaStakePool);
|
|||
```javascript
|
||||
// `solanaStakePool` is provided in the global namespace by the script bundle.
|
||||
console.log(solanaStakePool);
|
||||
```
|
||||
```
|
||||
|
|
|
@ -7,6 +7,9 @@ export const STAKE_POOL_PROGRAM_ID = new PublicKey('SPoo1Ku8WFXoNDMHPsrGSTSG1Y47
|
|||
// Maximum number of validators to update during UpdateValidatorListBalance.
|
||||
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.
|
||||
export const TRANSIENT_STAKE_SEED_PREFIX = Buffer.from('transient');
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
prepareWithdrawAccounts,
|
||||
lamportsToSol,
|
||||
solToLamports,
|
||||
findEphemeralStakeProgramAddress,
|
||||
} from './utils';
|
||||
import { StakePoolInstruction } from './instructions';
|
||||
import {
|
||||
|
@ -36,6 +37,7 @@ import {
|
|||
} from './layouts';
|
||||
import { MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, STAKE_POOL_PROGRAM_ID } from './constants';
|
||||
import { create } from 'superstruct';
|
||||
import BN from 'bn.js';
|
||||
|
||||
export type { StakePool, AccountType, ValidatorList, ValidatorStakeInfo } from './layouts';
|
||||
export { STAKE_POOL_PROGRAM_ID } from './constants';
|
||||
|
@ -66,6 +68,17 @@ export interface StakePoolAccounts {
|
|||
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.
|
||||
* @param connection: An active web3js connection.
|
||||
|
@ -401,7 +414,7 @@ export async function withdrawStake(
|
|||
val.voteAccountAddress.equals(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}`);
|
||||
}
|
||||
if (isValidVoter) {
|
||||
|
@ -668,6 +681,7 @@ export async function increaseValidatorStake(
|
|||
stakePoolAddress: PublicKey,
|
||||
validatorVote: PublicKey,
|
||||
lamports: number,
|
||||
ephemeralStakeSeed?: number,
|
||||
) {
|
||||
const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
|
||||
|
||||
|
@ -705,8 +719,14 @@ export async function increaseValidatorStake(
|
|||
);
|
||||
|
||||
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,
|
||||
staker: stakePool.account.data.staker,
|
||||
validatorList: stakePool.account.data.validatorList,
|
||||
|
@ -717,8 +737,25 @@ export async function increaseValidatorStake(
|
|||
validatorStake,
|
||||
validatorVote,
|
||||
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 {
|
||||
instructions,
|
||||
|
@ -733,6 +770,7 @@ export async function decreaseValidatorStake(
|
|||
stakePoolAddress: PublicKey,
|
||||
validatorVote: PublicKey,
|
||||
lamports: number,
|
||||
ephemeralStakeSeed?: number,
|
||||
) {
|
||||
const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
|
||||
const validatorList = await getValidatorListAccount(
|
||||
|
@ -769,18 +807,41 @@ export async function decreaseValidatorStake(
|
|||
);
|
||||
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
instructions.push(
|
||||
StakePoolInstruction.decreaseValidatorStake({
|
||||
stakePool: stakePoolAddress,
|
||||
staker: stakePool.account.data.staker,
|
||||
validatorList: stakePool.account.data.validatorList,
|
||||
transientStakeSeed: transientStakeSeed.toNumber(),
|
||||
withdrawAuthority,
|
||||
validatorStake,
|
||||
transientStake,
|
||||
lamports,
|
||||
}),
|
||||
);
|
||||
|
||||
if (ephemeralStakeSeed != undefined) {
|
||||
const ephemeralStake = await findEphemeralStakeProgramAddress(
|
||||
STAKE_POOL_PROGRAM_ID,
|
||||
stakePoolAddress,
|
||||
new BN(ephemeralStakeSeed),
|
||||
);
|
||||
instructions.push(
|
||||
StakePoolInstruction.decreaseAdditionalValidatorStake({
|
||||
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 {
|
||||
instructions,
|
||||
|
@ -993,3 +1054,82 @@ export async function stakePoolInfo(connection: Connection, stakePoolAddress: Pu
|
|||
}, // 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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import * as BufferLayout from '@solana/buffer-layout';
|
|||
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
||||
import { STAKE_POOL_PROGRAM_ID } from './constants';
|
||||
import { InstructionType, encodeData, decodeData } from './utils';
|
||||
import BN from 'bn.js';
|
||||
|
||||
/**
|
||||
* An enumeration of valid StakePoolInstructionType's
|
||||
|
@ -25,7 +26,10 @@ export type StakePoolInstructionType =
|
|||
| 'DepositStake'
|
||||
| 'DepositSol'
|
||||
| 'WithdrawStake'
|
||||
| 'WithdrawSol';
|
||||
| 'WithdrawSol'
|
||||
| 'IncreaseAdditionalValidatorStake'
|
||||
| 'DecreaseAdditionalValidatorStake'
|
||||
| 'Redelegate';
|
||||
|
||||
const MOVE_STAKE_LAYOUT = BufferLayout.struct<any>([
|
||||
BufferLayout.u8('instruction'),
|
||||
|
@ -96,6 +100,40 @@ export const STAKE_POOL_INSTRUCTION_LAYOUTS: {
|
|||
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;
|
||||
validatorStake: 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;
|
||||
// Seed to used to create the transient stake account.
|
||||
// Seed to used to create the transient stake account
|
||||
transientStakeSeed: number;
|
||||
};
|
||||
|
||||
export interface DecreaseAdditionalValidatorStakeParams extends DecreaseValidatorStakeParams {
|
||||
ephemeralStake: PublicKey;
|
||||
ephemeralStakeSeed: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Staker only) Increase stake on a validator from the reserve account.
|
||||
*/
|
||||
|
@ -159,12 +202,17 @@ export type IncreaseValidatorStakeParams = {
|
|||
transientStake: PublicKey;
|
||||
validatorStake: 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;
|
||||
// Seed to used to create the transient stake account.
|
||||
// Seed to used to create the transient stake account
|
||||
transientStakeSeed: number;
|
||||
};
|
||||
|
||||
export interface IncreaseAdditionalValidatorStakeParams extends IncreaseValidatorStakeParams {
|
||||
ephemeralStake: PublicKey;
|
||||
ephemeralStakeSeed: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposits a stake account into the pool in exchange for pool tokens
|
||||
*/
|
||||
|
@ -232,6 +280,29 @@ export type DepositSolParams = {
|
|||
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
|
||||
*/
|
||||
|
@ -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 {
|
||||
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 {
|
||||
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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { PublicKey } from '@solana/web3.js';
|
||||
import BN from 'bn.js';
|
||||
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
|
||||
|
@ -46,9 +46,24 @@ export async function findTransientStakeProgramAddress(
|
|||
TRANSIENT_STAKE_SEED_PREFIX,
|
||||
voteAccountAddress.toBuffer(),
|
||||
stakePoolAddress.toBuffer(),
|
||||
new Uint8Array(seed.toArray('le', 8)),
|
||||
seed.toBuffer('le', 8),
|
||||
],
|
||||
programId,
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
depositSol,
|
||||
withdrawSol,
|
||||
withdrawStake,
|
||||
redelegate,
|
||||
getStakeAccount,
|
||||
} from '../src';
|
||||
|
||||
|
@ -317,4 +318,30 @@ describe('StakePoolProgram', () => {
|
|||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AccountInfo, LAMPORTS_PER_SOL, PublicKey, StakeProgram } from '@solana/web3.js';
|
||||
import BN from 'bn.js';
|
||||
import { ValidatorStakeInfo } from '../src';
|
||||
import { ValidatorStakeInfoStatus, AccountLayout, ValidatorListLayout } from '../src/layouts';
|
||||
import { AccountLayout, ValidatorListLayout, ValidatorStakeInfoStatus } from '../src/layouts';
|
||||
|
||||
export const CONSTANTS = {
|
||||
poolTokenAccount: new PublicKey(
|
||||
|
@ -149,13 +149,12 @@ export const mockRpc = (data: any): any => {
|
|||
executable: false,
|
||||
rentEpoch: 0,
|
||||
};
|
||||
const result = {
|
||||
return {
|
||||
context: {
|
||||
slot: 11,
|
||||
},
|
||||
value: value,
|
||||
};
|
||||
return result;
|
||||
};
|
||||
|
||||
export const stakeAccountData = {
|
||||
|
|
Loading…
Reference in New Issue