feat(stake-program): support `splitWithSeed` (#23213)

This commit is contained in:
mooori 2022-02-17 20:21:07 +01:00 committed by GitHub
parent ae7fedf0b1
commit 5726f42a7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 135 additions and 18 deletions

View File

@ -147,6 +147,18 @@ export type SplitStakeParams = {
lamports: number;
};
/**
* Split with seed transaction params
*/
export type SplitStakeWithSeedParams = {
stakePubkey: PublicKey;
authorizedPubkey: PublicKey;
splitStakePubkey: PublicKey;
basePubkey: PublicKey;
seed: string;
lamports: number;
};
/**
* Withdraw stake instruction params
*/
@ -706,25 +718,13 @@ export class StakeProgram {
}
/**
* Generate a Transaction that splits Stake tokens into another stake account
* @internal
*/
static split(params: SplitStakeParams): Transaction {
static splitInstruction(params: SplitStakeParams): TransactionInstruction {
const {stakePubkey, authorizedPubkey, splitStakePubkey, lamports} = params;
const transaction = new Transaction();
transaction.add(
SystemProgram.createAccount({
fromPubkey: authorizedPubkey,
newAccountPubkey: splitStakePubkey,
lamports: 0,
space: this.space,
programId: this.programId,
}),
);
const type = STAKE_INSTRUCTION_LAYOUTS.Split;
const data = encodeData(type, {lamports});
return transaction.add({
return new TransactionInstruction({
keys: [
{pubkey: stakePubkey, isSigner: false, isWritable: true},
{pubkey: splitStakePubkey, isSigner: false, isWritable: true},
@ -735,6 +735,56 @@ export class StakeProgram {
});
}
/**
* Generate a Transaction that splits Stake tokens into another stake account
*/
static split(params: SplitStakeParams): Transaction {
const transaction = new Transaction();
transaction.add(
SystemProgram.createAccount({
fromPubkey: params.authorizedPubkey,
newAccountPubkey: params.splitStakePubkey,
lamports: 0,
space: this.space,
programId: this.programId,
}),
);
return transaction.add(this.splitInstruction(params));
}
/**
* Generate a Transaction that splits Stake tokens into another account
* derived from a base public key and seed
*/
static splitWithSeed(params: SplitStakeWithSeedParams): Transaction {
const {
stakePubkey,
authorizedPubkey,
splitStakePubkey,
basePubkey,
seed,
lamports,
} = params;
const transaction = new Transaction();
transaction.add(
SystemProgram.allocate({
accountPubkey: splitStakePubkey,
basePubkey,
seed,
space: this.space,
programId: this.programId,
}),
);
return transaction.add(
this.splitInstruction({
stakePubkey,
authorizedPubkey,
splitStakePubkey,
lamports,
}),
);
}
/**
* Generate a Transaction that merges Stake accounts.
*/

View File

@ -220,6 +220,46 @@ describe('StakeProgram', () => {
expect(params).to.eql(StakeInstruction.decodeSplit(stakeInstruction));
});
it('splitWithSeed', async () => {
const stakePubkey = Keypair.generate().publicKey;
const authorizedPubkey = Keypair.generate().publicKey;
const lamports = 123;
const seed = 'test string';
const basePubkey = Keypair.generate().publicKey;
const splitStakePubkey = await PublicKey.createWithSeed(
basePubkey,
seed,
StakeProgram.programId,
);
const transaction = StakeProgram.splitWithSeed({
stakePubkey,
authorizedPubkey,
lamports,
splitStakePubkey,
basePubkey,
seed,
});
expect(transaction.instructions).to.have.length(2);
const [systemInstruction, stakeInstruction] = transaction.instructions;
const systemParams = {
accountPubkey: splitStakePubkey,
basePubkey,
seed,
space: StakeProgram.space,
programId: StakeProgram.programId,
};
expect(systemParams).to.eql(
SystemInstruction.decodeAllocateWithSeed(systemInstruction),
);
const splitParams = {
stakePubkey,
authorizedPubkey,
splitStakePubkey,
lamports,
};
expect(splitParams).to.eql(StakeInstruction.decodeSplit(stakeInstruction));
});
it('merge', () => {
const stakePubkey = Keypair.generate().publicKey;
const sourceStakePubKey = Keypair.generate().publicKey;
@ -420,7 +460,7 @@ describe('StakeProgram', () => {
seed,
authorized: new Authorized(authorized.publicKey, authorized.publicKey),
lockup: new Lockup(0, 0, new PublicKey(0)),
lamports: 3 * minimumAmount + 42,
lamports: 4 * minimumAmount + 62,
});
await sendAndConfirmTransaction(
@ -430,7 +470,7 @@ describe('StakeProgram', () => {
{preflightCommitment: 'confirmed'},
);
let originalStakeBalance = await connection.getBalance(newAccountPubkey);
expect(originalStakeBalance).to.eq(3 * minimumAmount + 42);
expect(originalStakeBalance).to.eq(4 * minimumAmount + 62);
let delegation = StakeProgram.delegate({
stakePubkey: newAccountPubkey,
@ -502,7 +542,34 @@ describe('StakeProgram', () => {
},
);
const balance = await connection.getBalance(newAccountPubkey);
expect(balance).to.eq(minimumAmount + 2);
expect(balance).to.eq(2 * minimumAmount + 22);
// Split stake with seed
const seed2 = 'test string 2';
const newStake2 = await PublicKey.createWithSeed(
payer.publicKey,
seed2,
StakeProgram.programId,
);
let splitWithSeed = StakeProgram.splitWithSeed({
stakePubkey: newAccountPubkey,
authorizedPubkey: authorized.publicKey,
lamports: minimumAmount + 20,
splitStakePubkey: newStake2,
basePubkey: payer.publicKey,
seed: seed2,
});
await sendAndConfirmTransaction(
connection,
splitWithSeed,
[payer, authorized],
{
preflightCommitment: 'confirmed',
},
);
expect(await connection.getBalance(newAccountPubkey)).to.eq(
minimumAmount + 2,
);
// Merge stake
let merge = StakeProgram.merge({