feat: add API for decoding system instructions

This commit is contained in:
Justin Starry 2020-03-03 16:05:50 +08:00 committed by Michael Vines
parent 662ce22cdd
commit 6ed2bad9d0
12 changed files with 932 additions and 580 deletions

94
web3.js/module.d.ts vendored
View File

@ -475,6 +475,65 @@ declare module '@solana/web3.js' {
}
// === src/system-program.js ===
export type CreateAccountParams = {
fromPubkey: PublicKey;
newAccountPubkey: PublicKey;
lamports: number;
space: number;
programId: PublicKey;
};
export type TransferParams = {
fromPubkey: PublicKey;
toPubkey: PublicKey;
lamports: number;
};
export type AssignParams = {
fromPubkey: PublicKey;
programId: PublicKey;
};
export type CreateAccountWithSeedParams = {
fromPubkey: PublicKey;
newAccountPubkey: PublicKey;
basePubkey: PublicKey;
seed: string;
lamports: number;
space: number;
programId: PublicKey;
};
export type CreateNonceAccountParams = {
fromPubkey: PublicKey;
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
lamports: number;
};
export type InitializeNonceParams = {
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
};
export type AdvanceNonceParams = {
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
};
export type WithdrawNonceParams = {
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
toPubkey: PublicKey;
lamports: number;
};
export type AuthorizeNonceParams = {
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
newAuthorizedPubkey: PublicKey;
};
export class SystemProgram {
static programId: PublicKey;
static nonceSpace: number;
@ -538,17 +597,30 @@ declare module '@solana/web3.js' {
[type in SystemInstructionType]: InstructionType;
};
export class SystemInstruction extends TransactionInstruction {
type: SystemInstructionType;
fromPublicKey: PublicKey | null;
toPublicKey: PublicKey | null;
amount: number | null;
constructor(
opts: TransactionInstructionCtorFields,
type: SystemInstructionType,
);
static from(instruction: TransactionInstruction): SystemInstruction;
export class SystemInstruction {
static decodeInstructionType(
instruction: TransactionInstruction,
): SystemInstructionType;
static decodeCreateAccount(
instruction: TransactionInstruction,
): CreateAccountParams;
static decodeTransfer(instruction: TransactionInstruction): TransferParams;
static decodeAssign(instruction: TransactionInstruction): AssignParams;
static decodeCreateWithSeed(
instruction: TransactionInstruction,
): CreateAccountWithSeedParams;
static decodeNonceInitialize(
instruction: TransactionInstruction,
): InitializeNonceParams;
static decodeNonceAdvance(
instruction: TransactionInstruction,
): AdvanceNonceParams;
static decodeNonceWithdraw(
instruction: TransactionInstruction,
): WithdrawNonceParams;
static decodeNonceAuthorize(
instruction: TransactionInstruction,
): AuthorizeNonceParams;
}
// === src/loader.js ===

View File

@ -371,53 +371,79 @@ declare module '@solana/web3.js' {
}
// === src/system-program.js ===
declare export type CreateAccountParams = {|
fromPubkey: PublicKey,
newAccountPubkey: PublicKey,
lamports: number,
space: number,
programId: PublicKey,
|};
declare export type TransferParams = {|
fromPubkey: PublicKey,
toPubkey: PublicKey,
lamports: number,
|};
declare export type AssignParams = {|
fromPubkey: PublicKey,
programId: PublicKey,
|};
declare export type CreateAccountWithSeedParams = {|
fromPubkey: PublicKey,
newAccountPubkey: PublicKey,
basePubkey: PublicKey,
seed: string,
lamports: number,
space: number,
programId: PublicKey,
|};
declare export type CreateNonceAccountParams = {|
fromPubkey: PublicKey,
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
lamports: number,
|};
declare export type InitializeNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
|};
declare export type AdvanceNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
|};
declare export type WithdrawNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
toPubkey: PublicKey,
lamports: number,
|};
declare export type AuthorizeNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
newAuthorizedPubkey: PublicKey,
|};
declare export class SystemProgram {
static programId: PublicKey;
static nonceSpace: number;
static createAccount(
from: PublicKey,
newAccount: PublicKey,
lamports: number,
space: number,
programId: PublicKey,
): Transaction;
static transfer(
from: PublicKey,
to: PublicKey,
amount: number,
): Transaction;
static assign(from: PublicKey, programId: PublicKey): Transaction;
static createAccount(params: CreateAccountParams): Transaction;
static transfer(params: TransferParams): Transaction;
static assign(params: AssignParams): Transaction;
static createAccountWithSeed(
from: PublicKey,
newAccount: PublicKey,
base: PublicKey,
seed: string,
lamports: number,
space: number,
programId: PublicKey,
): Transaction;
static createNonceAccount(
from: PublicKey,
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
lamports: number,
): Transaction;
static nonceAdvance(
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
): TransactionInstruction;
static nonceWithdraw(
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
to: PublicKey,
lamports: number,
): Transaction;
static nonceAuthorize(
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
newAuthorized: PublicKey,
params: CreateAccountWithSeedParams,
): Transaction;
static createNonceAccount(params: CreateNonceAccountParams): Transaction;
static nonceAdvance(params: AdvanceNonceParams): TransactionInstruction;
static nonceWithdraw(params: WithdrawNonceParams): Transaction;
static nonceAuthorize(params: AuthorizeNonceParams): Transaction;
}
declare export type SystemInstructionType =
@ -434,17 +460,27 @@ declare module '@solana/web3.js' {
[SystemInstructionType]: InstructionType,
};
declare export class SystemInstruction extends TransactionInstruction {
type: SystemInstructionType;
fromPublicKey: PublicKey | null;
toPublicKey: PublicKey | null;
amount: number | null;
constructor(
opts?: TransactionInstructionCtorFields,
type: SystemInstructionType,
): SystemInstruction;
static from(instruction: TransactionInstruction): SystemInstruction;
declare export class SystemInstruction {
static decodeCreateAccount(
instruction: TransactionInstruction,
): CreateAccountParams;
static decodeTransfer(instruction: TransactionInstruction): TransferParams;
static decodeAssign(instruction: TransactionInstruction): AssignParams;
static decodeCreateWithSeed(
instruction: TransactionInstruction,
): CreateAccountWithSeedParams;
static decodeNonceInitialize(
instruction: TransactionInstruction,
): InitializeNonceParams;
static decodeNonceAdvance(
instruction: TransactionInstruction,
): AdvanceNonceParams;
static decodeNonceWithdraw(
instruction: TransactionInstruction,
): WithdrawNonceParams;
static decodeNonceAuthorize(
instruction: TransactionInstruction,
): AuthorizeNonceParams;
}
// === src/validator-info.js ===

View File

@ -191,13 +191,13 @@ export class BudgetProgram {
}
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount(
from,
program,
amount,
trimmedData.length,
this.programId,
);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [
@ -227,13 +227,13 @@ export class BudgetProgram {
}
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount(
from,
program,
amount,
trimmedData.length,
this.programId,
);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [{pubkey: program, isSigner: false, isWritable: true}],
@ -260,13 +260,13 @@ export class BudgetProgram {
}
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount(
from,
program,
amount,
trimmedData.length,
this.programId,
);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [{pubkey: program, isSigner: false, isWritable: true}],
@ -316,13 +316,13 @@ export class BudgetProgram {
const trimmedData = data.slice(0, pos);
const transaction = SystemProgram.createAccount(
from,
program,
amount,
trimmedData.length,
this.programId,
);
const transaction = SystemProgram.createAccount({
fromPubkey: from,
newAccountPubkey: program,
lamports: amount,
space: trimmedData.length,
programId: this.programId,
});
return transaction.add({
keys: [{pubkey: program, isSigner: false, isWritable: true}],

View File

@ -58,13 +58,13 @@ export class Loader {
const balanceNeeded = await connection.getMinimumBalanceForRentExemption(
data.length,
);
const transaction = SystemProgram.createAccount(
payer.publicKey,
program.publicKey,
balanceNeeded > 0 ? balanceNeeded : 1,
data.length,
const transaction = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: program.publicKey,
lamports: balanceNeeded > 0 ? balanceNeeded : 1,
space: data.length,
programId,
);
});
await sendAndConfirmTransaction(connection, transaction, payer, program);
}

View File

@ -463,15 +463,15 @@ export class StakeProgram {
static createAccountWithSeed(
params: CreateStakeAccountWithSeedParams,
): Transaction {
let transaction = SystemProgram.createAccountWithSeed(
params.fromPubkey,
params.stakePubkey,
params.basePubkey,
params.seed,
params.lamports,
this.space,
this.programId,
);
let transaction = SystemProgram.createAccountWithSeed({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.stakePubkey,
basePubkey: params.basePubkey,
seed: params.seed,
lamports: params.lamports,
space: this.space,
programId: this.programId,
});
const {stakePubkey, authorized, lockup} = params;
return transaction.add(this.initialize({stakePubkey, authorized, lockup}));
@ -481,13 +481,13 @@ export class StakeProgram {
* Generate a Transaction that creates a new Stake account
*/
static createAccount(params: CreateStakeAccountParams): Transaction {
let transaction = SystemProgram.createAccount(
params.fromPubkey,
params.stakePubkey,
params.lamports,
this.space,
this.programId,
);
let transaction = SystemProgram.createAccount({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.stakePubkey,
lamports: params.lamports,
space: this.space,
programId: this.programId,
});
const {stakePubkey, authorized, lockup} = params;
return transaction.add(this.initialize({stakePubkey, authorized, lockup}));
@ -557,13 +557,13 @@ export class StakeProgram {
static split(params: SplitStakeParams): Transaction {
const {stakePubkey, authorizedPubkey, splitStakePubkey, lamports} = params;
let transaction = SystemProgram.createAccount(
stakePubkey,
splitStakePubkey,
0,
this.space,
this.programId,
);
let transaction = SystemProgram.createAccount({
fromPubkey: stakePubkey,
newAccountPubkey: splitStakePubkey,
lamports: 0,
space: this.space,
programId: this.programId,
});
transaction.instructions[0].keys[0].isSigner = false;
const type = STAKE_INSTRUCTION_LAYOUTS.Split;
const data = encodeData(type, {lamports});

View File

@ -2,116 +2,351 @@
import * as BufferLayout from 'buffer-layout';
import {encodeData} from './instruction';
import {encodeData, decodeData} from './instruction';
import * as Layout from './layout';
import {PublicKey} from './publickey';
import {SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY} from './sysvar';
import {Transaction, TransactionInstruction} from './transaction';
import type {TransactionInstructionCtorFields} from './transaction';
/**
* Create account system transaction params
* @typedef {Object} CreateAccountParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} newAccountPubkey
* @property {number} lamports
* @property {number} space
* @property {PublicKey} programId
*/
export type CreateAccountParams = {|
fromPubkey: PublicKey,
newAccountPubkey: PublicKey,
lamports: number,
space: number,
programId: PublicKey,
|};
/**
* Transfer system transaction params
* @typedef {Object} TransferParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} toPubkey
* @property {number} lamports
*/
export type TransferParams = {|
fromPubkey: PublicKey,
toPubkey: PublicKey,
lamports: number,
|};
/**
* Assign system transaction params
* @typedef {Object} AssignParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} programId
*/
export type AssignParams = {|
fromPubkey: PublicKey,
programId: PublicKey,
|};
/**
* Create account with seed system transaction params
* @typedef {Object} CreateAccountWithSeedParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} newAccountPubkey
* @property {PublicKey} basePubkey
* @property {string} seed
* @property {number} lamports
* @property {number} space
* @property {PublicKey} programId
*/
export type CreateAccountWithSeedParams = {|
fromPubkey: PublicKey,
newAccountPubkey: PublicKey,
basePubkey: PublicKey,
seed: string,
lamports: number,
space: number,
programId: PublicKey,
|};
/**
* Create nonce account system transaction params
* @typedef {Object} AssignParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} programId
*/
export type CreateNonceAccountParams = {|
fromPubkey: PublicKey,
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
lamports: number,
|};
/**
* Initialize nonce account system instruction params
* @typedef {Object} InitializeNonceParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} programId
*/
export type InitializeNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
|};
/**
* Advance nonce account system instruction params
* @typedef {Object} AdvanceNonceParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} programId
*/
export type AdvanceNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
|};
/**
* Withdraw nonce account system transaction params
* @typedef {Object} WithdrawNonceParams
* @property {PublicKey} noncePubkey
* @property {PublicKey} authorizedPubkey
* @property {PublicKey} toPubkey
* @property {number} lamports
*/
export type WithdrawNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
toPubkey: PublicKey,
lamports: number,
|};
/**
* Authorize nonce account system transaction params
* @typedef {Object} AuthorizeNonceParams
* @property {PublicKey} noncePubkey
* @property {PublicKey} authorizedPubkey
* @property {PublicKey} newAuthorizedPubkey
*/
export type AuthorizeNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
newAuthorizedPubkey: PublicKey,
|};
/**
* System Instruction class
*/
export class SystemInstruction extends TransactionInstruction {
export class SystemInstruction {
/**
* Type of SystemInstruction
* Decode a system instruction and retrieve the instruction type.
*/
_type: SystemInstructionType;
constructor(
opts?: TransactionInstructionCtorFields,
type: SystemInstructionType,
) {
if (
opts &&
opts.programId &&
!opts.programId.equals(SystemProgram.programId)
) {
throw new Error('programId incorrect; not a SystemInstruction');
}
super(opts);
this._type = type;
}
static from(instruction: TransactionInstruction): SystemInstruction {
if (!instruction.programId.equals(SystemProgram.programId)) {
throw new Error('programId incorrect; not SystemProgram');
}
static decodeInstructionType(
instruction: TransactionInstruction,
): SystemInstructionType {
this.checkProgramId(instruction.programId);
const instructionTypeLayout = BufferLayout.u32('instruction');
const typeIndex = instructionTypeLayout.decode(instruction.data);
let type;
for (const t of Object.keys(SYSTEM_INSTRUCTION_LAYOUTS)) {
if (SYSTEM_INSTRUCTION_LAYOUTS[t].index == typeIndex) {
type = t;
}
}
if (!type) {
throw new Error('Instruction type incorrect; not a SystemInstruction');
}
return new SystemInstruction(
{
keys: instruction.keys,
programId: instruction.programId,
data: instruction.data,
},
type,
return type;
}
/**
* Decode a create account system instruction and retrieve the instruction params.
*/
static decodeCreateAccount(
instruction: TransactionInstruction,
): CreateAccountParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {lamports, space, programId} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.Create,
instruction.data,
);
return {
fromPubkey: instruction.keys[0].pubkey,
newAccountPubkey: instruction.keys[1].pubkey,
lamports,
space,
programId: new PublicKey(programId),
};
}
/**
* Type of SystemInstruction
* Decode a transfer system instruction and retrieve the instruction params.
*/
get type(): SystemInstructionType {
return this._type;
static decodeTransfer(instruction: TransactionInstruction): TransferParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {lamports} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.Transfer,
instruction.data,
);
return {
fromPubkey: instruction.keys[0].pubkey,
toPubkey: instruction.keys[1].pubkey,
lamports,
};
}
/**
* The `from` public key of the instruction;
* returns null if SystemInstructionType does not support this field
* Decode an assign system instruction and retrieve the instruction params.
*/
get fromPublicKey(): PublicKey | null {
switch (this.type) {
case 'Create':
case 'CreateWithSeed':
case 'WithdrawNonceAccount':
case 'Transfer':
return this.keys[0].pubkey;
default:
return null;
static decodeAssign(instruction: TransactionInstruction): AssignParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 1);
const {programId} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.Assign,
instruction.data,
);
return {
fromPubkey: instruction.keys[0].pubkey,
programId: new PublicKey(programId),
};
}
/**
* Decode a create account with seed system instruction and retrieve the instruction params.
*/
static decodeCreateWithSeed(
instruction: TransactionInstruction,
): CreateAccountWithSeedParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {base, seed, lamports, space, programId} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed,
instruction.data,
);
return {
fromPubkey: instruction.keys[0].pubkey,
newAccountPubkey: instruction.keys[1].pubkey,
basePubkey: new PublicKey(base),
seed,
lamports,
space,
programId: new PublicKey(programId),
};
}
/**
* Decode a nonce initialize system instruction and retrieve the instruction params.
*/
static decodeNonceInitialize(
instruction: TransactionInstruction,
): InitializeNonceParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {authorized} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount,
instruction.data,
);
return {
noncePubkey: instruction.keys[0].pubkey,
authorizedPubkey: new PublicKey(authorized),
};
}
/**
* Decode a nonce advance system instruction and retrieve the instruction params.
*/
static decodeNonceAdvance(
instruction: TransactionInstruction,
): AdvanceNonceParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount,
instruction.data,
);
return {
noncePubkey: instruction.keys[0].pubkey,
authorizedPubkey: instruction.keys[2].pubkey,
};
}
/**
* Decode a nonce withdraw system instruction and retrieve the instruction params.
*/
static decodeNonceWithdraw(
instruction: TransactionInstruction,
): WithdrawNonceParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 5);
const {lamports} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount,
instruction.data,
);
return {
noncePubkey: instruction.keys[0].pubkey,
toPubkey: instruction.keys[1].pubkey,
authorizedPubkey: instruction.keys[4].pubkey,
lamports,
};
}
/**
* Decode a nonce authorize system instruction and retrieve the instruction params.
*/
static decodeNonceAuthorize(
instruction: TransactionInstruction,
): AuthorizeNonceParams {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {authorized} = decodeData(
SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount,
instruction.data,
);
return {
noncePubkey: instruction.keys[0].pubkey,
authorizedPubkey: instruction.keys[1].pubkey,
newAuthorizedPubkey: new PublicKey(authorized),
};
}
/**
* @private
*/
static checkProgramId(programId: PublicKey) {
if (!programId.equals(SystemProgram.programId)) {
throw new Error('invalid instruction; programId is not SystemProgram');
}
}
/**
* The `to` public key of the instruction;
* returns null if SystemInstructionType does not support this field
* @private
*/
get toPublicKey(): PublicKey | null {
switch (this.type) {
case 'Create':
case 'CreateWithSeed':
case 'WithdrawNonceAccount':
case 'Transfer':
return this.keys[1].pubkey;
default:
return null;
}
}
/**
* The `amount` or `lamports` of the instruction;
* returns null if SystemInstructionType does not support this field
*/
get amount(): number | null {
const data = SYSTEM_INSTRUCTION_LAYOUTS[this.type].layout.decode(this.data);
switch (this.type) {
case 'Create':
case 'CreateWithSeed':
case 'WithdrawNonceAccount':
case 'Transfer':
return data.lamports;
default:
return null;
static checkKeyLength(keys: Array<any>, expectedLength: number) {
if (keys.length !== expectedLength) {
throw new Error(
`invalid instruction; key length mismatch ${keys.length} != ${expectedLength}`,
);
}
}
}
@ -212,24 +447,18 @@ export class SystemProgram {
/**
* Generate a Transaction that creates a new account
*/
static createAccount(
from: PublicKey,
newAccount: PublicKey,
lamports: number,
space: number,
programId: PublicKey,
): Transaction {
static createAccount(params: CreateAccountParams): Transaction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Create;
const data = encodeData(type, {
lamports,
space,
programId: programId.toBuffer(),
lamports: params.lamports,
space: params.space,
programId: params.programId.toBuffer(),
});
return new Transaction().add({
keys: [
{pubkey: from, isSigner: true, isWritable: true},
{pubkey: newAccount, isSigner: true, isWritable: true},
{pubkey: params.fromPubkey, isSigner: true, isWritable: true},
{pubkey: params.newAccountPubkey, isSigner: true, isWritable: true},
],
programId: this.programId,
data,
@ -239,18 +468,14 @@ export class SystemProgram {
/**
* Generate a Transaction that transfers lamports from one account to another
*/
static transfer(
from: PublicKey,
to: PublicKey,
lamports: number,
): Transaction {
static transfer(params: TransferParams): Transaction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Transfer;
const data = encodeData(type, {lamports});
const data = encodeData(type, {lamports: params.lamports});
return new Transaction().add({
keys: [
{pubkey: from, isSigner: true, isWritable: true},
{pubkey: to, isSigner: false, isWritable: true},
{pubkey: params.fromPubkey, isSigner: true, isWritable: true},
{pubkey: params.toPubkey, isSigner: false, isWritable: true},
],
programId: this.programId,
data,
@ -260,12 +485,12 @@ export class SystemProgram {
/**
* Generate a Transaction that assigns an account to a program
*/
static assign(from: PublicKey, programId: PublicKey): Transaction {
static assign(params: AssignParams): Transaction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Assign;
const data = encodeData(type, {programId: programId.toBuffer()});
const data = encodeData(type, {programId: params.programId.toBuffer()});
return new Transaction().add({
keys: [{pubkey: from, isSigner: true, isWritable: true}],
keys: [{pubkey: params.fromPubkey, isSigner: true, isWritable: true}],
programId: this.programId,
data,
});
@ -276,27 +501,21 @@ export class SystemProgram {
* an address generated with `from`, a seed, and programId
*/
static createAccountWithSeed(
from: PublicKey,
newAccount: PublicKey,
base: PublicKey,
seed: string,
lamports: number,
space: number,
programId: PublicKey,
params: CreateAccountWithSeedParams,
): Transaction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed;
const data = encodeData(type, {
base: base.toBuffer(),
seed,
lamports,
space,
programId: programId.toBuffer(),
base: params.basePubkey.toBuffer(),
seed: params.seed,
lamports: params.lamports,
space: params.space,
programId: params.programId.toBuffer(),
});
return new Transaction().add({
keys: [
{pubkey: from, isSigner: true, isWritable: true},
{pubkey: newAccount, isSigner: false, isWritable: true},
{pubkey: params.fromPubkey, isSigner: true, isWritable: true},
{pubkey: params.newAccountPubkey, isSigner: false, isWritable: true},
],
programId: this.programId,
data,
@ -306,28 +525,37 @@ export class SystemProgram {
/**
* Generate a Transaction that creates a new Nonce account
*/
static createNonceAccount(
from: PublicKey,
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
lamports: number,
): Transaction {
let transaction = SystemProgram.createAccount(
from,
nonceAccount,
lamports,
this.nonceSpace,
this.programId,
);
const type = SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount;
const data = encodeData(type, {
authorized: authorizedPubkey.toBuffer(),
static createNonceAccount(params: CreateNonceAccountParams): Transaction {
let transaction = SystemProgram.createAccount({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
lamports: params.lamports,
space: this.nonceSpace,
programId: this.programId,
});
return transaction.add({
const initParams = {
noncePubkey: params.noncePubkey,
authorizedPubkey: params.authorizedPubkey,
};
transaction.add(this.nonceInitialize(initParams));
return transaction;
}
/**
* Generate an instruction to initialize a Nonce account
*/
static nonceInitialize(
params: InitializeNonceParams,
): TransactionInstruction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount;
const data = encodeData(type, {
authorized: params.authorizedPubkey.toBuffer(),
});
const instructionData = {
keys: [
{pubkey: nonceAccount, isSigner: false, isWritable: true},
{pubkey: params.noncePubkey, isSigner: false, isWritable: true},
{
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
isSigner: false,
@ -337,27 +565,25 @@ export class SystemProgram {
],
programId: this.programId,
data,
});
};
return new TransactionInstruction(instructionData);
}
/**
* Generate an instruction to advance the nonce in a Nonce account
*/
static nonceAdvance(
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
): TransactionInstruction {
static nonceAdvance(params: AdvanceNonceParams): TransactionInstruction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount;
const data = encodeData(type);
const instructionData = {
keys: [
{pubkey: nonceAccount, isSigner: false, isWritable: true},
{pubkey: params.noncePubkey, isSigner: false, isWritable: true},
{
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
isSigner: false,
isWritable: false,
},
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
{pubkey: params.authorizedPubkey, isSigner: true, isWritable: false},
],
programId: this.programId,
data,
@ -368,19 +594,14 @@ export class SystemProgram {
/**
* Generate a Transaction that withdraws lamports from a Nonce account
*/
static nonceWithdraw(
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
to: PublicKey,
lamports: number,
): Transaction {
static nonceWithdraw(params: WithdrawNonceParams): Transaction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount;
const data = encodeData(type, {lamports});
const data = encodeData(type, {lamports: params.lamports});
return new Transaction().add({
keys: [
{pubkey: nonceAccount, isSigner: false, isWritable: true},
{pubkey: to, isSigner: false, isWritable: true},
{pubkey: params.noncePubkey, isSigner: false, isWritable: true},
{pubkey: params.toPubkey, isSigner: false, isWritable: true},
{
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
isSigner: false,
@ -391,7 +612,7 @@ export class SystemProgram {
isSigner: false,
isWritable: false,
},
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
{pubkey: params.authorizedPubkey, isSigner: true, isWritable: false},
],
programId: this.programId,
data,
@ -402,20 +623,16 @@ export class SystemProgram {
* Generate a Transaction that authorizes a new PublicKey as the authority
* on a Nonce account.
*/
static nonceAuthorize(
nonceAccount: PublicKey,
authorizedPubkey: PublicKey,
newAuthorized: PublicKey,
): Transaction {
static nonceAuthorize(params: AuthorizeNonceParams): Transaction {
const type = SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount;
const data = encodeData(type, {
newAuthorized: newAuthorized.toBuffer(),
authorized: params.newAuthorizedPubkey.toBuffer(),
});
return new Transaction().add({
keys: [
{pubkey: nonceAccount, isSigner: false, isWritable: true},
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
{pubkey: params.noncePubkey, isSigner: false, isWritable: true},
{pubkey: params.authorizedPubkey, isSigner: true, isWritable: false},
],
programId: this.programId,
data,

View File

@ -109,10 +109,10 @@ test('get program accounts', async () => {
result: {Ok: null},
},
]);
let transaction = SystemProgram.assign(
account0.publicKey,
programId.publicKey,
);
let transaction = SystemProgram.assign({
fromPubkey: account0.publicKey,
programId: programId.publicKey,
});
await sendAndConfirmTransaction(connection, transaction, account0);
mockRpc.push([
@ -140,7 +140,11 @@ test('get program accounts', async () => {
result: {Ok: null},
},
]);
transaction = SystemProgram.assign(account1.publicKey, programId.publicKey);
transaction = SystemProgram.assign({
fromPubkey: account1.publicKey,
programId: programId.publicKey,
});
await sendAndConfirmTransaction(connection, transaction, account1);
mockGetRecentBlockhash('recent');
@ -651,14 +655,16 @@ test('get confirmed block', async () => {
url,
{
method: 'getConfirmedBlock',
params: [10000],
params: [Number.MAX_SAFE_INTEGER],
},
{
error: null,
result: null,
},
]);
await expect(connection.getConfirmedBlock(10000)).rejects.toThrow();
await expect(
connection.getConfirmedBlock(Number.MAX_SAFE_INTEGER),
).rejects.toThrow();
});
test('get recent blockhash', async () => {
@ -962,11 +968,11 @@ test('transaction', async () => {
},
]);
const transaction = SystemProgram.transfer(
accountFrom.publicKey,
accountTo.publicKey,
10,
);
const transaction = SystemProgram.transfer({
fromPubkey: accountFrom.publicKey,
toPubkey: accountTo.publicKey,
lamports: 10,
});
const signature = await connection.sendTransaction(transaction, accountFrom);
mockRpc.push([
@ -1088,12 +1094,16 @@ test('multi-instruction transaction', async () => {
// 1. Move(accountFrom, accountTo)
// 2. Move(accountTo, accountFrom)
const transaction = SystemProgram.transfer(
accountFrom.publicKey,
accountTo.publicKey,
100,
).add(
SystemProgram.transfer(accountTo.publicKey, accountFrom.publicKey, 100),
const transaction = SystemProgram.transfer({
fromPubkey: accountFrom.publicKey,
toPubkey: accountTo.publicKey,
lamports: 100,
}).add(
SystemProgram.transfer({
fromPubkey: accountTo.publicKey,
toPubkey: accountFrom.publicKey,
lamports: 100,
}),
);
const signature = await connection.sendTransaction(
transaction,
@ -1149,11 +1159,11 @@ test('account change notification', async () => {
await connection.requestAirdrop(owner.publicKey, LAMPORTS_PER_SOL);
try {
let transaction = SystemProgram.transfer(
owner.publicKey,
programAccount.publicKey,
balanceNeeded,
);
let transaction = SystemProgram.transfer({
fromPubkey: owner.publicKey,
toPubkey: programAccount.publicKey,
lamports: balanceNeeded,
});
await sendAndConfirmTransaction(connection, transaction, owner);
} catch (err) {
await connection.removeAccountChangeListener(subscriptionId);
@ -1213,11 +1223,11 @@ test('program account change notification', async () => {
await connection.requestAirdrop(owner.publicKey, LAMPORTS_PER_SOL);
try {
let transaction = SystemProgram.transfer(
owner.publicKey,
programAccount.publicKey,
balanceNeeded,
);
let transaction = SystemProgram.transfer({
fromPubkey: owner.publicKey,
toPubkey: programAccount.publicKey,
lamports: balanceNeeded,
});
await sendAndConfirmTransaction(connection, transaction, owner);
} catch (err) {
await connection.removeProgramAccountChangeListener(subscriptionId);

View File

@ -86,12 +86,12 @@ test('create and query nonce account', async () => {
},
]);
const transaction = SystemProgram.createNonceAccount(
from.publicKey,
nonceAccount.publicKey,
from.publicKey,
minimumAmount,
);
const transaction = SystemProgram.createNonceAccount({
fromPubkey: from.publicKey,
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: from.publicKey,
lamports: minimumAmount,
});
await connection.sendTransaction(transaction, from, nonceAccount);
const expectedData = Buffer.alloc(68);

View File

@ -12,7 +12,6 @@ import {
StakeInstruction,
StakeProgram,
SystemInstruction,
SystemProgram,
Transaction,
} from '../src';
import {mockRpcEnabled} from './__mocks__/node-fetch';
@ -34,6 +33,7 @@ test('createAccountWithSeed', () => {
const authorizedPubkey = new Account().publicKey;
const authorized = new Authorized(authorizedPubkey, authorizedPubkey);
const lockup = new Lockup(0, 0, fromPubkey);
const lamports = 123;
const transaction = StakeProgram.createAccountWithSeed({
fromPubkey,
stakePubkey: newAccountPubkey,
@ -41,19 +41,26 @@ test('createAccountWithSeed', () => {
seed,
authorized,
lockup,
lamports: 123,
lamports,
});
expect(transaction.instructions).toHaveLength(2);
const [systemInstruction, stakeInstruction] = transaction.instructions;
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
// TODO decode system instruction
const params = StakeInstruction.decodeInitialize(stakeInstruction);
expect(params.stakePubkey).toEqual(newAccountPubkey);
expect(params.authorized).toEqual(authorized);
expect(params.lockup).toEqual(lockup);
const systemParams = {
fromPubkey,
newAccountPubkey,
basePubkey: fromPubkey,
seed,
lamports,
space: StakeProgram.space,
programId: StakeProgram.programId,
};
expect(systemParams).toEqual(
SystemInstruction.decodeCreateWithSeed(systemInstruction),
);
const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
expect(initParams).toEqual(
StakeInstruction.decodeInitialize(stakeInstruction),
);
});
test('createAccount', () => {
@ -62,24 +69,31 @@ test('createAccount', () => {
const authorizedPubkey = new Account().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: 123,
lamports,
});
expect(transaction.instructions).toHaveLength(2);
const [systemInstruction, stakeInstruction] = transaction.instructions;
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
const systemParams = {
fromPubkey,
newAccountPubkey,
lamports,
space: StakeProgram.space,
programId: StakeProgram.programId,
};
expect(systemParams).toEqual(
SystemInstruction.decodeCreateAccount(systemInstruction),
);
// TODO decode system instruction
const params = StakeInstruction.decodeInitialize(stakeInstruction);
expect(params.stakePubkey).toEqual(newAccountPubkey);
expect(params.authorized).toEqual(authorized);
expect(params.lockup).toEqual(lockup);
const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
expect(initParams).toEqual(
StakeInstruction.decodeInitialize(stakeInstruction),
);
});
test('delegate', () => {
@ -127,7 +141,16 @@ test('split', () => {
const transaction = StakeProgram.split(params);
expect(transaction.instructions).toHaveLength(2);
const [systemInstruction, stakeInstruction] = transaction.instructions;
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
const systemParams = {
fromPubkey: stakePubkey,
newAccountPubkey: splitStakePubkey,
lamports: 0,
space: StakeProgram.space,
programId: StakeProgram.programId,
};
expect(systemParams).toEqual(
SystemInstruction.decodeCreateAccount(systemInstruction),
);
expect(params).toEqual(StakeInstruction.decodeSplit(stakeInstruction));
});
@ -182,13 +205,10 @@ test('StakeInstructions', () => {
);
expect(createWithSeedTransaction.instructions).toHaveLength(2);
const systemInstruction = SystemInstruction.from(
const systemInstructionType = SystemInstruction.decodeInstructionType(
createWithSeedTransaction.instructions[0],
);
expect(systemInstruction.fromPublicKey).toEqual(from.publicKey);
expect(systemInstruction.toPublicKey).toEqual(newAccountPubkey);
expect(systemInstruction.amount).toEqual(amount);
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
expect(systemInstructionType).toEqual('CreateWithSeed');
const stakeInstructionType = StakeInstruction.decodeInstructionType(
createWithSeedTransaction.instructions[1],
@ -237,6 +257,35 @@ test('live staking actions', async () => {
'recent',
);
{
// Create Stake account without seed
const newStakeAccount = new Account();
let createAndInitialize = StakeProgram.createAccount({
fromPubkey: from.publicKey,
stakePubkey: newStakeAccount.publicKey,
authorized: new Authorized(authorized.publicKey, authorized.publicKey),
lockup: new Lockup(0, 0, new PublicKey('0x00')),
lamports: minimumAmount + 42,
});
await sendAndConfirmRecentTransaction(
connection,
createAndInitialize,
from,
newStakeAccount,
);
expect(await connection.getBalance(newStakeAccount.publicKey)).toEqual(
minimumAmount + 42,
);
let delegation = StakeProgram.delegate({
stakePubkey: newStakeAccount.publicKey,
authorizedPubkey: authorized.publicKey,
votePubkey,
});
await sendAndConfirmRecentTransaction(connection, delegation, authorized);
}
// Create Stake account with seed
const seed = 'test string';
const newAccountPubkey = PublicKey.createWithSeed(

View File

@ -7,6 +7,7 @@ import {
SystemInstruction,
SystemProgram,
Transaction,
TransactionInstruction,
sendAndConfirmRecentTransaction,
LAMPORTS_PER_SOL,
} from '../src';
@ -20,219 +21,129 @@ if (!mockRpcEnabled) {
}
test('createAccount', () => {
const from = new Account();
const newAccount = new Account();
let transaction;
transaction = SystemProgram.createAccount(
from.publicKey,
newAccount.publicKey,
123,
BudgetProgram.space,
BudgetProgram.programId,
const params = {
fromPubkey: new Account().publicKey,
newAccountPubkey: new Account().publicKey,
lamports: 123,
space: BudgetProgram.space,
programId: BudgetProgram.programId,
};
const transaction = SystemProgram.createAccount(params);
expect(transaction.instructions).toHaveLength(1);
const [systemInstruction] = transaction.instructions;
expect(params).toEqual(
SystemInstruction.decodeCreateAccount(systemInstruction),
);
expect(transaction.keys).toHaveLength(2);
expect(transaction.programId).toEqual(SystemProgram.programId);
// TODO: Validate transaction contents more
});
test('transfer', () => {
const from = new Account();
const to = new Account();
let transaction;
transaction = SystemProgram.transfer(from.publicKey, to.publicKey, 123);
expect(transaction.keys).toHaveLength(2);
expect(transaction.programId).toEqual(SystemProgram.programId);
// TODO: Validate transaction contents more
const params = {
fromPubkey: new Account().publicKey,
toPubkey: new Account().publicKey,
lamports: 123,
};
const transaction = SystemProgram.transfer(params);
expect(transaction.instructions).toHaveLength(1);
const [systemInstruction] = transaction.instructions;
expect(params).toEqual(SystemInstruction.decodeTransfer(systemInstruction));
});
test('assign', () => {
const from = new Account();
const to = new Account();
let transaction;
transaction = SystemProgram.assign(from.publicKey, to.publicKey);
expect(transaction.keys).toHaveLength(1);
expect(transaction.programId).toEqual(SystemProgram.programId);
// TODO: Validate transaction contents more
const params = {
fromPubkey: new Account().publicKey,
programId: new Account().publicKey,
};
const transaction = SystemProgram.assign(params);
expect(transaction.instructions).toHaveLength(1);
const [systemInstruction] = transaction.instructions;
expect(params).toEqual(SystemInstruction.decodeAssign(systemInstruction));
});
test('createAccountWithSeed', () => {
const from = new Account();
const newAccount = new Account();
let transaction;
transaction = SystemProgram.createAccountWithSeed(
from.publicKey,
newAccount.publicKey,
from.publicKey,
'hi there',
123,
BudgetProgram.space,
BudgetProgram.programId,
const fromPubkey = new Account().publicKey;
const params = {
fromPubkey,
newAccountPubkey: new Account().publicKey,
basePubkey: fromPubkey,
seed: 'hi there',
lamports: 123,
space: BudgetProgram.space,
programId: BudgetProgram.programId,
};
const transaction = SystemProgram.createAccountWithSeed(params);
expect(transaction.instructions).toHaveLength(1);
const [systemInstruction] = transaction.instructions;
expect(params).toEqual(
SystemInstruction.decodeCreateWithSeed(systemInstruction),
);
expect(transaction.keys).toHaveLength(2);
expect(transaction.programId).toEqual(SystemProgram.programId);
// TODO: Validate transaction contents more
});
test('createNonceAccount', () => {
const from = new Account();
const nonceAccount = new Account();
const transaction = SystemProgram.createNonceAccount(
from.publicKey,
nonceAccount.publicKey,
from.publicKey,
123,
);
const fromPubkey = new Account().publicKey;
const params = {
fromPubkey,
noncePubkey: new Account().publicKey,
authorizedPubkey: fromPubkey,
lamports: 123,
};
const transaction = SystemProgram.createNonceAccount(params);
expect(transaction.instructions).toHaveLength(2);
expect(transaction.instructions[0].programId).toEqual(
SystemProgram.programId,
const [createInstruction, initInstruction] = transaction.instructions;
const createParams = {
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
lamports: params.lamports,
space: SystemProgram.nonceSpace,
programId: SystemProgram.programId,
};
expect(createParams).toEqual(
SystemInstruction.decodeCreateAccount(createInstruction),
);
expect(transaction.instructions[1].programId).toEqual(
SystemProgram.programId,
const initParams = {
noncePubkey: params.noncePubkey,
authorizedPubkey: fromPubkey,
};
expect(initParams).toEqual(
SystemInstruction.decodeNonceInitialize(initInstruction),
);
// TODO: Validate transaction contents more
});
test('nonceAdvance', () => {
const params = {
noncePubkey: new Account().publicKey,
authorizedPubkey: new Account().publicKey,
};
const instruction = SystemProgram.nonceAdvance(params);
expect(params).toEqual(SystemInstruction.decodeNonceAdvance(instruction));
});
test('nonceWithdraw', () => {
const from = new Account();
const nonceAccount = new Account();
const to = new Account();
const transaction = SystemProgram.nonceWithdraw(
nonceAccount.publicKey,
from.publicKey,
to.publicKey,
123,
);
expect(transaction.keys).toHaveLength(5);
expect(transaction.programId).toEqual(SystemProgram.programId);
// TODO: Validate transaction contents more
const params = {
noncePubkey: new Account().publicKey,
authorizedPubkey: new Account().publicKey,
toPubkey: new Account().publicKey,
lamports: 123,
};
const transaction = SystemProgram.nonceWithdraw(params);
expect(transaction.instructions).toHaveLength(1);
const [instruction] = transaction.instructions;
expect(params).toEqual(SystemInstruction.decodeNonceWithdraw(instruction));
});
test('nonceAuthorize', () => {
const nonceAccount = new Account();
const authorized = new Account();
const newAuthorized = new Account();
const params = {
noncePubkey: new Account().publicKey,
authorizedPubkey: new Account().publicKey,
newAuthorizedPubkey: new Account().publicKey,
};
const transaction = SystemProgram.nonceAuthorize(
nonceAccount.publicKey,
authorized.publicKey,
newAuthorized.publicKey,
);
expect(transaction.keys).toHaveLength(2);
expect(transaction.programId).toEqual(SystemProgram.programId);
// TODO: Validate transaction contents more
});
test('SystemInstruction create', () => {
const from = new Account();
const to = new Account();
const program = new Account();
const amount = 42;
const space = 100;
const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
const create = SystemProgram.createAccount(
from.publicKey,
to.publicKey,
amount,
space,
program.publicKey,
);
const transaction = new Transaction({recentBlockhash}).add(create);
const systemInstruction = SystemInstruction.from(transaction.instructions[0]);
expect(systemInstruction.fromPublicKey).toEqual(from.publicKey);
expect(systemInstruction.toPublicKey).toEqual(to.publicKey);
expect(systemInstruction.amount).toEqual(amount);
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
});
test('SystemInstruction transfer', () => {
const from = new Account();
const to = new Account();
const amount = 42;
const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
const transfer = SystemProgram.transfer(from.publicKey, to.publicKey, amount);
const transaction = new Transaction({recentBlockhash}).add(transfer);
transaction.sign(from);
const systemInstruction = SystemInstruction.from(transaction.instructions[0]);
expect(systemInstruction.fromPublicKey).toEqual(from.publicKey);
expect(systemInstruction.toPublicKey).toEqual(to.publicKey);
expect(systemInstruction.amount).toEqual(amount);
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
});
test('SystemInstruction assign', () => {
const from = new Account();
const program = new Account();
const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
const assign = SystemProgram.assign(from.publicKey, program.publicKey);
const transaction = new Transaction({recentBlockhash}).add(assign);
transaction.sign(from);
const systemInstruction = SystemInstruction.from(transaction.instructions[0]);
expect(systemInstruction.fromPublicKey).toBeNull();
expect(systemInstruction.toPublicKey).toBeNull();
expect(systemInstruction.amount).toBeNull();
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
});
test('SystemInstruction createWithSeed', () => {
const from = new Account();
const to = new Account();
const program = new Account();
const amount = 42;
const space = 100;
const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
const create = SystemProgram.createAccountWithSeed(
from.publicKey,
to.publicKey,
from.publicKey,
'hi there',
amount,
space,
program.publicKey,
);
const transaction = new Transaction({recentBlockhash}).add(create);
const systemInstruction = SystemInstruction.from(transaction.instructions[0]);
expect(systemInstruction.fromPublicKey).toEqual(from.publicKey);
expect(systemInstruction.toPublicKey).toEqual(to.publicKey);
expect(systemInstruction.amount).toEqual(amount);
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
});
test('SystemInstruction nonceWithdraw', () => {
const nonceAccount = new Account();
const authorized = new Account();
const to = new Account();
const amount = 42;
const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
const nonceWithdraw = SystemProgram.nonceWithdraw(
nonceAccount.publicKey,
authorized.publicKey,
to.publicKey,
amount,
);
const transaction = new Transaction({recentBlockhash}).add(nonceWithdraw);
const systemInstruction = SystemInstruction.from(transaction.instructions[0]);
expect(systemInstruction.fromPublicKey).toEqual(nonceAccount.publicKey);
expect(systemInstruction.toPublicKey).toEqual(to.publicKey);
expect(systemInstruction.amount).toEqual(amount);
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
const transaction = SystemProgram.nonceAuthorize(params);
expect(transaction.instructions).toHaveLength(1);
const [instruction] = transaction.instructions;
expect(params).toEqual(SystemInstruction.decodeNonceAuthorize(instruction));
});
test('non-SystemInstruction error', () => {
@ -249,7 +160,9 @@ test('non-SystemInstruction error', () => {
data: Buffer.from([2, 0, 0, 0]),
};
expect(() => {
new SystemInstruction(badProgramId, 'Create');
SystemInstruction.decodeInstructionType(
new TransactionInstruction(badProgramId),
);
}).toThrow();
const amount = 123;
@ -264,12 +177,12 @@ test('non-SystemInstruction error', () => {
transaction.sign(from);
expect(() => {
SystemInstruction.from(transaction.instructions[1]);
SystemInstruction.decodeInstructionType(transaction.instructions[1]);
}).toThrow();
transaction.instructions[0].data[0] = 11;
expect(() => {
SystemInstruction.from(transaction.instructions[0]);
SystemInstruction.decodeInstructionType(transaction.instructions[0]);
}).toThrow();
});
@ -284,20 +197,22 @@ test('live Nonce actions', async () => {
const from = new Account();
const to = new Account();
const authority = new Account();
const newAuthority = new Account();
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL);
await connection.requestAirdrop(authority.publicKey, LAMPORTS_PER_SOL);
await connection.requestAirdrop(newAuthority.publicKey, LAMPORTS_PER_SOL);
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
SystemProgram.nonceSpace,
'recent',
);
let createNonceAccount = SystemProgram.createNonceAccount(
from.publicKey,
nonceAccount.publicKey,
from.publicKey,
minimumAmount,
);
let createNonceAccount = SystemProgram.createNonceAccount({
fromPubkey: from.publicKey,
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: from.publicKey,
lamports: minimumAmount,
});
await sendAndConfirmRecentTransaction(
connection,
createNonceAccount,
@ -311,33 +226,74 @@ test('live Nonce actions', async () => {
const nonceQuery2 = await connection.getNonce(nonceAccount.publicKey);
expect(nonceQuery1.nonce).toEqual(nonceQuery2.nonce);
// Wait for blockhash to advance
await sleep(500);
const advanceNonce = new Transaction().add(
SystemProgram.nonceAdvance(nonceAccount.publicKey, from.publicKey),
SystemProgram.nonceAdvance({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: from.publicKey,
}),
);
await sendAndConfirmRecentTransaction(connection, advanceNonce, from);
const nonceQuery3 = await connection.getNonce(nonceAccount.publicKey);
expect(nonceQuery1.nonce).not.toEqual(nonceQuery3.nonce);
const nonce = nonceQuery3.nonce;
// Wait for blockhash to advance
await sleep(500);
let transfer = SystemProgram.transfer(
from.publicKey,
to.publicKey,
minimumAmount,
const authorizeNonce = new Transaction().add(
SystemProgram.nonceAuthorize({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: from.publicKey,
newAuthorizedPubkey: newAuthority.publicKey,
}),
);
await sendAndConfirmRecentTransaction(connection, authorizeNonce, from);
let transfer = SystemProgram.transfer({
fromPubkey: from.publicKey,
toPubkey: to.publicKey,
lamports: minimumAmount,
});
transfer.nonceInfo = {
nonce,
nonceInstruction: SystemProgram.nonceAdvance(
nonceAccount.publicKey,
from.publicKey,
),
nonceInstruction: SystemProgram.nonceAdvance({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: newAuthority.publicKey,
}),
};
await sendAndConfirmRecentTransaction(connection, transfer, from);
await sendAndConfirmRecentTransaction(
connection,
transfer,
from,
newAuthority,
);
const toBalance = await connection.getBalance(to.publicKey);
expect(toBalance).toEqual(minimumAmount);
// Wait for blockhash to advance
await sleep(500);
const withdrawAccount = new Account();
const withdrawNonce = new Transaction().add(
SystemProgram.nonceWithdraw({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: newAuthority.publicKey,
lamports: minimumAmount,
toPubkey: withdrawAccount.publicKey,
}),
);
await sendAndConfirmRecentTransaction(
connection,
withdrawNonce,
newAuthority,
);
expect(await connection.getBalance(nonceAccount.publicKey)).toEqual(0);
const withdrawBalance = await connection.getBalance(
withdrawAccount.publicKey,
);
expect(withdrawBalance).toEqual(minimumAmount);
});

View File

@ -100,11 +100,11 @@ test('transaction-payer', async () => {
},
]);
const transaction = SystemProgram.transfer(
accountFrom.publicKey,
accountTo.publicKey,
10,
);
const transaction = SystemProgram.transfer({
fromPubkey: accountFrom.publicKey,
toPubkey: accountTo.publicKey,
lamports: 10,
});
const signature = await connection.sendTransaction(
transaction,

View File

@ -12,11 +12,11 @@ test('signPartial', () => {
const account1 = new Account();
const account2 = new Account();
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
const transfer = SystemProgram.transfer(
account1.publicKey,
account2.publicKey,
123,
);
const transfer = SystemProgram.transfer({
fromPubkey: account1.publicKey,
toPubkey: account2.publicKey,
lamports: 123,
});
const transaction = new Transaction({recentBlockhash}).add(transfer);
transaction.sign(account1, account2);
@ -33,16 +33,16 @@ test('transfer signatures', () => {
const account1 = new Account();
const account2 = new Account();
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
const transfer1 = SystemProgram.transfer(
account1.publicKey,
account2.publicKey,
123,
);
const transfer2 = SystemProgram.transfer(
account2.publicKey,
account1.publicKey,
123,
);
const transfer1 = SystemProgram.transfer({
fromPubkey: account1.publicKey,
toPubkey: account2.publicKey,
lamports: 123,
});
const transfer2 = SystemProgram.transfer({
fromPubkey: account2.publicKey,
toPubkey: account1.publicKey,
lamports: 123,
});
const orgTransaction = new Transaction({recentBlockhash}).add(
transfer1,
@ -62,16 +62,16 @@ test('dedup signatures', () => {
const account1 = new Account();
const account2 = new Account();
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
const transfer1 = SystemProgram.transfer(
account1.publicKey,
account2.publicKey,
123,
);
const transfer2 = SystemProgram.transfer(
account1.publicKey,
account2.publicKey,
123,
);
const transfer1 = SystemProgram.transfer({
fromPubkey: account1.publicKey,
toPubkey: account2.publicKey,
lamports: 123,
});
const transfer2 = SystemProgram.transfer({
fromPubkey: account1.publicKey,
toPubkey: account2.publicKey,
lamports: 123,
});
const orgTransaction = new Transaction({recentBlockhash}).add(
transfer1,
@ -88,14 +88,18 @@ test('use nonce', () => {
const nonceInfo = {
nonce,
nonceInstruction: SystemProgram.nonceAdvance(
nonceAccount.publicKey,
account1.publicKey,
),
nonceInstruction: SystemProgram.nonceAdvance({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: account1.publicKey,
}),
};
const transferTransaction = new Transaction({nonceInfo}).add(
SystemProgram.transfer(account1.publicKey, account2.publicKey, 123),
SystemProgram.transfer({
fromPubkey: account1.publicKey,
toPubkey: account2.publicKey,
lamports: 123,
}),
);
transferTransaction.sign(account1);
@ -137,7 +141,11 @@ test('parse wire format and serialize', () => {
const recipient = new PublicKey(
'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99',
); // Arbitrary known public key
const transfer = SystemProgram.transfer(sender.publicKey, recipient, 49);
const transfer = SystemProgram.transfer({
fromPubkey: sender.publicKey,
toPubkey: recipient,
lamports: 49,
});
const expectedTransaction = new Transaction({recentBlockhash}).add(transfer);
expectedTransaction.sign(sender);
@ -198,7 +206,11 @@ test('serialize unsigned transaction', () => {
const recipient = new PublicKey(
'J3dxNj7nDRRqRRXuEMynDG57DkZK4jYRuv3Garmb1i99',
); // Arbitrary known public key
const transfer = SystemProgram.transfer(sender.publicKey, recipient, 49);
const transfer = SystemProgram.transfer({
fromPubkey: sender.publicKey,
toPubkey: recipient,
lamports: 49,
});
const expectedTransaction = new Transaction({recentBlockhash}).add(transfer);
const wireTransactionArray = [