fix: add integration test and fix various exposed bugs
This commit is contained in:
parent
07c0670f65
commit
3595892fab
|
@ -203,9 +203,6 @@ declare module '@solana/web3.js' {
|
|||
validatorExit(): Promise<boolean>;
|
||||
}
|
||||
|
||||
// === src/config-program.js ===
|
||||
declare export var CONFIG_PROGRAM_ID;
|
||||
|
||||
// === src/stake-program.js ===
|
||||
declare export class StakeProgram {
|
||||
static programId: PublicKey;
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// @flow
|
||||
import {PublicKey} from './publickey';
|
||||
|
||||
export const CONFIG_PROGRAM_ID = new PublicKey(
|
||||
'Config1111111111111111111111111111111111111',
|
||||
);
|
|
@ -2,11 +2,11 @@
|
|||
export {Account} from './account';
|
||||
export {BpfLoader} from './bpf-loader';
|
||||
export {BudgetProgram} from './budget-program';
|
||||
export {CONFIG_PROGRAM_ID} from './config-program';
|
||||
export {Connection} from './connection';
|
||||
export {Loader} from './loader';
|
||||
export {PublicKey} from './publickey';
|
||||
export {
|
||||
STAKE_CONFIG_ID,
|
||||
Authorized,
|
||||
Lockup,
|
||||
StakeAuthorizationLayout,
|
||||
|
|
|
@ -69,7 +69,11 @@ export const authorized = (property: string = 'authorized') => {
|
|||
*/
|
||||
export const lockup = (property: string = 'lockup') => {
|
||||
return BufferLayout.struct(
|
||||
[BufferLayout.ns64('epoch'), publicKey('custodian')],
|
||||
[
|
||||
BufferLayout.ns64('unixTimestamp'),
|
||||
BufferLayout.ns64('epoch'),
|
||||
publicKey('custodian'),
|
||||
],
|
||||
property,
|
||||
);
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import * as BufferLayout from 'buffer-layout';
|
||||
import hasha from 'hasha';
|
||||
|
||||
import {CONFIG_PROGRAM_ID} from './config-program';
|
||||
import {encodeData} from './instruction';
|
||||
import type {InstructionType} from './instruction';
|
||||
import * as Layout from './layout';
|
||||
|
@ -18,6 +17,10 @@ import {
|
|||
import {Transaction, TransactionInstruction} from './transaction';
|
||||
import type {TransactionInstructionCtorFields} from './transaction';
|
||||
|
||||
export const STAKE_CONFIG_ID = new PublicKey(
|
||||
'StakeConfig11111111111111111111111111111111',
|
||||
);
|
||||
|
||||
export class Authorized {
|
||||
staker: PublicKey;
|
||||
withdrawer: PublicKey;
|
||||
|
@ -32,13 +35,15 @@ export class Authorized {
|
|||
}
|
||||
|
||||
export class Lockup {
|
||||
unixTimestamp: number;
|
||||
epoch: number;
|
||||
custodian: PublicKey;
|
||||
|
||||
/**
|
||||
* Create a new Authorized object
|
||||
* Create a new Lockup object
|
||||
*/
|
||||
constructor(epoch: number, custodian: PublicKey) {
|
||||
constructor(unixTimestamp: number, epoch: number, custodian: PublicKey) {
|
||||
this.unixTimestamp = unixTimestamp;
|
||||
this.epoch = epoch;
|
||||
this.custodian = custodian;
|
||||
}
|
||||
|
@ -126,14 +131,14 @@ export const StakeInstructionLayout = Object.freeze({
|
|||
index: 4,
|
||||
layout: BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
BufferLayout.ns64('amount'),
|
||||
BufferLayout.ns64('lamports'),
|
||||
]),
|
||||
},
|
||||
Withdraw: {
|
||||
index: 5,
|
||||
layout: BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
BufferLayout.ns64('amount'),
|
||||
BufferLayout.ns64('lamports'),
|
||||
]),
|
||||
},
|
||||
Deactivate: {
|
||||
|
@ -197,7 +202,7 @@ export class StakeProgram {
|
|||
* Max space of a Stake account
|
||||
*/
|
||||
static get space(): number {
|
||||
return 2000;
|
||||
return 2008;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,6 +220,7 @@ export class StakeProgram {
|
|||
withdrawer: authorized.withdrawer.toBuffer(),
|
||||
},
|
||||
lockup: {
|
||||
unixTimestamp: lockup.unixTimestamp,
|
||||
epoch: lockup.epoch,
|
||||
custodian: lockup.custodian.toBuffer(),
|
||||
},
|
||||
|
@ -293,7 +299,7 @@ export class StakeProgram {
|
|||
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||
{pubkey: votePubkey, isSigner: false, isWritable: false},
|
||||
{pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false},
|
||||
{pubkey: CONFIG_PROGRAM_ID, isSigner: false, isWritable: false},
|
||||
{pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false},
|
||||
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
|
||||
],
|
||||
programId: this.programId,
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
import {
|
||||
Account,
|
||||
Authorized,
|
||||
Connection,
|
||||
Lockup,
|
||||
PublicKey,
|
||||
sendAndConfirmRecentTransaction,
|
||||
LAMPORTS_PER_SOL,
|
||||
StakeAuthorizationLayout,
|
||||
StakeInstruction,
|
||||
StakeInstructionLayout,
|
||||
|
@ -13,6 +16,13 @@ import {
|
|||
SystemProgram,
|
||||
Transaction,
|
||||
} from '../src';
|
||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
||||
import {url} from './url';
|
||||
|
||||
if (!mockRpcEnabled) {
|
||||
// Testing max commitment level takes around 20s to complete
|
||||
jest.setTimeout(30000);
|
||||
}
|
||||
|
||||
test('createAccountWithSeed', () => {
|
||||
const from = new Account();
|
||||
|
@ -30,7 +40,7 @@ test('createAccountWithSeed', () => {
|
|||
newAccountPubkey,
|
||||
seed,
|
||||
new Authorized(authorized.publicKey, authorized.publicKey),
|
||||
new Lockup(0, from.publicKey),
|
||||
new Lockup(0, 0, from.publicKey),
|
||||
123,
|
||||
);
|
||||
|
||||
|
@ -52,7 +62,7 @@ test('createAccount', () => {
|
|||
from.publicKey,
|
||||
newAccount.publicKey,
|
||||
new Authorized(authorized.publicKey, authorized.publicKey),
|
||||
new Lockup(0, from.publicKey),
|
||||
new Lockup(0, 0, from.publicKey),
|
||||
123,
|
||||
);
|
||||
|
||||
|
@ -179,7 +189,7 @@ test('StakeInstructions', () => {
|
|||
newAccountPubkey,
|
||||
seed,
|
||||
new Authorized(authorized.publicKey, authorized.publicKey),
|
||||
new Lockup(0, from.publicKey),
|
||||
new Lockup(0, 0, from.publicKey),
|
||||
amount,
|
||||
);
|
||||
const createWithSeedTransaction = new Transaction({recentBlockhash}).add(
|
||||
|
@ -220,3 +230,121 @@ test('StakeInstructions', () => {
|
|||
StakeInstructionLayout.DelegateStake,
|
||||
);
|
||||
});
|
||||
|
||||
test('live staking actions', async () => {
|
||||
if (mockRpcEnabled) {
|
||||
console.log('non-live test skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
const connection = new Connection(url, 'recent');
|
||||
const voteAccounts = await connection.getVoteAccounts();
|
||||
const voteAccount = voteAccounts.current.concat(voteAccounts.delinquent)[0];
|
||||
const votePubkey = new PublicKey(voteAccount.votePubkey);
|
||||
|
||||
const from = new Account();
|
||||
const authorized = new Account();
|
||||
await connection.requestAirdrop(from.publicKey, LAMPORTS_PER_SOL);
|
||||
await connection.requestAirdrop(authorized.publicKey, LAMPORTS_PER_SOL);
|
||||
|
||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
||||
StakeProgram.space,
|
||||
'recent',
|
||||
);
|
||||
|
||||
// Create Stake account with seed
|
||||
const seed = 'test string';
|
||||
const newAccountPubkey = PublicKey.createWithSeed(
|
||||
from.publicKey,
|
||||
seed,
|
||||
StakeProgram.programId,
|
||||
);
|
||||
|
||||
let createAndInitializeWithSeed = StakeProgram.createAccountWithSeed(
|
||||
from.publicKey,
|
||||
newAccountPubkey,
|
||||
seed,
|
||||
new Authorized(authorized.publicKey, authorized.publicKey),
|
||||
new Lockup(0, 0, new PublicKey('0x00')),
|
||||
2 * minimumAmount + 42,
|
||||
);
|
||||
|
||||
await sendAndConfirmRecentTransaction(
|
||||
connection,
|
||||
createAndInitializeWithSeed,
|
||||
from,
|
||||
);
|
||||
let originalStakeBalance = await connection.getBalance(newAccountPubkey);
|
||||
expect(originalStakeBalance).toEqual(2 * minimumAmount + 42);
|
||||
|
||||
let delegation = StakeProgram.delegate(
|
||||
newAccountPubkey,
|
||||
authorized.publicKey,
|
||||
votePubkey,
|
||||
);
|
||||
await sendAndConfirmRecentTransaction(connection, delegation, authorized);
|
||||
|
||||
// Test that withdraw fails before deactivation
|
||||
const recipient = new Account();
|
||||
let withdraw = StakeProgram.withdraw(
|
||||
newAccountPubkey,
|
||||
authorized.publicKey,
|
||||
recipient.publicKey,
|
||||
1000,
|
||||
);
|
||||
await expect(
|
||||
sendAndConfirmRecentTransaction(connection, withdraw, authorized),
|
||||
).rejects.toThrow();
|
||||
|
||||
// Authorize to new account
|
||||
const newAuthorized = new Account();
|
||||
await connection.requestAirdrop(newAuthorized.publicKey, LAMPORTS_PER_SOL);
|
||||
|
||||
let authorize = StakeProgram.authorize(
|
||||
newAccountPubkey,
|
||||
authorized.publicKey,
|
||||
newAuthorized.publicKey,
|
||||
StakeAuthorizationLayout.Withdrawer,
|
||||
);
|
||||
await sendAndConfirmRecentTransaction(connection, authorize, authorized);
|
||||
authorize = StakeProgram.authorize(
|
||||
newAccountPubkey,
|
||||
authorized.publicKey,
|
||||
newAuthorized.publicKey,
|
||||
StakeAuthorizationLayout.Staker,
|
||||
);
|
||||
await sendAndConfirmRecentTransaction(connection, authorize, authorized);
|
||||
|
||||
// Test old authorized can't deactivate
|
||||
let deactivateNotAuthorized = StakeProgram.deactivate(
|
||||
newAccountPubkey,
|
||||
authorized.publicKey,
|
||||
);
|
||||
await expect(
|
||||
sendAndConfirmRecentTransaction(
|
||||
connection,
|
||||
deactivateNotAuthorized,
|
||||
authorized,
|
||||
),
|
||||
).rejects.toThrow();
|
||||
|
||||
// Deactivate stake
|
||||
let deactivate = StakeProgram.deactivate(
|
||||
newAccountPubkey,
|
||||
newAuthorized.publicKey,
|
||||
);
|
||||
await sendAndConfirmRecentTransaction(connection, deactivate, newAuthorized);
|
||||
|
||||
// Test that withdraw succeeds after deactivation
|
||||
withdraw = StakeProgram.withdraw(
|
||||
newAccountPubkey,
|
||||
newAuthorized.publicKey,
|
||||
recipient.publicKey,
|
||||
minimumAmount + 20,
|
||||
);
|
||||
await sendAndConfirmRecentTransaction(connection, withdraw, newAuthorized);
|
||||
const balance = await connection.getBalance(newAccountPubkey);
|
||||
expect(balance).toEqual(minimumAmount + 22);
|
||||
const recipientBalance = await connection.getBalance(recipient.publicKey);
|
||||
expect(recipientBalance).toEqual(minimumAmount + 20);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue