PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-sol/test/unit
Просмотр файла: instructionParamsFactory.staking.ts
import should from 'should';
import * as testData from '../resources/sol';
import { instructionParamsFactory } from '../../src/lib/instructionParamsFactory';
import { TransactionType } from '@bitgo/sdk-core';
import { InstructionParams, Nonce, StakingActivate, StakingDeactivate, StakingWithdraw } from '../../src/lib/iface';
import { InstructionBuilderTypes, MEMO_PROGRAM_PK, STAKE_ACCOUNT_RENT_EXEMPT_AMOUNT } from '../../src/lib/constants';
import {
Keypair as SolKeypair,
Lockup,
PublicKey,
StakeProgram,
SystemProgram,
TransactionInstruction,
} from '@solana/web3.js';
import BigNumber from 'bignumber.js';
describe('Instruction Parser Staking Tests: ', function () {
describe('Activate staking instructions ', function () {
it('Should parse activate stake tx instructions with memo and durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const stakingActivateParams: StakingActivate = {
type: InstructionBuilderTypes.StakingActivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
validator: validator.toString(),
amount,
isMarinade: false,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [
nonceAdvanceInstruction,
...stakingActivateInstructions,
...stakingDelegateInstructions,
memoInstruction,
];
const instructionsData = [nonceAdvanceParams, memoParams, stakingActivateParams];
const result = instructionParamsFactory(TransactionType.StakingActivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse activate stake tx instructions with memo and durable nonce with instructions in any order', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const stakingActivateParams: StakingActivate = {
type: InstructionBuilderTypes.StakingActivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
validator: validator.toString(),
amount,
isMarinade: false,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [
memoInstruction,
...stakingActivateInstructions,
...stakingDelegateInstructions,
nonceAdvanceInstruction,
];
const instructionsData = [memoParams, nonceAdvanceParams, stakingActivateParams];
const result = instructionParamsFactory(TransactionType.StakingActivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse activate stake tx instructions without memo or durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
// Instructions
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
// Params
const stakingActivateParams: StakingActivate = {
type: InstructionBuilderTypes.StakingActivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
validator: validator.toString(),
amount,
isMarinade: false,
},
};
const instructions = [...stakingActivateInstructions, ...stakingDelegateInstructions];
const instructionsData = [stakingActivateParams];
const result = instructionParamsFactory(TransactionType.StakingActivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse activate stake tx instructions if there are unexpected instructions', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
// Instructions
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
}).instructions;
// Params
const stakingActivateParams: StakingActivate = {
type: InstructionBuilderTypes.StakingActivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
validator: validator.toString(),
amount,
isMarinade: false,
},
};
const instructions = [
...stakingActivateInstructions,
...stakingDelegateInstructions,
...stakingDeactivateInstructions,
];
const instructionsData = [stakingActivateParams];
const result = instructionParamsFactory(TransactionType.StakingActivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should fail to parse activate stake tx instructions if there are missing instructions', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
// Instructions
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
should.throws(() => {
const instructions = [stakingActivateInstructions[1], ...stakingDelegateInstructions];
instructionParamsFactory(TransactionType.StakingActivate, instructions);
}, 'Invalid staking activate transaction, missing create stake account instruction');
should.throws(() => {
const instructions = [stakingActivateInstructions[0]];
instructionParamsFactory(TransactionType.StakingActivate, instructions);
}, 'Invalid staking activate transaction, missing initialize stake account/delegate instruction');
});
});
describe('Deactivate staking instructions ', function () {
it('Should parse deactivate stake tx instructions with memo and durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const stakingDeactivateParams: StakingDeactivate = {
type: InstructionBuilderTypes.StakingDeactivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount: undefined,
unstakingAddress: undefined,
isMarinade: false,
recipients: undefined,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [nonceAdvanceInstruction, ...stakingDeactivateInstructions, memoInstruction];
const instructionsData = [nonceAdvanceParams, memoParams, stakingDeactivateParams];
const result = instructionParamsFactory(TransactionType.StakingDeactivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse deactivate stake tx instructions with memo and durable nonce with instructions in any order', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const stakingDeactivateParams: StakingDeactivate = {
type: InstructionBuilderTypes.StakingDeactivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount: undefined,
unstakingAddress: undefined,
isMarinade: false,
recipients: undefined,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [memoInstruction, ...stakingDeactivateInstructions, nonceAdvanceInstruction];
const instructionsData = [memoParams, nonceAdvanceParams, stakingDeactivateParams];
const result = instructionParamsFactory(TransactionType.StakingDeactivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse deactivate stake tx instructions without memo or durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
// Instructions
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
}).instructions;
// Params
const stakingDeactivateParams: StakingDeactivate = {
type: InstructionBuilderTypes.StakingDeactivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount: undefined,
unstakingAddress: undefined,
isMarinade: false,
recipients: undefined,
},
};
const instructions = [...stakingDeactivateInstructions];
const instructionsData = [stakingDeactivateParams];
const result = instructionParamsFactory(TransactionType.StakingDeactivate, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse deactivate stake tx instructions if there are unexpected instructions', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
// Instructions
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
}).instructions;
// Params
const stakingActivateParams: StakingDeactivate = {
type: InstructionBuilderTypes.StakingDeactivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount: undefined,
unstakingAddress: undefined,
isMarinade: false,
recipients: undefined,
},
};
const instructions = [
...stakingActivateInstructions,
...stakingDelegateInstructions,
...stakingDeactivateInstructions,
];
const instructionsData = [stakingActivateParams];
const result = instructionParamsFactory(TransactionType.StakingDeactivate, instructions);
should.deepEqual(result, instructionsData);
});
describe('Partially deactivate stake instructions', function () {
describe('Input validation', function () {
it('Should throw an error if the Allocate instruction is missing', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: StakeProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, missing allocate unstake account instruction'
);
});
it('Should throw an error if the Assign instruction is missing', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: splitStakeAccount,
space: StakeProgram.space,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, missing assign unstake account instruction'
);
});
it('Should throw an error if the Split instruction is missing', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: splitStakeAccount,
space: StakeProgram.space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: StakeProgram.programId,
});
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, missing split stake account instruction'
);
});
it('Should throw an error if the transfer instruction is missing for partial', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: splitStakeAccount,
space: StakeProgram.space,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: StakeProgram.programId,
});
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, missing funding of unstake address instruction'
);
});
it('Should throw an error if the allocated account does not match the assigned account', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: new SolKeypair().publicKey,
space: StakeProgram.space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: StakeProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, must allocate and assign the same public key'
);
});
[199, 201].forEach((space) => {
it(`Should throw an error if the correct amount of space is not allocated for the split account - ${space}`, () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: splitStakeAccount,
space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: StakeProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
`Invalid partial deactivate stake transaction, unstaking account must allocate ${StakeProgram.space} bytes`
);
});
});
it('Should throw an error if the allocated account is not assigned to the StakeProgram', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: splitStakeAccount,
space: StakeProgram.space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: SystemProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, the unstake account must be assigned to the Stake Program'
);
});
it('Should throw an error if the split account is not allocated', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const key = new SolKeypair().publicKey;
const allocateInstruction = SystemProgram.allocate({
accountPubkey: key,
space: StakeProgram.space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: key,
programId: StakeProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: stakingAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, must allocate the unstaking account'
);
});
it('Should throw an error if the stake account and the split account are the same account', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: stakingAccount,
space: StakeProgram.space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: stakingAccount,
programId: StakeProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: stakingAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
const instructions = [
nonceAdvanceInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
should(() => instructionParamsFactory(TransactionType.StakingDeactivate, instructions)).throw(
'Invalid partial deactivate stake transaction, the unstaking account must be different from the Stake Account'
);
});
});
it('Should parse partial deactivate stake tx instructions with memo and durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const splitStakeAccount = new PublicKey(testData.splitStakeAccount.pub);
const memo = 'test memo';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
// transfer
const transferInstruction = SystemProgram.transfer({
fromPubkey: new PublicKey(fromAccount),
toPubkey: new PublicKey(splitStakeAccount),
lamports: parseInt(STAKE_ACCOUNT_RENT_EXEMPT_AMOUNT.toString(), 10),
});
const allocateInstruction = SystemProgram.allocate({
accountPubkey: splitStakeAccount,
space: StakeProgram.space,
});
const assignInstruction = SystemProgram.assign({
accountPubkey: splitStakeAccount,
programId: StakeProgram.programId,
});
const splitInstructions = StakeProgram.split(
{
stakePubkey: stakingAccount,
authorizedPubkey: fromAccount,
splitStakePubkey: splitStakeAccount,
lamports: 100000,
},
0
).instructions;
const stakingDeactivateInstructions = StakeProgram.deactivate({
authorizedPubkey: fromAccount,
stakePubkey: splitStakeAccount,
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const stakingDeactivateParams: StakingDeactivate = {
type: InstructionBuilderTypes.StakingDeactivate,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount: '100000',
unstakingAddress: splitStakeAccount.toString(),
isMarinade: false,
recipients: undefined,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [
nonceAdvanceInstruction,
transferInstruction,
allocateInstruction,
assignInstruction,
...splitInstructions,
...stakingDeactivateInstructions,
memoInstruction,
];
const instructionsData = [nonceAdvanceParams, memoParams, stakingDeactivateParams];
const result = instructionParamsFactory(TransactionType.StakingDeactivate, instructions);
should.deepEqual(result, instructionsData);
});
});
});
describe('Withdraw stake instructions ', function () {
it('Should parse withdraw stake tx instructions with memo and durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const memo = 'test memo';
const amount = '100000';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const withdrawStakeInstructions = StakeProgram.withdraw({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
toPubkey: fromAccount,
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const withdrawStakeParams: StakingWithdraw = {
type: InstructionBuilderTypes.StakingWithdraw,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [nonceAdvanceInstruction, ...withdrawStakeInstructions, memoInstruction];
const instructionsData = [nonceAdvanceParams, withdrawStakeParams, memoParams];
const result = instructionParamsFactory(TransactionType.StakingWithdraw, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse withdraw stake tx instructions with memo and durable nonce with instructions in any order', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const nonceAccount = testData.nonceAccount.pub;
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const memo = 'test memo';
const amount = '100000';
// Instructions
const nonceAdvanceInstruction = SystemProgram.nonceAdvance({
noncePubkey: new PublicKey(nonceAccount),
authorizedPubkey: fromAccount,
});
const withdrawStakeInstructions = StakeProgram.withdraw({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
toPubkey: fromAccount,
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const memoInstruction = new TransactionInstruction({
keys: [],
programId: new PublicKey(MEMO_PROGRAM_PK),
data: Buffer.from(memo),
});
// Params
const nonceAdvanceParams: Nonce = {
type: InstructionBuilderTypes.NonceAdvance,
params: { walletNonceAddress: nonceAccount, authWalletAddress: fromAccount.toString() },
};
const withdrawStakeParams: StakingWithdraw = {
type: InstructionBuilderTypes.StakingWithdraw,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount,
},
};
const memoParams: InstructionParams = {
type: InstructionBuilderTypes.Memo,
params: { memo },
};
const instructions = [memoInstruction, ...withdrawStakeInstructions, nonceAdvanceInstruction];
const instructionsData = [memoParams, withdrawStakeParams, nonceAdvanceParams];
const result = instructionParamsFactory(TransactionType.StakingWithdraw, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse withdraw stake tx instructions without memo or durable nonce', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const amount = '100000';
// Instructions
const withdrawStakeInstructions = StakeProgram.withdraw({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
toPubkey: fromAccount,
lamports: new BigNumber(amount).toNumber(),
}).instructions;
// Params
const withdrawStakeParams: StakingWithdraw = {
type: InstructionBuilderTypes.StakingWithdraw,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount,
},
};
const instructions = [...withdrawStakeInstructions];
const instructionsData = [withdrawStakeParams];
const result = instructionParamsFactory(TransactionType.StakingWithdraw, instructions);
should.deepEqual(result, instructionsData);
});
it('Should parse withdraw stake tx instructions if there are unexpected instructions', () => {
const fromAccount = new PublicKey(testData.authAccount.pub);
const stakingAccount = new PublicKey(testData.stakeAccount.pub);
const validator = new PublicKey(testData.validator.pub);
const amount = '100000';
// Instructions
const stakingActivateInstructions = StakeProgram.createAccount({
fromPubkey: fromAccount,
stakePubkey: stakingAccount,
authorized: {
staker: fromAccount,
withdrawer: fromAccount,
},
lockup: new Lockup(0, 0, fromAccount),
lamports: new BigNumber(amount).toNumber(),
}).instructions;
const stakingDelegateInstructions = StakeProgram.delegate({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
votePubkey: validator,
}).instructions;
const withdrawStakeInstructions = StakeProgram.withdraw({
authorizedPubkey: fromAccount,
stakePubkey: stakingAccount,
toPubkey: fromAccount,
lamports: new BigNumber(amount).toNumber(),
}).instructions;
// Params
const withdrawStakeParams: StakingWithdraw = {
type: InstructionBuilderTypes.StakingWithdraw,
params: {
fromAddress: fromAccount.toString(),
stakingAddress: stakingAccount.toString(),
amount,
},
};
const instructions = [
...stakingActivateInstructions,
...stakingDelegateInstructions,
...withdrawStakeInstructions,
];
const instructionsData = [withdrawStakeParams];
const result = instructionParamsFactory(TransactionType.StakingWithdraw, instructions);
should.deepEqual(result, instructionsData);
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!