621 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			621 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import {expect, use} from 'chai';
 | 
						|
import chaiAsPromised from 'chai-as-promised';
 | 
						|
 | 
						|
import {
 | 
						|
  Keypair,
 | 
						|
  Authorized,
 | 
						|
  Connection,
 | 
						|
  Lockup,
 | 
						|
  PublicKey,
 | 
						|
  sendAndConfirmTransaction,
 | 
						|
  LAMPORTS_PER_SOL,
 | 
						|
  StakeAuthorizationLayout,
 | 
						|
  StakeInstruction,
 | 
						|
  StakeProgram,
 | 
						|
  SystemInstruction,
 | 
						|
  Transaction,
 | 
						|
} from '../src';
 | 
						|
import {helpers} from './mocks/rpc-http';
 | 
						|
import {url} from './url';
 | 
						|
 | 
						|
use(chaiAsPromised);
 | 
						|
 | 
						|
describe('StakeProgram', () => {
 | 
						|
  it('createAccountWithSeed', async () => {
 | 
						|
    const fromPubkey = Keypair.generate().publicKey;
 | 
						|
    const seed = 'test string';
 | 
						|
    const newAccountPubkey = await PublicKey.createWithSeed(
 | 
						|
      fromPubkey,
 | 
						|
      seed,
 | 
						|
      StakeProgram.programId,
 | 
						|
    );
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const authorized = new Authorized(authorizedPubkey, authorizedPubkey);
 | 
						|
    const lockup = new Lockup(0, 0, fromPubkey);
 | 
						|
    const lamports = 123;
 | 
						|
    const transaction = StakeProgram.createAccountWithSeed({
 | 
						|
      fromPubkey,
 | 
						|
      stakePubkey: newAccountPubkey,
 | 
						|
      basePubkey: fromPubkey,
 | 
						|
      seed,
 | 
						|
      authorized,
 | 
						|
      lockup,
 | 
						|
      lamports,
 | 
						|
    });
 | 
						|
    expect(transaction.instructions).to.have.length(2);
 | 
						|
    const [systemInstruction, stakeInstruction] = transaction.instructions;
 | 
						|
    const systemParams = {
 | 
						|
      fromPubkey,
 | 
						|
      newAccountPubkey,
 | 
						|
      basePubkey: fromPubkey,
 | 
						|
      seed,
 | 
						|
      lamports,
 | 
						|
      space: StakeProgram.space,
 | 
						|
      programId: StakeProgram.programId,
 | 
						|
    };
 | 
						|
    expect(systemParams).to.eql(
 | 
						|
      SystemInstruction.decodeCreateWithSeed(systemInstruction),
 | 
						|
    );
 | 
						|
    const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
 | 
						|
    expect(initParams).to.eql(
 | 
						|
      StakeInstruction.decodeInitialize(stakeInstruction),
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('createAccount', () => {
 | 
						|
    const fromPubkey = Keypair.generate().publicKey;
 | 
						|
    const newAccountPubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const authorized = new Authorized(authorizedPubkey, authorizedPubkey);
 | 
						|
    const lockup = new Lockup(0, 0, fromPubkey);
 | 
						|
    const lamports = 123;
 | 
						|
    const transaction = StakeProgram.createAccount({
 | 
						|
      fromPubkey,
 | 
						|
      stakePubkey: newAccountPubkey,
 | 
						|
      authorized,
 | 
						|
      lockup,
 | 
						|
      lamports,
 | 
						|
    });
 | 
						|
    expect(transaction.instructions).to.have.length(2);
 | 
						|
    const [systemInstruction, stakeInstruction] = transaction.instructions;
 | 
						|
    const systemParams = {
 | 
						|
      fromPubkey,
 | 
						|
      newAccountPubkey,
 | 
						|
      lamports,
 | 
						|
      space: StakeProgram.space,
 | 
						|
      programId: StakeProgram.programId,
 | 
						|
    };
 | 
						|
    expect(systemParams).to.eql(
 | 
						|
      SystemInstruction.decodeCreateAccount(systemInstruction),
 | 
						|
    );
 | 
						|
 | 
						|
    const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
 | 
						|
    expect(initParams).to.eql(
 | 
						|
      StakeInstruction.decodeInitialize(stakeInstruction),
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('delegate', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const votePubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorizedPubkey,
 | 
						|
      votePubkey,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.delegate(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeDelegate(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('authorize', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const newAuthorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const stakeAuthorizationType = StakeAuthorizationLayout.Staker;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorizedPubkey,
 | 
						|
      newAuthorizedPubkey,
 | 
						|
      stakeAuthorizationType,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.authorize(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeAuthorize(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('authorize with custodian', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const newAuthorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const stakeAuthorizationType = StakeAuthorizationLayout.Withdrawer;
 | 
						|
    const custodianPubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorizedPubkey,
 | 
						|
      newAuthorizedPubkey,
 | 
						|
      stakeAuthorizationType,
 | 
						|
      custodianPubkey,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.authorize(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeAuthorize(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('authorizeWithSeed', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorityBase = Keypair.generate().publicKey;
 | 
						|
    const authoritySeed = 'test string';
 | 
						|
    const authorityOwner = Keypair.generate().publicKey;
 | 
						|
    const newAuthorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const stakeAuthorizationType = StakeAuthorizationLayout.Staker;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorityBase,
 | 
						|
      authoritySeed,
 | 
						|
      authorityOwner,
 | 
						|
      newAuthorizedPubkey,
 | 
						|
      stakeAuthorizationType,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.authorizeWithSeed(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(
 | 
						|
      StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction),
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('authorizeWithSeed with custodian', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorityBase = Keypair.generate().publicKey;
 | 
						|
    const authoritySeed = 'test string';
 | 
						|
    const authorityOwner = Keypair.generate().publicKey;
 | 
						|
    const newAuthorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const stakeAuthorizationType = StakeAuthorizationLayout.Staker;
 | 
						|
    const custodianPubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorityBase,
 | 
						|
      authoritySeed,
 | 
						|
      authorityOwner,
 | 
						|
      newAuthorizedPubkey,
 | 
						|
      stakeAuthorizationType,
 | 
						|
      custodianPubkey,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.authorizeWithSeed(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(
 | 
						|
      StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction),
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('split', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const splitStakePubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorizedPubkey,
 | 
						|
      splitStakePubkey,
 | 
						|
      lamports: 123,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.split(params);
 | 
						|
    expect(transaction.instructions).to.have.length(2);
 | 
						|
    const [systemInstruction, stakeInstruction] = transaction.instructions;
 | 
						|
    const systemParams = {
 | 
						|
      fromPubkey: authorizedPubkey,
 | 
						|
      newAccountPubkey: splitStakePubkey,
 | 
						|
      lamports: 0,
 | 
						|
      space: StakeProgram.space,
 | 
						|
      programId: StakeProgram.programId,
 | 
						|
    };
 | 
						|
    expect(systemParams).to.eql(
 | 
						|
      SystemInstruction.decodeCreateAccount(systemInstruction),
 | 
						|
    );
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeSplit(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('merge', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const sourceStakePubKey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      sourceStakePubKey,
 | 
						|
      authorizedPubkey,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.merge(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeMerge(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('withdraw', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const toPubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorizedPubkey,
 | 
						|
      toPubkey,
 | 
						|
      lamports: 123,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.withdraw(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeWithdraw(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('withdraw with custodian', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const toPubkey = Keypair.generate().publicKey;
 | 
						|
    const custodianPubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {
 | 
						|
      stakePubkey,
 | 
						|
      authorizedPubkey,
 | 
						|
      toPubkey,
 | 
						|
      lamports: 123,
 | 
						|
      custodianPubkey,
 | 
						|
    };
 | 
						|
    const transaction = StakeProgram.withdraw(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeWithdraw(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('deactivate', () => {
 | 
						|
    const stakePubkey = Keypair.generate().publicKey;
 | 
						|
    const authorizedPubkey = Keypair.generate().publicKey;
 | 
						|
    const params = {stakePubkey, authorizedPubkey};
 | 
						|
    const transaction = StakeProgram.deactivate(params);
 | 
						|
    expect(transaction.instructions).to.have.length(1);
 | 
						|
    const [stakeInstruction] = transaction.instructions;
 | 
						|
    expect(params).to.eql(StakeInstruction.decodeDeactivate(stakeInstruction));
 | 
						|
  });
 | 
						|
 | 
						|
  it('StakeInstructions', async () => {
 | 
						|
    const from = Keypair.generate();
 | 
						|
    const seed = 'test string';
 | 
						|
    const newAccountPubkey = await PublicKey.createWithSeed(
 | 
						|
      from.publicKey,
 | 
						|
      seed,
 | 
						|
      StakeProgram.programId,
 | 
						|
    );
 | 
						|
    const authorized = Keypair.generate();
 | 
						|
    const amount = 123;
 | 
						|
    const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
 | 
						|
    const createWithSeed = StakeProgram.createAccountWithSeed({
 | 
						|
      fromPubkey: from.publicKey,
 | 
						|
      stakePubkey: newAccountPubkey,
 | 
						|
      basePubkey: from.publicKey,
 | 
						|
      seed,
 | 
						|
      authorized: new Authorized(authorized.publicKey, authorized.publicKey),
 | 
						|
      lockup: new Lockup(0, 0, from.publicKey),
 | 
						|
      lamports: amount,
 | 
						|
    });
 | 
						|
    const createWithSeedTransaction = new Transaction({recentBlockhash}).add(
 | 
						|
      createWithSeed,
 | 
						|
    );
 | 
						|
 | 
						|
    expect(createWithSeedTransaction.instructions).to.have.length(2);
 | 
						|
    const systemInstructionType = SystemInstruction.decodeInstructionType(
 | 
						|
      createWithSeedTransaction.instructions[0],
 | 
						|
    );
 | 
						|
    expect(systemInstructionType).to.eq('CreateWithSeed');
 | 
						|
 | 
						|
    const stakeInstructionType = StakeInstruction.decodeInstructionType(
 | 
						|
      createWithSeedTransaction.instructions[1],
 | 
						|
    );
 | 
						|
    expect(stakeInstructionType).to.eq('Initialize');
 | 
						|
 | 
						|
    expect(() => {
 | 
						|
      StakeInstruction.decodeInstructionType(
 | 
						|
        createWithSeedTransaction.instructions[0],
 | 
						|
      );
 | 
						|
    }).to.throw();
 | 
						|
 | 
						|
    const stake = Keypair.generate();
 | 
						|
    const vote = Keypair.generate();
 | 
						|
    const delegate = StakeProgram.delegate({
 | 
						|
      stakePubkey: stake.publicKey,
 | 
						|
      authorizedPubkey: authorized.publicKey,
 | 
						|
      votePubkey: vote.publicKey,
 | 
						|
    });
 | 
						|
 | 
						|
    const delegateTransaction = new Transaction({recentBlockhash}).add(
 | 
						|
      delegate,
 | 
						|
    );
 | 
						|
    const anotherStakeInstructionType = StakeInstruction.decodeInstructionType(
 | 
						|
      delegateTransaction.instructions[0],
 | 
						|
    );
 | 
						|
    expect(anotherStakeInstructionType).to.eq('Delegate');
 | 
						|
  });
 | 
						|
 | 
						|
  if (process.env.TEST_LIVE) {
 | 
						|
    it('live staking actions', async () => {
 | 
						|
      const connection = new Connection(url, 'confirmed');
 | 
						|
 | 
						|
      const voteAccounts = await connection.getVoteAccounts();
 | 
						|
      const voteAccount = voteAccounts.current.concat(
 | 
						|
        voteAccounts.delinquent,
 | 
						|
      )[0];
 | 
						|
      const votePubkey = new PublicKey(voteAccount.votePubkey);
 | 
						|
 | 
						|
      const payer = Keypair.generate();
 | 
						|
      await helpers.airdrop({
 | 
						|
        connection,
 | 
						|
        address: payer.publicKey,
 | 
						|
        amount: 2 * LAMPORTS_PER_SOL,
 | 
						|
      });
 | 
						|
 | 
						|
      const authorized = Keypair.generate();
 | 
						|
      await helpers.airdrop({
 | 
						|
        connection,
 | 
						|
        address: authorized.publicKey,
 | 
						|
        amount: 2 * LAMPORTS_PER_SOL,
 | 
						|
      });
 | 
						|
 | 
						|
      const minimumAmount = await connection.getMinimumBalanceForRentExemption(
 | 
						|
        StakeProgram.space,
 | 
						|
      );
 | 
						|
 | 
						|
      expect(await connection.getBalance(payer.publicKey)).to.eq(
 | 
						|
        2 * LAMPORTS_PER_SOL,
 | 
						|
      );
 | 
						|
      expect(await connection.getBalance(authorized.publicKey)).to.eq(
 | 
						|
        2 * LAMPORTS_PER_SOL,
 | 
						|
      );
 | 
						|
 | 
						|
      {
 | 
						|
        // Create Stake account without seed
 | 
						|
        const newStakeAccount = Keypair.generate();
 | 
						|
        let createAndInitialize = StakeProgram.createAccount({
 | 
						|
          fromPubkey: payer.publicKey,
 | 
						|
          stakePubkey: newStakeAccount.publicKey,
 | 
						|
          authorized: new Authorized(
 | 
						|
            authorized.publicKey,
 | 
						|
            authorized.publicKey,
 | 
						|
          ),
 | 
						|
          lamports: minimumAmount + 42,
 | 
						|
        });
 | 
						|
 | 
						|
        await sendAndConfirmTransaction(
 | 
						|
          connection,
 | 
						|
          createAndInitialize,
 | 
						|
          [payer, newStakeAccount],
 | 
						|
          {preflightCommitment: 'confirmed'},
 | 
						|
        );
 | 
						|
        expect(await connection.getBalance(newStakeAccount.publicKey)).to.eq(
 | 
						|
          minimumAmount + 42,
 | 
						|
        );
 | 
						|
 | 
						|
        const delegation = StakeProgram.delegate({
 | 
						|
          stakePubkey: newStakeAccount.publicKey,
 | 
						|
          authorizedPubkey: authorized.publicKey,
 | 
						|
          votePubkey,
 | 
						|
        });
 | 
						|
        await sendAndConfirmTransaction(connection, delegation, [authorized], {
 | 
						|
          commitment: 'confirmed',
 | 
						|
        });
 | 
						|
      }
 | 
						|
 | 
						|
      // Create Stake account with seed
 | 
						|
      const seed = 'test string';
 | 
						|
      const newAccountPubkey = await PublicKey.createWithSeed(
 | 
						|
        payer.publicKey,
 | 
						|
        seed,
 | 
						|
        StakeProgram.programId,
 | 
						|
      );
 | 
						|
 | 
						|
      let createAndInitializeWithSeed = StakeProgram.createAccountWithSeed({
 | 
						|
        fromPubkey: payer.publicKey,
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        basePubkey: payer.publicKey,
 | 
						|
        seed,
 | 
						|
        authorized: new Authorized(authorized.publicKey, authorized.publicKey),
 | 
						|
        lockup: new Lockup(0, 0, new PublicKey(0)),
 | 
						|
        lamports: 3 * minimumAmount + 42,
 | 
						|
      });
 | 
						|
 | 
						|
      await sendAndConfirmTransaction(
 | 
						|
        connection,
 | 
						|
        createAndInitializeWithSeed,
 | 
						|
        [payer],
 | 
						|
        {preflightCommitment: 'confirmed'},
 | 
						|
      );
 | 
						|
      let originalStakeBalance = await connection.getBalance(newAccountPubkey);
 | 
						|
      expect(originalStakeBalance).to.eq(3 * minimumAmount + 42);
 | 
						|
 | 
						|
      let delegation = StakeProgram.delegate({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        votePubkey,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, delegation, [authorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
 | 
						|
      // Test that withdraw fails before deactivation
 | 
						|
      const recipient = Keypair.generate();
 | 
						|
      let withdraw = StakeProgram.withdraw({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        toPubkey: recipient.publicKey,
 | 
						|
        lamports: 1000,
 | 
						|
      });
 | 
						|
      await expect(
 | 
						|
        sendAndConfirmTransaction(connection, withdraw, [authorized], {
 | 
						|
          preflightCommitment: 'confirmed',
 | 
						|
        }),
 | 
						|
      ).to.be.rejected;
 | 
						|
 | 
						|
      // Deactivate stake
 | 
						|
      let deactivate = StakeProgram.deactivate({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, deactivate, [authorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
 | 
						|
      let stakeActivationState;
 | 
						|
      do {
 | 
						|
        stakeActivationState = await connection.getStakeActivation(
 | 
						|
          newAccountPubkey,
 | 
						|
        );
 | 
						|
      } while (stakeActivationState.state != 'inactive');
 | 
						|
 | 
						|
      // Test that withdraw succeeds after deactivation
 | 
						|
      withdraw = StakeProgram.withdraw({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        toPubkey: recipient.publicKey,
 | 
						|
        lamports: minimumAmount + 20,
 | 
						|
      });
 | 
						|
 | 
						|
      await sendAndConfirmTransaction(connection, withdraw, [authorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
      const recipientBalance = await connection.getBalance(recipient.publicKey);
 | 
						|
      expect(recipientBalance).to.eq(minimumAmount + 20);
 | 
						|
 | 
						|
      // Split stake
 | 
						|
      const newStake = Keypair.generate();
 | 
						|
      let split = StakeProgram.split({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        splitStakePubkey: newStake.publicKey,
 | 
						|
        lamports: minimumAmount + 20,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(
 | 
						|
        connection,
 | 
						|
        split,
 | 
						|
        [authorized, newStake],
 | 
						|
        {
 | 
						|
          preflightCommitment: 'confirmed',
 | 
						|
        },
 | 
						|
      );
 | 
						|
      const balance = await connection.getBalance(newAccountPubkey);
 | 
						|
      expect(balance).to.eq(minimumAmount + 2);
 | 
						|
 | 
						|
      // Merge stake
 | 
						|
      let merge = StakeProgram.merge({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        sourceStakePubKey: newStake.publicKey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, merge, [authorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
      const mergedBalance = await connection.getBalance(newAccountPubkey);
 | 
						|
      expect(mergedBalance).to.eq(2 * minimumAmount + 22);
 | 
						|
 | 
						|
      // Resplit
 | 
						|
      split = StakeProgram.split({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        splitStakePubkey: newStake.publicKey,
 | 
						|
        lamports: minimumAmount + 20,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(
 | 
						|
        connection,
 | 
						|
        split,
 | 
						|
        [authorized, newStake],
 | 
						|
        {
 | 
						|
          preflightCommitment: 'confirmed',
 | 
						|
        },
 | 
						|
      );
 | 
						|
 | 
						|
      // Authorize to new account
 | 
						|
      const newAuthorized = Keypair.generate();
 | 
						|
      await connection.requestAirdrop(
 | 
						|
        newAuthorized.publicKey,
 | 
						|
        LAMPORTS_PER_SOL,
 | 
						|
      );
 | 
						|
 | 
						|
      let authorize = StakeProgram.authorize({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        newAuthorizedPubkey: newAuthorized.publicKey,
 | 
						|
        stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, authorize, [authorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
      authorize = StakeProgram.authorize({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        newAuthorizedPubkey: newAuthorized.publicKey,
 | 
						|
        stakeAuthorizationType: StakeAuthorizationLayout.Staker,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, authorize, [authorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
 | 
						|
      // Test old authorized can't delegate
 | 
						|
      let delegateNotAuthorized = StakeProgram.delegate({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
        votePubkey,
 | 
						|
      });
 | 
						|
      await expect(
 | 
						|
        sendAndConfirmTransaction(
 | 
						|
          connection,
 | 
						|
          delegateNotAuthorized,
 | 
						|
          [authorized],
 | 
						|
          {
 | 
						|
            preflightCommitment: 'confirmed',
 | 
						|
          },
 | 
						|
        ),
 | 
						|
      ).to.be.rejected;
 | 
						|
 | 
						|
      // Test accounts with different authorities can't be merged
 | 
						|
      let mergeNotAuthorized = StakeProgram.merge({
 | 
						|
        stakePubkey: newStake.publicKey,
 | 
						|
        sourceStakePubKey: newAccountPubkey,
 | 
						|
        authorizedPubkey: authorized.publicKey,
 | 
						|
      });
 | 
						|
      await expect(
 | 
						|
        sendAndConfirmTransaction(
 | 
						|
          connection,
 | 
						|
          mergeNotAuthorized,
 | 
						|
          [authorized],
 | 
						|
          {
 | 
						|
            preflightCommitment: 'confirmed',
 | 
						|
          },
 | 
						|
        ),
 | 
						|
      ).to.be.rejected;
 | 
						|
 | 
						|
      // Authorize a derived address
 | 
						|
      authorize = StakeProgram.authorize({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorizedPubkey: newAuthorized.publicKey,
 | 
						|
        newAuthorizedPubkey: newAccountPubkey,
 | 
						|
        stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, authorize, [newAuthorized], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
 | 
						|
      // Restore the previous authority using a derived address
 | 
						|
      authorize = StakeProgram.authorizeWithSeed({
 | 
						|
        stakePubkey: newAccountPubkey,
 | 
						|
        authorityBase: payer.publicKey,
 | 
						|
        authoritySeed: seed,
 | 
						|
        authorityOwner: StakeProgram.programId,
 | 
						|
        newAuthorizedPubkey: newAuthorized.publicKey,
 | 
						|
        stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
 | 
						|
      });
 | 
						|
      await sendAndConfirmTransaction(connection, authorize, [payer], {
 | 
						|
        preflightCommitment: 'confirmed',
 | 
						|
      });
 | 
						|
    }).timeout(10 * 1000);
 | 
						|
  }
 | 
						|
});
 |