feat: add stake program methods; refactor instruction type handling
This commit is contained in:
committed by
Michael Vines
parent
fc77e55920
commit
532b28e96e
4
web3.js/flow-typed/hasha.js
vendored
Normal file
4
web3.js/flow-typed/hasha.js
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module 'hasha' {
|
||||||
|
// TODO: Fill in types
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
@ -203,6 +203,62 @@ declare module '@solana/web3.js' {
|
|||||||
validatorExit(): Promise<boolean>;
|
validatorExit(): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === src/config-program.js ===
|
||||||
|
declare export var CONFIG_PROGRAM_ID;
|
||||||
|
|
||||||
|
// === src/stake-program.js ===
|
||||||
|
declare export class StakeProgram {
|
||||||
|
static programId: PublicKey;
|
||||||
|
static space: number;
|
||||||
|
|
||||||
|
static createAccount(
|
||||||
|
from: PublicKey,
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorized: Authorized,
|
||||||
|
lockup: Lockup,
|
||||||
|
lamports: number,
|
||||||
|
): Transaction;
|
||||||
|
static createAccountWithSeed(
|
||||||
|
from: PublicKey,
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
seed: string,
|
||||||
|
authorized: Authorized,
|
||||||
|
lockup: Lockup,
|
||||||
|
lamports: number,
|
||||||
|
): Transaction;
|
||||||
|
static delegate(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
votePubkey: PublicKey,
|
||||||
|
): Transaction;
|
||||||
|
static authorize(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
newAuthorized: PublicKey,
|
||||||
|
stakeAuthorizationType: StakeAuthorizationType,
|
||||||
|
): Transaction;
|
||||||
|
static redeemVoteCredits(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
votePubkey: PublicKey,
|
||||||
|
): Transaction;
|
||||||
|
static split(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
lamports: number,
|
||||||
|
splitStakePubkey: PublicKey,
|
||||||
|
): Transaction;
|
||||||
|
static withdraw(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
withdrawerPubkey: PublicKey,
|
||||||
|
to: PublicKey,
|
||||||
|
lamports: number,
|
||||||
|
): Transaction;
|
||||||
|
static deactivate(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
): Transaction;
|
||||||
|
}
|
||||||
|
|
||||||
// === src/system-program.js ===
|
// === src/system-program.js ===
|
||||||
declare export class SystemProgram {
|
declare export class SystemProgram {
|
||||||
static programId: PublicKey;
|
static programId: PublicKey;
|
||||||
@ -248,11 +304,14 @@ declare module '@solana/web3.js' {
|
|||||||
static fromConfigData(buffer: Buffer): ?ValidatorInfo;
|
static fromConfigData(buffer: Buffer): ?ValidatorInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === src/sysvar-rent.js ===
|
// === src/sysvar.js ===
|
||||||
|
declare export var SYSVAR_CLOCK_PUBKEY;
|
||||||
declare export var SYSVAR_RENT_PUBKEY;
|
declare export var SYSVAR_RENT_PUBKEY;
|
||||||
|
declare export var SYSVAR_REWARDS_PUBKEY;
|
||||||
|
declare export var SYSVAR_STAKE_HISTORY_PUBKEY;
|
||||||
|
|
||||||
// === src/vote-account.js ===
|
// === src/vote-account.js ===
|
||||||
declare export var VOTE_ACCOUNT_KEY;
|
declare export var VOTE_PROGRAM_ID;
|
||||||
declare export type Lockout = {|
|
declare export type Lockout = {|
|
||||||
slot: number,
|
slot: number,
|
||||||
confirmationCount: number,
|
confirmationCount: number,
|
||||||
@ -277,6 +336,17 @@ declare module '@solana/web3.js' {
|
|||||||
static fromAccountData(buffer: Buffer): VoteAccount;
|
static fromAccountData(buffer: Buffer): VoteAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === src/instruction.js ===
|
||||||
|
declare export type InstructionType = {|
|
||||||
|
index: number,
|
||||||
|
layout: typeof BufferLayout,
|
||||||
|
|};
|
||||||
|
|
||||||
|
declare export function encodeData(
|
||||||
|
type: InstructionType,
|
||||||
|
fields: Object,
|
||||||
|
): Buffer;
|
||||||
|
|
||||||
// === src/transaction.js ===
|
// === src/transaction.js ===
|
||||||
declare export type TransactionSignature = string;
|
declare export type TransactionSignature = string;
|
||||||
|
|
||||||
|
21
web3.js/package-lock.json
generated
21
web3.js/package-lock.json
generated
@ -9692,6 +9692,27 @@
|
|||||||
"minimalistic-assert": "^1.0.1"
|
"minimalistic-assert": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hasha": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hasha/-/hasha-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-OFPDWmzPN1l7atOV1TgBVmNtBxaIysToK6Ve9DK+vT6pYuklw/nPNT+HJbZi0KDcI6vWB+9tgvZ5YD7fA3CXcA==",
|
||||||
|
"requires": {
|
||||||
|
"is-stream": "^2.0.0",
|
||||||
|
"type-fest": "^0.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"is-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw=="
|
||||||
|
},
|
||||||
|
"type-fest": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"hawk": {
|
"hawk": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
"bs58": "^4.0.1",
|
"bs58": "^4.0.1",
|
||||||
"buffer-layout": "^1.2.0",
|
"buffer-layout": "^1.2.0",
|
||||||
"esdoc-inject-style-plugin": "^1.0.0",
|
"esdoc-inject-style-plugin": "^1.0.0",
|
||||||
|
"hasha": "^5.1.0",
|
||||||
"jayson": "^3.0.1",
|
"jayson": "^3.0.1",
|
||||||
"mz": "^2.7.0",
|
"mz": "^2.7.0",
|
||||||
"node-fetch": "^2.2.0",
|
"node-fetch": "^2.2.0",
|
||||||
|
6
web3.js/src/config-program.js
Normal file
6
web3.js/src/config-program.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// @flow
|
||||||
|
import {PublicKey} from './publickey';
|
||||||
|
|
||||||
|
export const CONFIG_PROGRAM_ID = new PublicKey(
|
||||||
|
'Config1111111111111111111111111111111111111',
|
||||||
|
);
|
@ -2,21 +2,26 @@
|
|||||||
export {Account} from './account';
|
export {Account} from './account';
|
||||||
export {BpfLoader} from './bpf-loader';
|
export {BpfLoader} from './bpf-loader';
|
||||||
export {BudgetProgram} from './budget-program';
|
export {BudgetProgram} from './budget-program';
|
||||||
|
export {CONFIG_PROGRAM_ID} from './config-program';
|
||||||
export {Connection} from './connection';
|
export {Connection} from './connection';
|
||||||
export {Loader} from './loader';
|
export {Loader} from './loader';
|
||||||
export {PublicKey} from './publickey';
|
export {PublicKey} from './publickey';
|
||||||
|
export {StakeInstruction, StakeProgram} from './stake-program';
|
||||||
export {SystemInstruction, SystemProgram} from './system-program';
|
export {SystemInstruction, SystemProgram} from './system-program';
|
||||||
export {Transaction, TransactionInstruction} from './transaction';
|
export {Transaction, TransactionInstruction} from './transaction';
|
||||||
export {VALIDATOR_INFO_KEY, ValidatorInfo} from './validator-info';
|
export {VALIDATOR_INFO_KEY, ValidatorInfo} from './validator-info';
|
||||||
export {VOTE_ACCOUNT_KEY, VoteAccount} from './vote-account';
|
export {VOTE_PROGRAM_ID, VoteAccount} from './vote-account';
|
||||||
export {SYSVAR_RENT_PUBKEY} from './sysvar-rent';
|
export {
|
||||||
|
SYSVAR_CLOCK_PUBKEY,
|
||||||
|
SYSVAR_RENT_PUBKEY,
|
||||||
|
SYSVAR_REWARDS_PUBKEY,
|
||||||
|
SYSVAR_STAKE_HISTORY_PUBKEY,
|
||||||
|
} from './sysvar';
|
||||||
export {
|
export {
|
||||||
sendAndConfirmTransaction,
|
sendAndConfirmTransaction,
|
||||||
sendAndConfirmRecentTransaction,
|
sendAndConfirmRecentTransaction,
|
||||||
} from './util/send-and-confirm-transaction';
|
} from './util/send-and-confirm-transaction';
|
||||||
export {
|
export {sendAndConfirmRawTransaction} from './util/send-and-confirm-raw-transaction';
|
||||||
sendAndConfirmRawTransaction,
|
|
||||||
} from './util/send-and-confirm-raw-transaction';
|
|
||||||
export {testnetChannelEndpoint} from './util/testnet';
|
export {testnetChannelEndpoint} from './util/testnet';
|
||||||
|
|
||||||
// There are 1-billion lamports in one SOL
|
// There are 1-billion lamports in one SOL
|
||||||
|
27
web3.js/src/instruction.js
Normal file
27
web3.js/src/instruction.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as BufferLayout from 'buffer-layout';
|
||||||
|
|
||||||
|
import * as Layout from './layout';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} InstructionType
|
||||||
|
* @property (index} The Instruction index (from solana upstream program)
|
||||||
|
* @property (BufferLayout} The BufferLayout to use to build data
|
||||||
|
*/
|
||||||
|
export type InstructionType = {|
|
||||||
|
index: number,
|
||||||
|
layout: typeof BufferLayout,
|
||||||
|
|};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate a buffer of instruction data using an InstructionType
|
||||||
|
*/
|
||||||
|
export function encodeData(type: InstructionType, fields: Object): Buffer {
|
||||||
|
const allocLength =
|
||||||
|
type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields);
|
||||||
|
const data = Buffer.alloc(allocLength);
|
||||||
|
const layoutFields = Object.assign({instruction: type.index}, fields);
|
||||||
|
type.layout.encode(layoutFields, data);
|
||||||
|
return data;
|
||||||
|
}
|
@ -54,6 +54,26 @@ export const rustString = (property: string = 'string') => {
|
|||||||
return rsl;
|
return rsl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout for an Authorized object
|
||||||
|
*/
|
||||||
|
export const authorized = (property: string = 'authorized') => {
|
||||||
|
return BufferLayout.struct(
|
||||||
|
[publicKey('staker'), publicKey('withdrawer')],
|
||||||
|
property,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout for a Lockup object
|
||||||
|
*/
|
||||||
|
export const lockup = (property: string = 'lockup') => {
|
||||||
|
return BufferLayout.struct(
|
||||||
|
[BufferLayout.ns64('epoch'), publicKey('custodian')],
|
||||||
|
property,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function getAlloc(type: Object, fields: Object): number {
|
export function getAlloc(type: Object, fields: Object): number {
|
||||||
let alloc = 0;
|
let alloc = 0;
|
||||||
type.layout.fields.forEach(item => {
|
type.layout.fields.forEach(item => {
|
||||||
|
@ -6,7 +6,7 @@ import {Account} from './account';
|
|||||||
import {PublicKey} from './publickey';
|
import {PublicKey} from './publickey';
|
||||||
import {NUM_TICKS_PER_SECOND} from './timing';
|
import {NUM_TICKS_PER_SECOND} from './timing';
|
||||||
import {Transaction, PACKET_DATA_SIZE} from './transaction';
|
import {Transaction, PACKET_DATA_SIZE} from './transaction';
|
||||||
import {SYSVAR_RENT_PUBKEY} from './sysvar-rent';
|
import {SYSVAR_RENT_PUBKEY} from './sysvar';
|
||||||
import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction';
|
import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction';
|
||||||
import {sleep} from './util/sleep';
|
import {sleep} from './util/sleep';
|
||||||
import type {Connection} from './connection';
|
import type {Connection} from './connection';
|
||||||
|
@ -80,8 +80,16 @@ export class PublicKey {
|
|||||||
/**
|
/**
|
||||||
* Derive a public key from another key, a seed, and a programId.
|
* Derive a public key from another key, a seed, and a programId.
|
||||||
*/
|
*/
|
||||||
static createWithSeed(fromPublicKey: PublicKey, seed: string, programId: PublicKey): PublicKey {
|
static createWithSeed(
|
||||||
const buffer = Buffer.concat([fromPublicKey.toBuffer(), Buffer.from(seed), programId.toBuffer()])
|
fromPublicKey: PublicKey,
|
||||||
|
seed: string,
|
||||||
|
programId: PublicKey,
|
||||||
|
): PublicKey {
|
||||||
|
const buffer = Buffer.concat([
|
||||||
|
fromPublicKey.toBuffer(),
|
||||||
|
Buffer.from(seed),
|
||||||
|
programId.toBuffer(),
|
||||||
|
]);
|
||||||
const hash = hasha(buffer, {algorithm: 'sha256'});
|
const hash = hasha(buffer, {algorithm: 'sha256'});
|
||||||
return new PublicKey('0x' + hash);
|
return new PublicKey('0x' + hash);
|
||||||
}
|
}
|
||||||
|
395
web3.js/src/stake-program.js
Normal file
395
web3.js/src/stake-program.js
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
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';
|
||||||
|
import {PublicKey} from './publickey';
|
||||||
|
import {SystemProgram} from './system-program';
|
||||||
|
import {
|
||||||
|
SYSVAR_CLOCK_PUBKEY,
|
||||||
|
SYSVAR_RENT_PUBKEY,
|
||||||
|
SYSVAR_REWARDS_PUBKEY,
|
||||||
|
SYSVAR_STAKE_HISTORY_PUBKEY,
|
||||||
|
} from './sysvar';
|
||||||
|
import {Transaction, TransactionInstruction} from './transaction';
|
||||||
|
import type {TransactionInstructionCtorFields} from './transaction';
|
||||||
|
|
||||||
|
export class Authorized {
|
||||||
|
staker: PublicKey;
|
||||||
|
withdrawer: PublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Authorized object
|
||||||
|
*/
|
||||||
|
constructor(staker: PublicKey, withdrawer: PublicKey) {
|
||||||
|
this.staker = staker;
|
||||||
|
this.withdrawer = withdrawer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Lockup {
|
||||||
|
epoch: number;
|
||||||
|
custodian: PublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Authorized object
|
||||||
|
*/
|
||||||
|
constructor(epoch: number, custodian: PublicKey) {
|
||||||
|
this.epoch = epoch;
|
||||||
|
this.custodian = custodian;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stake Instruction class
|
||||||
|
*/
|
||||||
|
export class StakeInstruction extends TransactionInstruction {
|
||||||
|
/**
|
||||||
|
* Type of StakeInstruction
|
||||||
|
*/
|
||||||
|
type: InstructionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enumeration of valid StakeInstructionTypes
|
||||||
|
*/
|
||||||
|
const StakeInstructionLayout = Object.freeze({
|
||||||
|
Initialize: {
|
||||||
|
index: 0,
|
||||||
|
layout: BufferLayout.struct([
|
||||||
|
BufferLayout.u32('instruction'),
|
||||||
|
Layout.authorized(),
|
||||||
|
Layout.lockup(),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
Authorize: {
|
||||||
|
index: 1,
|
||||||
|
layout: BufferLayout.struct([
|
||||||
|
BufferLayout.u32('instruction'),
|
||||||
|
Layout.publicKey('newAuthorized'),
|
||||||
|
BufferLayout.u32('stakeAuthorizationType'),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
DelegateStake: {
|
||||||
|
index: 2,
|
||||||
|
layout: BufferLayout.struct([BufferLayout.u32('instruction')]),
|
||||||
|
},
|
||||||
|
RedeemVoteCredits: {
|
||||||
|
index: 3,
|
||||||
|
layout: BufferLayout.struct([BufferLayout.u32('instruction')]),
|
||||||
|
},
|
||||||
|
Split: {
|
||||||
|
index: 4,
|
||||||
|
layout: BufferLayout.struct([
|
||||||
|
BufferLayout.u32('instruction'),
|
||||||
|
BufferLayout.ns64('amount'),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
Withdraw: {
|
||||||
|
index: 5,
|
||||||
|
layout: BufferLayout.struct([
|
||||||
|
BufferLayout.u32('instruction'),
|
||||||
|
BufferLayout.ns64('amount'),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
Deactivate: {
|
||||||
|
index: 6,
|
||||||
|
layout: BufferLayout.struct([BufferLayout.u32('instruction')]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} StakeAuthorizationType
|
||||||
|
* @property (index} The Stake Authorization index (from solana-stake-program)
|
||||||
|
*/
|
||||||
|
export type StakeAuthorizationType = {|
|
||||||
|
index: number,
|
||||||
|
|};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enumeration of valid StakeInstructionTypes
|
||||||
|
*/
|
||||||
|
export const StakeAuthorizationLayout = Object.freeze({
|
||||||
|
Staker: {
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
Withdrawer: {
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
class RewardsPoolPublicKey extends PublicKey {
|
||||||
|
static get rewardsPoolBaseId(): PublicKey {
|
||||||
|
return new PublicKey('StakeRewards1111111111111111111111111111111');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Derive a public key from another key, a seed, and a programId.
|
||||||
|
*/
|
||||||
|
static randomId(): PublicKey {
|
||||||
|
const randomInt = Math.floor(Math.random() * (256 - 1));
|
||||||
|
let pubkey = this.rewardsPoolBaseId;
|
||||||
|
for (let i = 0; i < randomInt; i++) {
|
||||||
|
const buffer = pubkey.toBuffer();
|
||||||
|
const hash = hasha(buffer, {algorithm: 'sha256'});
|
||||||
|
return new PublicKey('0x' + hash);
|
||||||
|
}
|
||||||
|
return pubkey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class for transactions to interact with the Stake program
|
||||||
|
*/
|
||||||
|
export class StakeProgram {
|
||||||
|
/**
|
||||||
|
* Public key that identifies the Stake program
|
||||||
|
*/
|
||||||
|
static get programId(): PublicKey {
|
||||||
|
return new PublicKey('Stake11111111111111111111111111111111111111');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max space of a Stake account
|
||||||
|
*/
|
||||||
|
static get space(): number {
|
||||||
|
return 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an Initialize instruction to add to a Stake Create transaction
|
||||||
|
*/
|
||||||
|
static initialize(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorized: Authorized,
|
||||||
|
lockup: Lockup,
|
||||||
|
): TransactionInstruction {
|
||||||
|
const type = StakeInstructionLayout.Initialize;
|
||||||
|
const data = encodeData(type, {
|
||||||
|
authorized,
|
||||||
|
lockup,
|
||||||
|
});
|
||||||
|
const instructionData = {
|
||||||
|
keys: [
|
||||||
|
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
return new TransactionInstruction(instructionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that creates a new Stake account at
|
||||||
|
* an address generated with `from`, a seed, and the Stake programId
|
||||||
|
*/
|
||||||
|
static createAccountWithSeed(
|
||||||
|
from: PublicKey,
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
seed: string,
|
||||||
|
authorized: Authorized,
|
||||||
|
lockup: Lockup,
|
||||||
|
lamports: number,
|
||||||
|
): Transaction {
|
||||||
|
let transaction = SystemProgram.createAccountWithSeed(
|
||||||
|
from,
|
||||||
|
stakeAccount,
|
||||||
|
seed,
|
||||||
|
lamports,
|
||||||
|
this.space,
|
||||||
|
this.programId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return transaction.add(this.initialize(stakeAccount, authorized, lockup));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that creates a new Stake account
|
||||||
|
*/
|
||||||
|
static createAccount(
|
||||||
|
from: PublicKey,
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorized: Authorized,
|
||||||
|
lockup: Lockup,
|
||||||
|
lamports: number,
|
||||||
|
): Transaction {
|
||||||
|
let transaction = SystemProgram.createAccount(
|
||||||
|
from,
|
||||||
|
stakeAccount,
|
||||||
|
lamports,
|
||||||
|
this.space,
|
||||||
|
this.programId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return transaction.add(this.initialize(stakeAccount, authorized, lockup));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that delegates Stake tokens to a validator
|
||||||
|
* Vote PublicKey. This transaction can also be used to redelegate Stake
|
||||||
|
* to a new validator Vote PublicKey.
|
||||||
|
*/
|
||||||
|
static delegate(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
votePubkey: PublicKey,
|
||||||
|
): Transaction {
|
||||||
|
const type = StakeInstructionLayout.DelegateStake;
|
||||||
|
const data = encodeData(type);
|
||||||
|
|
||||||
|
return new Transaction().add({
|
||||||
|
keys: [
|
||||||
|
{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: authorizedPubkey, isSigner: true, isWritable: false},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that authorizes a new PublicKey as Staker
|
||||||
|
* or Withdrawer on the Stake account.
|
||||||
|
*/
|
||||||
|
static authorize(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
newAuthorized: PublicKey,
|
||||||
|
stakeAuthorizationType: StakeAuthorizationType,
|
||||||
|
): Transaction {
|
||||||
|
const type = StakeInstructionLayout.Authorize;
|
||||||
|
const data = encodeData(type, {
|
||||||
|
newAuthorized,
|
||||||
|
stakeAuthorizationType: stakeAuthorizationType.index,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Transaction().add({
|
||||||
|
keys: [
|
||||||
|
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that authorizes a new PublicKey as Staker
|
||||||
|
* or Withdrawer on the Stake account.
|
||||||
|
*/
|
||||||
|
static redeemVoteCredits(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
votePubkey: PublicKey,
|
||||||
|
): Transaction {
|
||||||
|
const type = StakeInstructionLayout.RedeemVoteCredits;
|
||||||
|
const data = encodeData(type);
|
||||||
|
|
||||||
|
return new Transaction().add({
|
||||||
|
keys: [
|
||||||
|
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: votePubkey, isSigner: false, isWritable: true},
|
||||||
|
{
|
||||||
|
pubkey: RewardsPoolPublicKey.randomId(),
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: true,
|
||||||
|
},
|
||||||
|
{pubkey: SYSVAR_REWARDS_PUBKEY, isSigner: false, isWritable: false},
|
||||||
|
{
|
||||||
|
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that splits Stake tokens into another stake account
|
||||||
|
*/
|
||||||
|
static split(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
lamports: number,
|
||||||
|
splitStakePubkey: PublicKey,
|
||||||
|
): Transaction {
|
||||||
|
let transaction = SystemProgram.createAccount(
|
||||||
|
stakeAccount,
|
||||||
|
splitStakePubkey,
|
||||||
|
0,
|
||||||
|
this.space,
|
||||||
|
this.programId,
|
||||||
|
);
|
||||||
|
const type = StakeInstructionLayout.Split;
|
||||||
|
const data = encodeData(type, {lamports});
|
||||||
|
|
||||||
|
return transaction.add({
|
||||||
|
keys: [
|
||||||
|
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: splitStakePubkey, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that withdraws deactivated Stake tokens.
|
||||||
|
*/
|
||||||
|
static withdraw(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
withdrawerPubkey: PublicKey,
|
||||||
|
to: PublicKey,
|
||||||
|
lamports: number,
|
||||||
|
): Transaction {
|
||||||
|
const type = StakeInstructionLayout.Withdraw;
|
||||||
|
const data = encodeData(type, {lamports});
|
||||||
|
|
||||||
|
return new Transaction().add({
|
||||||
|
keys: [
|
||||||
|
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: to, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false},
|
||||||
|
{
|
||||||
|
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
|
||||||
|
isSigner: false,
|
||||||
|
isWritable: false,
|
||||||
|
},
|
||||||
|
{pubkey: withdrawerPubkey, isSigner: true, isWritable: false},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Transaction that deactivates Stake tokens.
|
||||||
|
*/
|
||||||
|
static deactivate(
|
||||||
|
stakeAccount: PublicKey,
|
||||||
|
authorizedPubkey: PublicKey,
|
||||||
|
): Transaction {
|
||||||
|
const type = StakeInstructionLayout.Deactivate;
|
||||||
|
const data = encodeData(type);
|
||||||
|
|
||||||
|
return new Transaction().add({
|
||||||
|
keys: [
|
||||||
|
{pubkey: stakeAccount, isSigner: false, isWritable: true},
|
||||||
|
{pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false},
|
||||||
|
{pubkey: authorizedPubkey, isSigner: true, isWritable: false},
|
||||||
|
],
|
||||||
|
programId: this.programId,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
import * as BufferLayout from 'buffer-layout';
|
import * as BufferLayout from 'buffer-layout';
|
||||||
|
|
||||||
import {Transaction, TransactionInstruction} from './transaction';
|
import {encodeData} from './instruction';
|
||||||
import {PublicKey} from './publickey';
|
import type {InstructionType} from './instruction';
|
||||||
import * as Layout from './layout';
|
import * as Layout from './layout';
|
||||||
|
import {PublicKey} from './publickey';
|
||||||
|
import {Transaction, TransactionInstruction} from './transaction';
|
||||||
import type {TransactionInstructionCtorFields} from './transaction';
|
import type {TransactionInstructionCtorFields} from './transaction';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,12 +16,9 @@ export class SystemInstruction extends TransactionInstruction {
|
|||||||
/**
|
/**
|
||||||
* Type of SystemInstruction
|
* Type of SystemInstruction
|
||||||
*/
|
*/
|
||||||
type: SystemInstructionType;
|
type: InstructionType;
|
||||||
|
|
||||||
constructor(
|
constructor(opts?: TransactionInstructionCtorFields, type?: InstructionType) {
|
||||||
opts?: TransactionInstructionCtorFields,
|
|
||||||
type?: SystemInstructionType,
|
|
||||||
) {
|
|
||||||
if (
|
if (
|
||||||
opts &&
|
opts &&
|
||||||
opts.programId &&
|
opts.programId &&
|
||||||
@ -107,16 +106,6 @@ export class SystemInstruction extends TransactionInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} SystemInstructionType
|
|
||||||
* @property (index} The System Instruction index (from solana-sdk)
|
|
||||||
* @property (BufferLayout} The BufferLayout to use to build data
|
|
||||||
*/
|
|
||||||
type SystemInstructionType = {|
|
|
||||||
index: number,
|
|
||||||
layout: typeof BufferLayout,
|
|
||||||
|};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enumeration of valid SystemInstructionTypes
|
* An enumeration of valid SystemInstructionTypes
|
||||||
*/
|
*/
|
||||||
@ -157,18 +146,6 @@ const SystemInstructionLayout = Object.freeze({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate a buffer of instruction data using the SystemInstructionType
|
|
||||||
*/
|
|
||||||
function encodeData(type: SystemInstructionType, fields: Object): Buffer {
|
|
||||||
const allocLength =
|
|
||||||
type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields);
|
|
||||||
const data = Buffer.alloc(allocLength);
|
|
||||||
const layoutFields = Object.assign({instruction: type.index}, fields);
|
|
||||||
type.layout.encode(layoutFields, data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory class for transactions to interact with the System program
|
* Factory class for transactions to interact with the System program
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import {PublicKey} from './publickey';
|
|
||||||
|
|
||||||
export const SYSVAR_RENT_PUBKEY = new PublicKey(
|
|
||||||
'SysvarRent111111111111111111111111111111111',
|
|
||||||
);
|
|
18
web3.js/src/sysvar.js
Normal file
18
web3.js/src/sysvar.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
import {PublicKey} from './publickey';
|
||||||
|
|
||||||
|
export const SYSVAR_CLOCK_PUBKEY = new PublicKey(
|
||||||
|
'SysvarC1ock11111111111111111111111111111111',
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SYSVAR_RENT_PUBKEY = new PublicKey(
|
||||||
|
'SysvarRent111111111111111111111111111111111',
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SYSVAR_REWARDS_PUBKEY = new PublicKey(
|
||||||
|
'SysvarRewards111111111111111111111111111111',
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey(
|
||||||
|
'SysvarStakeHistory1111111111111111111111111',
|
||||||
|
);
|
@ -4,7 +4,7 @@ import * as BufferLayout from 'buffer-layout';
|
|||||||
import * as Layout from './layout';
|
import * as Layout from './layout';
|
||||||
import {PublicKey} from './publickey';
|
import {PublicKey} from './publickey';
|
||||||
|
|
||||||
export const VOTE_ACCOUNT_KEY = new PublicKey(
|
export const VOTE_PROGRAM_ID = new PublicKey(
|
||||||
'Vote111111111111111111111111111111111111111',
|
'Vote111111111111111111111111111111111111111',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -259,7 +259,15 @@ test('createWithSeed', () => {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
]);
|
]);
|
||||||
const derivedKey = PublicKey.createWithSeed(defaultPublicKey, 'limber chicken: 4/45', defaultPublicKey);
|
const derivedKey = PublicKey.createWithSeed(
|
||||||
|
defaultPublicKey,
|
||||||
|
'limber chicken: 4/45',
|
||||||
|
defaultPublicKey,
|
||||||
|
);
|
||||||
|
|
||||||
expect(derivedKey.equals(new PublicKey('9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq'))).toBe(true);
|
expect(
|
||||||
|
derivedKey.equals(
|
||||||
|
new PublicKey('9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq'),
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user