Viewing File: /home/ubuntu/efiexchange-node-base/node_modules/@solana/web3.js/lib/index.cjs.js
'use strict';
var buffer = require('buffer');
var ed25519 = require('@noble/curves/ed25519');
var BN = require('bn.js');
var bs58 = require('bs58');
var sha256 = require('@noble/hashes/sha256');
var borsh = require('borsh');
var BufferLayout = require('@solana/buffer-layout');
var codecsNumbers = require('@solana/codecs-numbers');
var require$$0 = require('util');
var require$$0$1 = require('http');
var require$$0$2 = require('https');
var superstruct = require('superstruct');
var RpcClient = require('jayson/lib/client/browser');
var nodeFetch = require('node-fetch');
var rpcWebsockets = require('rpc-websockets');
var sha3 = require('@noble/hashes/sha3');
var secp256k1 = require('@noble/curves/secp256k1');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
function _interopNamespaceCompat(e) {
if (e && typeof e === 'object' && 'default' in e) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var BN__default = /*#__PURE__*/_interopDefaultCompat(BN);
var bs58__default = /*#__PURE__*/_interopDefaultCompat(bs58);
var BufferLayout__namespace = /*#__PURE__*/_interopNamespaceCompat(BufferLayout);
var require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
var require$$0__default$1 = /*#__PURE__*/_interopDefaultCompat(require$$0$1);
var require$$0__default$2 = /*#__PURE__*/_interopDefaultCompat(require$$0$2);
var RpcClient__default = /*#__PURE__*/_interopDefaultCompat(RpcClient);
var nodeFetch__namespace = /*#__PURE__*/_interopNamespaceCompat(nodeFetch);
/**
* A 64 byte secret key, the first 32 bytes of which is the
* private scalar and the last 32 bytes is the public key.
* Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/
*/
/**
* Ed25519 Keypair
*/
const generatePrivateKey = ed25519.ed25519.utils.randomPrivateKey;
const generateKeypair = () => {
const privateScalar = ed25519.ed25519.utils.randomPrivateKey();
const publicKey = getPublicKey(privateScalar);
const secretKey = new Uint8Array(64);
secretKey.set(privateScalar);
secretKey.set(publicKey, 32);
return {
publicKey,
secretKey
};
};
const getPublicKey = ed25519.ed25519.getPublicKey;
function isOnCurve(publicKey) {
try {
ed25519.ed25519.ExtendedPoint.fromHex(publicKey);
return true;
} catch {
return false;
}
}
const sign = (message, secretKey) => ed25519.ed25519.sign(message, secretKey.slice(0, 32));
const verify = ed25519.ed25519.verify;
const toBuffer = arr => {
if (buffer.Buffer.isBuffer(arr)) {
return arr;
} else if (arr instanceof Uint8Array) {
return buffer.Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
} else {
return buffer.Buffer.from(arr);
}
};
// Class wrapping a plain object
class Struct {
constructor(properties) {
Object.assign(this, properties);
}
encode() {
return buffer.Buffer.from(borsh.serialize(SOLANA_SCHEMA, this));
}
static decode(data) {
return borsh.deserialize(SOLANA_SCHEMA, this, data);
}
static decodeUnchecked(data) {
return borsh.deserializeUnchecked(SOLANA_SCHEMA, this, data);
}
}
// Class representing a Rust-compatible enum, since enums are only strings or
// numbers in pure JS
class Enum extends Struct {
constructor(properties) {
super(properties);
this.enum = '';
if (Object.keys(properties).length !== 1) {
throw new Error('Enum can only take single value');
}
Object.keys(properties).map(key => {
this.enum = key;
});
}
}
const SOLANA_SCHEMA = new Map();
var _PublicKey;
/**
* Maximum length of derived pubkey seed
*/
const MAX_SEED_LENGTH = 32;
/**
* Size of public key in bytes
*/
const PUBLIC_KEY_LENGTH = 32;
/**
* Value to be converted into public key
*/
/**
* JSON object representation of PublicKey class
*/
function isPublicKeyData(value) {
return value._bn !== undefined;
}
// local counter used by PublicKey.unique()
let uniquePublicKeyCounter = 1;
/**
* A public key
*/
class PublicKey extends Struct {
/**
* Create a new PublicKey object
* @param value ed25519 public key as buffer or base-58 encoded string
*/
constructor(value) {
super({});
/** @internal */
this._bn = void 0;
if (isPublicKeyData(value)) {
this._bn = value._bn;
} else {
if (typeof value === 'string') {
// assume base 58 encoding by default
const decoded = bs58__default.default.decode(value);
if (decoded.length != PUBLIC_KEY_LENGTH) {
throw new Error(`Invalid public key input`);
}
this._bn = new BN__default.default(decoded);
} else {
this._bn = new BN__default.default(value);
}
if (this._bn.byteLength() > PUBLIC_KEY_LENGTH) {
throw new Error(`Invalid public key input`);
}
}
}
/**
* Returns a unique PublicKey for tests and benchmarks using a counter
*/
static unique() {
const key = new PublicKey(uniquePublicKeyCounter);
uniquePublicKeyCounter += 1;
return new PublicKey(key.toBuffer());
}
/**
* Default public key value. The base58-encoded string representation is all ones (as seen below)
* The underlying BN number is 32 bytes that are all zeros
*/
/**
* Checks if two publicKeys are equal
*/
equals(publicKey) {
return this._bn.eq(publicKey._bn);
}
/**
* Return the base-58 representation of the public key
*/
toBase58() {
return bs58__default.default.encode(this.toBytes());
}
toJSON() {
return this.toBase58();
}
/**
* Return the byte array representation of the public key in big endian
*/
toBytes() {
const buf = this.toBuffer();
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
}
/**
* Return the Buffer representation of the public key in big endian
*/
toBuffer() {
const b = this._bn.toArrayLike(buffer.Buffer);
if (b.length === PUBLIC_KEY_LENGTH) {
return b;
}
const zeroPad = buffer.Buffer.alloc(32);
b.copy(zeroPad, 32 - b.length);
return zeroPad;
}
get [Symbol.toStringTag]() {
return `PublicKey(${this.toString()})`;
}
/**
* Return the base-58 representation of the public key
*/
toString() {
return this.toBase58();
}
/**
* Derive a public key from another key, a seed, and a program ID.
* The program ID will also serve as the owner of the public key, giving
* it permission to write data to the account.
*/
/* eslint-disable require-await */
static async createWithSeed(fromPublicKey, seed, programId) {
const buffer$1 = buffer.Buffer.concat([fromPublicKey.toBuffer(), buffer.Buffer.from(seed), programId.toBuffer()]);
const publicKeyBytes = sha256.sha256(buffer$1);
return new PublicKey(publicKeyBytes);
}
/**
* Derive a program address from seeds and a program ID.
*/
/* eslint-disable require-await */
static createProgramAddressSync(seeds, programId) {
let buffer$1 = buffer.Buffer.alloc(0);
seeds.forEach(function (seed) {
if (seed.length > MAX_SEED_LENGTH) {
throw new TypeError(`Max seed length exceeded`);
}
buffer$1 = buffer.Buffer.concat([buffer$1, toBuffer(seed)]);
});
buffer$1 = buffer.Buffer.concat([buffer$1, programId.toBuffer(), buffer.Buffer.from('ProgramDerivedAddress')]);
const publicKeyBytes = sha256.sha256(buffer$1);
if (isOnCurve(publicKeyBytes)) {
throw new Error(`Invalid seeds, address must fall off the curve`);
}
return new PublicKey(publicKeyBytes);
}
/**
* Async version of createProgramAddressSync
* For backwards compatibility
*
* @deprecated Use {@link createProgramAddressSync} instead
*/
/* eslint-disable require-await */
static async createProgramAddress(seeds, programId) {
return this.createProgramAddressSync(seeds, programId);
}
/**
* Find a valid program address
*
* Valid program addresses must fall off the ed25519 curve. This function
* iterates a nonce until it finds one that when combined with the seeds
* results in a valid program address.
*/
static findProgramAddressSync(seeds, programId) {
let nonce = 255;
let address;
while (nonce != 0) {
try {
const seedsWithNonce = seeds.concat(buffer.Buffer.from([nonce]));
address = this.createProgramAddressSync(seedsWithNonce, programId);
} catch (err) {
if (err instanceof TypeError) {
throw err;
}
nonce--;
continue;
}
return [address, nonce];
}
throw new Error(`Unable to find a viable program address nonce`);
}
/**
* Async version of findProgramAddressSync
* For backwards compatibility
*
* @deprecated Use {@link findProgramAddressSync} instead
*/
static async findProgramAddress(seeds, programId) {
return this.findProgramAddressSync(seeds, programId);
}
/**
* Check that a pubkey is on the ed25519 curve.
*/
static isOnCurve(pubkeyData) {
const pubkey = new PublicKey(pubkeyData);
return isOnCurve(pubkey.toBytes());
}
}
_PublicKey = PublicKey;
PublicKey.default = new _PublicKey('11111111111111111111111111111111');
SOLANA_SCHEMA.set(PublicKey, {
kind: 'struct',
fields: [['_bn', 'u256']]
});
/**
* An account key pair (public and secret keys).
*
* @deprecated since v1.10.0, please use {@link Keypair} instead.
*/
class Account {
/**
* Create a new Account object
*
* If the secretKey parameter is not provided a new key pair is randomly
* created for the account
*
* @param secretKey Secret key for the account
*/
constructor(secretKey) {
/** @internal */
this._publicKey = void 0;
/** @internal */
this._secretKey = void 0;
if (secretKey) {
const secretKeyBuffer = toBuffer(secretKey);
if (secretKey.length !== 64) {
throw new Error('bad secret key size');
}
this._publicKey = secretKeyBuffer.slice(32, 64);
this._secretKey = secretKeyBuffer.slice(0, 32);
} else {
this._secretKey = toBuffer(generatePrivateKey());
this._publicKey = toBuffer(getPublicKey(this._secretKey));
}
}
/**
* The public key for this account
*/
get publicKey() {
return new PublicKey(this._publicKey);
}
/**
* The **unencrypted** secret key for this account. The first 32 bytes
* is the private scalar and the last 32 bytes is the public key.
* Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/
*/
get secretKey() {
return buffer.Buffer.concat([this._secretKey, this._publicKey], 64);
}
}
const BPF_LOADER_DEPRECATED_PROGRAM_ID = new PublicKey('BPFLoader1111111111111111111111111111111111');
/**
* Maximum over-the-wire size of a Transaction
*
* 1280 is IPv6 minimum MTU
* 40 bytes is the size of the IPv6 header
* 8 bytes is the size of the fragment header
*/
const PACKET_DATA_SIZE = 1280 - 40 - 8;
const VERSION_PREFIX_MASK = 0x7f;
const SIGNATURE_LENGTH_IN_BYTES = 64;
class TransactionExpiredBlockheightExceededError extends Error {
constructor(signature) {
super(`Signature ${signature} has expired: block height exceeded.`);
this.signature = void 0;
this.signature = signature;
}
}
Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
value: 'TransactionExpiredBlockheightExceededError'
});
class TransactionExpiredTimeoutError extends Error {
constructor(signature, timeoutSeconds) {
super(`Transaction was not confirmed in ${timeoutSeconds.toFixed(2)} seconds. It is ` + 'unknown if it succeeded or failed. Check signature ' + `${signature} using the Solana Explorer or CLI tools.`);
this.signature = void 0;
this.signature = signature;
}
}
Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
value: 'TransactionExpiredTimeoutError'
});
class TransactionExpiredNonceInvalidError extends Error {
constructor(signature) {
super(`Signature ${signature} has expired: the nonce is no longer valid.`);
this.signature = void 0;
this.signature = signature;
}
}
Object.defineProperty(TransactionExpiredNonceInvalidError.prototype, 'name', {
value: 'TransactionExpiredNonceInvalidError'
});
class MessageAccountKeys {
constructor(staticAccountKeys, accountKeysFromLookups) {
this.staticAccountKeys = void 0;
this.accountKeysFromLookups = void 0;
this.staticAccountKeys = staticAccountKeys;
this.accountKeysFromLookups = accountKeysFromLookups;
}
keySegments() {
const keySegments = [this.staticAccountKeys];
if (this.accountKeysFromLookups) {
keySegments.push(this.accountKeysFromLookups.writable);
keySegments.push(this.accountKeysFromLookups.readonly);
}
return keySegments;
}
get(index) {
for (const keySegment of this.keySegments()) {
if (index < keySegment.length) {
return keySegment[index];
} else {
index -= keySegment.length;
}
}
return;
}
get length() {
return this.keySegments().flat().length;
}
compileInstructions(instructions) {
// Bail early if any account indexes would overflow a u8
const U8_MAX = 255;
if (this.length > U8_MAX + 1) {
throw new Error('Account index overflow encountered during compilation');
}
const keyIndexMap = new Map();
this.keySegments().flat().forEach((key, index) => {
keyIndexMap.set(key.toBase58(), index);
});
const findKeyIndex = key => {
const keyIndex = keyIndexMap.get(key.toBase58());
if (keyIndex === undefined) throw new Error('Encountered an unknown instruction account key during compilation');
return keyIndex;
};
return instructions.map(instruction => {
return {
programIdIndex: findKeyIndex(instruction.programId),
accountKeyIndexes: instruction.keys.map(meta => findKeyIndex(meta.pubkey)),
data: instruction.data
};
});
}
}
/**
* Layout for a public key
*/
const publicKey = (property = 'publicKey') => {
return BufferLayout__namespace.blob(32, property);
};
/**
* Layout for a signature
*/
const signature = (property = 'signature') => {
return BufferLayout__namespace.blob(64, property);
};
/**
* Layout for a Rust String type
*/
const rustString = (property = 'string') => {
const rsl = BufferLayout__namespace.struct([BufferLayout__namespace.u32('length'), BufferLayout__namespace.u32('lengthPadding'), BufferLayout__namespace.blob(BufferLayout__namespace.offset(BufferLayout__namespace.u32(), -8), 'chars')], property);
const _decode = rsl.decode.bind(rsl);
const _encode = rsl.encode.bind(rsl);
const rslShim = rsl;
rslShim.decode = (b, offset) => {
const data = _decode(b, offset);
return data['chars'].toString();
};
rslShim.encode = (str, b, offset) => {
const data = {
chars: buffer.Buffer.from(str, 'utf8')
};
return _encode(data, b, offset);
};
rslShim.alloc = str => {
return BufferLayout__namespace.u32().span + BufferLayout__namespace.u32().span + buffer.Buffer.from(str, 'utf8').length;
};
return rslShim;
};
/**
* Layout for an Authorized object
*/
const authorized = (property = 'authorized') => {
return BufferLayout__namespace.struct([publicKey('staker'), publicKey('withdrawer')], property);
};
/**
* Layout for a Lockup object
*/
const lockup = (property = 'lockup') => {
return BufferLayout__namespace.struct([BufferLayout__namespace.ns64('unixTimestamp'), BufferLayout__namespace.ns64('epoch'), publicKey('custodian')], property);
};
/**
* Layout for a VoteInit object
*/
const voteInit = (property = 'voteInit') => {
return BufferLayout__namespace.struct([publicKey('nodePubkey'), publicKey('authorizedVoter'), publicKey('authorizedWithdrawer'), BufferLayout__namespace.u8('commission')], property);
};
/**
* Layout for a VoteAuthorizeWithSeedArgs object
*/
const voteAuthorizeWithSeedArgs = (property = 'voteAuthorizeWithSeedArgs') => {
return BufferLayout__namespace.struct([BufferLayout__namespace.u32('voteAuthorizationType'), publicKey('currentAuthorityDerivedKeyOwnerPubkey'), rustString('currentAuthorityDerivedKeySeed'), publicKey('newAuthorized')], property);
};
function getAlloc(type, fields) {
const getItemAlloc = item => {
if (item.span >= 0) {
return item.span;
} else if (typeof item.alloc === 'function') {
return item.alloc(fields[item.property]);
} else if ('count' in item && 'elementLayout' in item) {
const field = fields[item.property];
if (Array.isArray(field)) {
return field.length * getItemAlloc(item.elementLayout);
}
} else if ('fields' in item) {
// This is a `Structure` whose size needs to be recursively measured.
return getAlloc({
layout: item
}, fields[item.property]);
}
// Couldn't determine allocated size of layout
return 0;
};
let alloc = 0;
type.layout.fields.forEach(item => {
alloc += getItemAlloc(item);
});
return alloc;
}
function decodeLength(bytes) {
let len = 0;
let size = 0;
for (;;) {
let elem = bytes.shift();
len |= (elem & 0x7f) << size * 7;
size += 1;
if ((elem & 0x80) === 0) {
break;
}
}
return len;
}
function encodeLength(bytes, len) {
let rem_len = len;
for (;;) {
let elem = rem_len & 0x7f;
rem_len >>= 7;
if (rem_len == 0) {
bytes.push(elem);
break;
} else {
elem |= 0x80;
bytes.push(elem);
}
}
}
function assert (condition, message) {
if (!condition) {
throw new Error(message || 'Assertion failed');
}
}
class CompiledKeys {
constructor(payer, keyMetaMap) {
this.payer = void 0;
this.keyMetaMap = void 0;
this.payer = payer;
this.keyMetaMap = keyMetaMap;
}
static compile(instructions, payer) {
const keyMetaMap = new Map();
const getOrInsertDefault = pubkey => {
const address = pubkey.toBase58();
let keyMeta = keyMetaMap.get(address);
if (keyMeta === undefined) {
keyMeta = {
isSigner: false,
isWritable: false,
isInvoked: false
};
keyMetaMap.set(address, keyMeta);
}
return keyMeta;
};
const payerKeyMeta = getOrInsertDefault(payer);
payerKeyMeta.isSigner = true;
payerKeyMeta.isWritable = true;
for (const ix of instructions) {
getOrInsertDefault(ix.programId).isInvoked = true;
for (const accountMeta of ix.keys) {
const keyMeta = getOrInsertDefault(accountMeta.pubkey);
keyMeta.isSigner ||= accountMeta.isSigner;
keyMeta.isWritable ||= accountMeta.isWritable;
}
}
return new CompiledKeys(payer, keyMetaMap);
}
getMessageComponents() {
const mapEntries = [...this.keyMetaMap.entries()];
assert(mapEntries.length <= 256, 'Max static account keys length exceeded');
const writableSigners = mapEntries.filter(([, meta]) => meta.isSigner && meta.isWritable);
const readonlySigners = mapEntries.filter(([, meta]) => meta.isSigner && !meta.isWritable);
const writableNonSigners = mapEntries.filter(([, meta]) => !meta.isSigner && meta.isWritable);
const readonlyNonSigners = mapEntries.filter(([, meta]) => !meta.isSigner && !meta.isWritable);
const header = {
numRequiredSignatures: writableSigners.length + readonlySigners.length,
numReadonlySignedAccounts: readonlySigners.length,
numReadonlyUnsignedAccounts: readonlyNonSigners.length
};
// sanity checks
{
assert(writableSigners.length > 0, 'Expected at least one writable signer key');
const [payerAddress] = writableSigners[0];
assert(payerAddress === this.payer.toBase58(), 'Expected first writable signer key to be the fee payer');
}
const staticAccountKeys = [...writableSigners.map(([address]) => new PublicKey(address)), ...readonlySigners.map(([address]) => new PublicKey(address)), ...writableNonSigners.map(([address]) => new PublicKey(address)), ...readonlyNonSigners.map(([address]) => new PublicKey(address))];
return [header, staticAccountKeys];
}
extractTableLookup(lookupTable) {
const [writableIndexes, drainedWritableKeys] = this.drainKeysFoundInLookupTable(lookupTable.state.addresses, keyMeta => !keyMeta.isSigner && !keyMeta.isInvoked && keyMeta.isWritable);
const [readonlyIndexes, drainedReadonlyKeys] = this.drainKeysFoundInLookupTable(lookupTable.state.addresses, keyMeta => !keyMeta.isSigner && !keyMeta.isInvoked && !keyMeta.isWritable);
// Don't extract lookup if no keys were found
if (writableIndexes.length === 0 && readonlyIndexes.length === 0) {
return;
}
return [{
accountKey: lookupTable.key,
writableIndexes,
readonlyIndexes
}, {
writable: drainedWritableKeys,
readonly: drainedReadonlyKeys
}];
}
/** @internal */
drainKeysFoundInLookupTable(lookupTableEntries, keyMetaFilter) {
const lookupTableIndexes = new Array();
const drainedKeys = new Array();
for (const [address, keyMeta] of this.keyMetaMap.entries()) {
if (keyMetaFilter(keyMeta)) {
const key = new PublicKey(address);
const lookupTableIndex = lookupTableEntries.findIndex(entry => entry.equals(key));
if (lookupTableIndex >= 0) {
assert(lookupTableIndex < 256, 'Max lookup table index exceeded');
lookupTableIndexes.push(lookupTableIndex);
drainedKeys.push(key);
this.keyMetaMap.delete(address);
}
}
}
return [lookupTableIndexes, drainedKeys];
}
}
const END_OF_BUFFER_ERROR_MESSAGE = 'Reached end of buffer unexpectedly';
/**
* Delegates to `Array#shift`, but throws if the array is zero-length.
*/
function guardedShift(byteArray) {
if (byteArray.length === 0) {
throw new Error(END_OF_BUFFER_ERROR_MESSAGE);
}
return byteArray.shift();
}
/**
* Delegates to `Array#splice`, but throws if the section being spliced out extends past the end of
* the array.
*/
function guardedSplice(byteArray, ...args) {
const [start] = args;
if (args.length === 2 // Implies that `deleteCount` was supplied
? start + (args[1] ?? 0) > byteArray.length : start >= byteArray.length) {
throw new Error(END_OF_BUFFER_ERROR_MESSAGE);
}
return byteArray.splice(...args);
}
/**
* An instruction to execute by a program
*
* @property {number} programIdIndex
* @property {number[]} accounts
* @property {string} data
*/
/**
* Message constructor arguments
*/
/**
* List of instructions to be processed atomically
*/
class Message {
constructor(args) {
this.header = void 0;
this.accountKeys = void 0;
this.recentBlockhash = void 0;
this.instructions = void 0;
this.indexToProgramIds = new Map();
this.header = args.header;
this.accountKeys = args.accountKeys.map(account => new PublicKey(account));
this.recentBlockhash = args.recentBlockhash;
this.instructions = args.instructions;
this.instructions.forEach(ix => this.indexToProgramIds.set(ix.programIdIndex, this.accountKeys[ix.programIdIndex]));
}
get version() {
return 'legacy';
}
get staticAccountKeys() {
return this.accountKeys;
}
get compiledInstructions() {
return this.instructions.map(ix => ({
programIdIndex: ix.programIdIndex,
accountKeyIndexes: ix.accounts,
data: bs58__default.default.decode(ix.data)
}));
}
get addressTableLookups() {
return [];
}
getAccountKeys() {
return new MessageAccountKeys(this.staticAccountKeys);
}
static compile(args) {
const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey);
const [header, staticAccountKeys] = compiledKeys.getMessageComponents();
const accountKeys = new MessageAccountKeys(staticAccountKeys);
const instructions = accountKeys.compileInstructions(args.instructions).map(ix => ({
programIdIndex: ix.programIdIndex,
accounts: ix.accountKeyIndexes,
data: bs58__default.default.encode(ix.data)
}));
return new Message({
header,
accountKeys: staticAccountKeys,
recentBlockhash: args.recentBlockhash,
instructions
});
}
isAccountSigner(index) {
return index < this.header.numRequiredSignatures;
}
isAccountWritable(index) {
const numSignedAccounts = this.header.numRequiredSignatures;
if (index >= this.header.numRequiredSignatures) {
const unsignedAccountIndex = index - numSignedAccounts;
const numUnsignedAccounts = this.accountKeys.length - numSignedAccounts;
const numWritableUnsignedAccounts = numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts;
return unsignedAccountIndex < numWritableUnsignedAccounts;
} else {
const numWritableSignedAccounts = numSignedAccounts - this.header.numReadonlySignedAccounts;
return index < numWritableSignedAccounts;
}
}
isProgramId(index) {
return this.indexToProgramIds.has(index);
}
programIds() {
return [...this.indexToProgramIds.values()];
}
nonProgramIds() {
return this.accountKeys.filter((_, index) => !this.isProgramId(index));
}
serialize() {
const numKeys = this.accountKeys.length;
let keyCount = [];
encodeLength(keyCount, numKeys);
const instructions = this.instructions.map(instruction => {
const {
accounts,
programIdIndex
} = instruction;
const data = Array.from(bs58__default.default.decode(instruction.data));
let keyIndicesCount = [];
encodeLength(keyIndicesCount, accounts.length);
let dataCount = [];
encodeLength(dataCount, data.length);
return {
programIdIndex,
keyIndicesCount: buffer.Buffer.from(keyIndicesCount),
keyIndices: accounts,
dataLength: buffer.Buffer.from(dataCount),
data
};
});
let instructionCount = [];
encodeLength(instructionCount, instructions.length);
let instructionBuffer = buffer.Buffer.alloc(PACKET_DATA_SIZE);
buffer.Buffer.from(instructionCount).copy(instructionBuffer);
let instructionBufferLength = instructionCount.length;
instructions.forEach(instruction => {
const instructionLayout = BufferLayout__namespace.struct([BufferLayout__namespace.u8('programIdIndex'), BufferLayout__namespace.blob(instruction.keyIndicesCount.length, 'keyIndicesCount'), BufferLayout__namespace.seq(BufferLayout__namespace.u8('keyIndex'), instruction.keyIndices.length, 'keyIndices'), BufferLayout__namespace.blob(instruction.dataLength.length, 'dataLength'), BufferLayout__namespace.seq(BufferLayout__namespace.u8('userdatum'), instruction.data.length, 'data')]);
const length = instructionLayout.encode(instruction, instructionBuffer, instructionBufferLength);
instructionBufferLength += length;
});
instructionBuffer = instructionBuffer.slice(0, instructionBufferLength);
const signDataLayout = BufferLayout__namespace.struct([BufferLayout__namespace.blob(1, 'numRequiredSignatures'), BufferLayout__namespace.blob(1, 'numReadonlySignedAccounts'), BufferLayout__namespace.blob(1, 'numReadonlyUnsignedAccounts'), BufferLayout__namespace.blob(keyCount.length, 'keyCount'), BufferLayout__namespace.seq(publicKey('key'), numKeys, 'keys'), publicKey('recentBlockhash')]);
const transaction = {
numRequiredSignatures: buffer.Buffer.from([this.header.numRequiredSignatures]),
numReadonlySignedAccounts: buffer.Buffer.from([this.header.numReadonlySignedAccounts]),
numReadonlyUnsignedAccounts: buffer.Buffer.from([this.header.numReadonlyUnsignedAccounts]),
keyCount: buffer.Buffer.from(keyCount),
keys: this.accountKeys.map(key => toBuffer(key.toBytes())),
recentBlockhash: bs58__default.default.decode(this.recentBlockhash)
};
let signData = buffer.Buffer.alloc(2048);
const length = signDataLayout.encode(transaction, signData);
instructionBuffer.copy(signData, length);
return signData.slice(0, length + instructionBuffer.length);
}
/**
* Decode a compiled message into a Message object.
*/
static from(buffer$1) {
// Slice up wire data
let byteArray = [...buffer$1];
const numRequiredSignatures = guardedShift(byteArray);
if (numRequiredSignatures !== (numRequiredSignatures & VERSION_PREFIX_MASK)) {
throw new Error('Versioned messages must be deserialized with VersionedMessage.deserialize()');
}
const numReadonlySignedAccounts = guardedShift(byteArray);
const numReadonlyUnsignedAccounts = guardedShift(byteArray);
const accountCount = decodeLength(byteArray);
let accountKeys = [];
for (let i = 0; i < accountCount; i++) {
const account = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH);
accountKeys.push(new PublicKey(buffer.Buffer.from(account)));
}
const recentBlockhash = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH);
const instructionCount = decodeLength(byteArray);
let instructions = [];
for (let i = 0; i < instructionCount; i++) {
const programIdIndex = guardedShift(byteArray);
const accountCount = decodeLength(byteArray);
const accounts = guardedSplice(byteArray, 0, accountCount);
const dataLength = decodeLength(byteArray);
const dataSlice = guardedSplice(byteArray, 0, dataLength);
const data = bs58__default.default.encode(buffer.Buffer.from(dataSlice));
instructions.push({
programIdIndex,
accounts,
data
});
}
const messageArgs = {
header: {
numRequiredSignatures,
numReadonlySignedAccounts,
numReadonlyUnsignedAccounts
},
recentBlockhash: bs58__default.default.encode(buffer.Buffer.from(recentBlockhash)),
accountKeys,
instructions
};
return new Message(messageArgs);
}
}
/**
* Message constructor arguments
*/
class MessageV0 {
constructor(args) {
this.header = void 0;
this.staticAccountKeys = void 0;
this.recentBlockhash = void 0;
this.compiledInstructions = void 0;
this.addressTableLookups = void 0;
this.header = args.header;
this.staticAccountKeys = args.staticAccountKeys;
this.recentBlockhash = args.recentBlockhash;
this.compiledInstructions = args.compiledInstructions;
this.addressTableLookups = args.addressTableLookups;
}
get version() {
return 0;
}
get numAccountKeysFromLookups() {
let count = 0;
for (const lookup of this.addressTableLookups) {
count += lookup.readonlyIndexes.length + lookup.writableIndexes.length;
}
return count;
}
getAccountKeys(args) {
let accountKeysFromLookups;
if (args && 'accountKeysFromLookups' in args && args.accountKeysFromLookups) {
if (this.numAccountKeysFromLookups != args.accountKeysFromLookups.writable.length + args.accountKeysFromLookups.readonly.length) {
throw new Error('Failed to get account keys because of a mismatch in the number of account keys from lookups');
}
accountKeysFromLookups = args.accountKeysFromLookups;
} else if (args && 'addressLookupTableAccounts' in args && args.addressLookupTableAccounts) {
accountKeysFromLookups = this.resolveAddressTableLookups(args.addressLookupTableAccounts);
} else if (this.addressTableLookups.length > 0) {
throw new Error('Failed to get account keys because address table lookups were not resolved');
}
return new MessageAccountKeys(this.staticAccountKeys, accountKeysFromLookups);
}
isAccountSigner(index) {
return index < this.header.numRequiredSignatures;
}
isAccountWritable(index) {
const numSignedAccounts = this.header.numRequiredSignatures;
const numStaticAccountKeys = this.staticAccountKeys.length;
if (index >= numStaticAccountKeys) {
const lookupAccountKeysIndex = index - numStaticAccountKeys;
const numWritableLookupAccountKeys = this.addressTableLookups.reduce((count, lookup) => count + lookup.writableIndexes.length, 0);
return lookupAccountKeysIndex < numWritableLookupAccountKeys;
} else if (index >= this.header.numRequiredSignatures) {
const unsignedAccountIndex = index - numSignedAccounts;
const numUnsignedAccounts = numStaticAccountKeys - numSignedAccounts;
const numWritableUnsignedAccounts = numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts;
return unsignedAccountIndex < numWritableUnsignedAccounts;
} else {
const numWritableSignedAccounts = numSignedAccounts - this.header.numReadonlySignedAccounts;
return index < numWritableSignedAccounts;
}
}
resolveAddressTableLookups(addressLookupTableAccounts) {
const accountKeysFromLookups = {
writable: [],
readonly: []
};
for (const tableLookup of this.addressTableLookups) {
const tableAccount = addressLookupTableAccounts.find(account => account.key.equals(tableLookup.accountKey));
if (!tableAccount) {
throw new Error(`Failed to find address lookup table account for table key ${tableLookup.accountKey.toBase58()}`);
}
for (const index of tableLookup.writableIndexes) {
if (index < tableAccount.state.addresses.length) {
accountKeysFromLookups.writable.push(tableAccount.state.addresses[index]);
} else {
throw new Error(`Failed to find address for index ${index} in address lookup table ${tableLookup.accountKey.toBase58()}`);
}
}
for (const index of tableLookup.readonlyIndexes) {
if (index < tableAccount.state.addresses.length) {
accountKeysFromLookups.readonly.push(tableAccount.state.addresses[index]);
} else {
throw new Error(`Failed to find address for index ${index} in address lookup table ${tableLookup.accountKey.toBase58()}`);
}
}
}
return accountKeysFromLookups;
}
static compile(args) {
const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey);
const addressTableLookups = new Array();
const accountKeysFromLookups = {
writable: new Array(),
readonly: new Array()
};
const lookupTableAccounts = args.addressLookupTableAccounts || [];
for (const lookupTable of lookupTableAccounts) {
const extractResult = compiledKeys.extractTableLookup(lookupTable);
if (extractResult !== undefined) {
const [addressTableLookup, {
writable,
readonly
}] = extractResult;
addressTableLookups.push(addressTableLookup);
accountKeysFromLookups.writable.push(...writable);
accountKeysFromLookups.readonly.push(...readonly);
}
}
const [header, staticAccountKeys] = compiledKeys.getMessageComponents();
const accountKeys = new MessageAccountKeys(staticAccountKeys, accountKeysFromLookups);
const compiledInstructions = accountKeys.compileInstructions(args.instructions);
return new MessageV0({
header,
staticAccountKeys,
recentBlockhash: args.recentBlockhash,
compiledInstructions,
addressTableLookups
});
}
serialize() {
const encodedStaticAccountKeysLength = Array();
encodeLength(encodedStaticAccountKeysLength, this.staticAccountKeys.length);
const serializedInstructions = this.serializeInstructions();
const encodedInstructionsLength = Array();
encodeLength(encodedInstructionsLength, this.compiledInstructions.length);
const serializedAddressTableLookups = this.serializeAddressTableLookups();
const encodedAddressTableLookupsLength = Array();
encodeLength(encodedAddressTableLookupsLength, this.addressTableLookups.length);
const messageLayout = BufferLayout__namespace.struct([BufferLayout__namespace.u8('prefix'), BufferLayout__namespace.struct([BufferLayout__namespace.u8('numRequiredSignatures'), BufferLayout__namespace.u8('numReadonlySignedAccounts'), BufferLayout__namespace.u8('numReadonlyUnsignedAccounts')], 'header'), BufferLayout__namespace.blob(encodedStaticAccountKeysLength.length, 'staticAccountKeysLength'), BufferLayout__namespace.seq(publicKey(), this.staticAccountKeys.length, 'staticAccountKeys'), publicKey('recentBlockhash'), BufferLayout__namespace.blob(encodedInstructionsLength.length, 'instructionsLength'), BufferLayout__namespace.blob(serializedInstructions.length, 'serializedInstructions'), BufferLayout__namespace.blob(encodedAddressTableLookupsLength.length, 'addressTableLookupsLength'), BufferLayout__namespace.blob(serializedAddressTableLookups.length, 'serializedAddressTableLookups')]);
const serializedMessage = new Uint8Array(PACKET_DATA_SIZE);
const MESSAGE_VERSION_0_PREFIX = 1 << 7;
const serializedMessageLength = messageLayout.encode({
prefix: MESSAGE_VERSION_0_PREFIX,
header: this.header,
staticAccountKeysLength: new Uint8Array(encodedStaticAccountKeysLength),
staticAccountKeys: this.staticAccountKeys.map(key => key.toBytes()),
recentBlockhash: bs58__default.default.decode(this.recentBlockhash),
instructionsLength: new Uint8Array(encodedInstructionsLength),
serializedInstructions,
addressTableLookupsLength: new Uint8Array(encodedAddressTableLookupsLength),
serializedAddressTableLookups
}, serializedMessage);
return serializedMessage.slice(0, serializedMessageLength);
}
serializeInstructions() {
let serializedLength = 0;
const serializedInstructions = new Uint8Array(PACKET_DATA_SIZE);
for (const instruction of this.compiledInstructions) {
const encodedAccountKeyIndexesLength = Array();
encodeLength(encodedAccountKeyIndexesLength, instruction.accountKeyIndexes.length);
const encodedDataLength = Array();
encodeLength(encodedDataLength, instruction.data.length);
const instructionLayout = BufferLayout__namespace.struct([BufferLayout__namespace.u8('programIdIndex'), BufferLayout__namespace.blob(encodedAccountKeyIndexesLength.length, 'encodedAccountKeyIndexesLength'), BufferLayout__namespace.seq(BufferLayout__namespace.u8(), instruction.accountKeyIndexes.length, 'accountKeyIndexes'), BufferLayout__namespace.blob(encodedDataLength.length, 'encodedDataLength'), BufferLayout__namespace.blob(instruction.data.length, 'data')]);
serializedLength += instructionLayout.encode({
programIdIndex: instruction.programIdIndex,
encodedAccountKeyIndexesLength: new Uint8Array(encodedAccountKeyIndexesLength),
accountKeyIndexes: instruction.accountKeyIndexes,
encodedDataLength: new Uint8Array(encodedDataLength),
data: instruction.data
}, serializedInstructions, serializedLength);
}
return serializedInstructions.slice(0, serializedLength);
}
serializeAddressTableLookups() {
let serializedLength = 0;
const serializedAddressTableLookups = new Uint8Array(PACKET_DATA_SIZE);
for (const lookup of this.addressTableLookups) {
const encodedWritableIndexesLength = Array();
encodeLength(encodedWritableIndexesLength, lookup.writableIndexes.length);
const encodedReadonlyIndexesLength = Array();
encodeLength(encodedReadonlyIndexesLength, lookup.readonlyIndexes.length);
const addressTableLookupLayout = BufferLayout__namespace.struct([publicKey('accountKey'), BufferLayout__namespace.blob(encodedWritableIndexesLength.length, 'encodedWritableIndexesLength'), BufferLayout__namespace.seq(BufferLayout__namespace.u8(), lookup.writableIndexes.length, 'writableIndexes'), BufferLayout__namespace.blob(encodedReadonlyIndexesLength.length, 'encodedReadonlyIndexesLength'), BufferLayout__namespace.seq(BufferLayout__namespace.u8(), lookup.readonlyIndexes.length, 'readonlyIndexes')]);
serializedLength += addressTableLookupLayout.encode({
accountKey: lookup.accountKey.toBytes(),
encodedWritableIndexesLength: new Uint8Array(encodedWritableIndexesLength),
writableIndexes: lookup.writableIndexes,
encodedReadonlyIndexesLength: new Uint8Array(encodedReadonlyIndexesLength),
readonlyIndexes: lookup.readonlyIndexes
}, serializedAddressTableLookups, serializedLength);
}
return serializedAddressTableLookups.slice(0, serializedLength);
}
static deserialize(serializedMessage) {
let byteArray = [...serializedMessage];
const prefix = guardedShift(byteArray);
const maskedPrefix = prefix & VERSION_PREFIX_MASK;
assert(prefix !== maskedPrefix, `Expected versioned message but received legacy message`);
const version = maskedPrefix;
assert(version === 0, `Expected versioned message with version 0 but found version ${version}`);
const header = {
numRequiredSignatures: guardedShift(byteArray),
numReadonlySignedAccounts: guardedShift(byteArray),
numReadonlyUnsignedAccounts: guardedShift(byteArray)
};
const staticAccountKeys = [];
const staticAccountKeysLength = decodeLength(byteArray);
for (let i = 0; i < staticAccountKeysLength; i++) {
staticAccountKeys.push(new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH)));
}
const recentBlockhash = bs58__default.default.encode(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
const instructionCount = decodeLength(byteArray);
const compiledInstructions = [];
for (let i = 0; i < instructionCount; i++) {
const programIdIndex = guardedShift(byteArray);
const accountKeyIndexesLength = decodeLength(byteArray);
const accountKeyIndexes = guardedSplice(byteArray, 0, accountKeyIndexesLength);
const dataLength = decodeLength(byteArray);
const data = new Uint8Array(guardedSplice(byteArray, 0, dataLength));
compiledInstructions.push({
programIdIndex,
accountKeyIndexes,
data
});
}
const addressTableLookupsCount = decodeLength(byteArray);
const addressTableLookups = [];
for (let i = 0; i < addressTableLookupsCount; i++) {
const accountKey = new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
const writableIndexesLength = decodeLength(byteArray);
const writableIndexes = guardedSplice(byteArray, 0, writableIndexesLength);
const readonlyIndexesLength = decodeLength(byteArray);
const readonlyIndexes = guardedSplice(byteArray, 0, readonlyIndexesLength);
addressTableLookups.push({
accountKey,
writableIndexes,
readonlyIndexes
});
}
return new MessageV0({
header,
staticAccountKeys,
recentBlockhash,
compiledInstructions,
addressTableLookups
});
}
}
// eslint-disable-next-line no-redeclare
const VersionedMessage = {
deserializeMessageVersion(serializedMessage) {
const prefix = serializedMessage[0];
const maskedPrefix = prefix & VERSION_PREFIX_MASK;
// if the highest bit of the prefix is not set, the message is not versioned
if (maskedPrefix === prefix) {
return 'legacy';
}
// the lower 7 bits of the prefix indicate the message version
return maskedPrefix;
},
deserialize: serializedMessage => {
const version = VersionedMessage.deserializeMessageVersion(serializedMessage);
if (version === 'legacy') {
return Message.from(serializedMessage);
}
if (version === 0) {
return MessageV0.deserialize(serializedMessage);
} else {
throw new Error(`Transaction message version ${version} deserialization is not supported`);
}
}
};
/** @internal */
/**
* Transaction signature as base-58 encoded string
*/
let TransactionStatus = /*#__PURE__*/function (TransactionStatus) {
TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
TransactionStatus[TransactionStatus["NONCE_INVALID"] = 3] = "NONCE_INVALID";
return TransactionStatus;
}({});
/**
* Default (empty) signature
*/
const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
/**
* Account metadata used to define instructions
*/
/**
* List of TransactionInstruction object fields that may be initialized at construction
*/
/**
* Configuration object for Transaction.serialize()
*/
/**
* @internal
*/
/**
* Transaction Instruction class
*/
class TransactionInstruction {
constructor(opts) {
/**
* Public keys to include in this transaction
* Boolean represents whether this pubkey needs to sign the transaction
*/
this.keys = void 0;
/**
* Program Id to execute
*/
this.programId = void 0;
/**
* Program input
*/
this.data = buffer.Buffer.alloc(0);
this.programId = opts.programId;
this.keys = opts.keys;
if (opts.data) {
this.data = opts.data;
}
}
/**
* @internal
*/
toJSON() {
return {
keys: this.keys.map(({
pubkey,
isSigner,
isWritable
}) => ({
pubkey: pubkey.toJSON(),
isSigner,
isWritable
})),
programId: this.programId.toJSON(),
data: [...this.data]
};
}
}
/**
* Pair of signature and corresponding public key
*/
/**
* List of Transaction object fields that may be initialized at construction
*/
// For backward compatibility; an unfortunate consequence of being
// forced to over-export types by the documentation generator.
// See https://github.com/solana-labs/solana/pull/25820
/**
* Blockhash-based transactions have a lifetime that are defined by
* the blockhash they include. Any transaction whose blockhash is
* too old will be rejected.
*/
/**
* Use these options to construct a durable nonce transaction.
*/
/**
* Nonce information to be used to build an offline Transaction.
*/
/**
* @internal
*/
/**
* Transaction class
*/
class Transaction {
/**
* The first (payer) Transaction signature
*
* @returns {Buffer | null} Buffer of payer's signature
*/
get signature() {
if (this.signatures.length > 0) {
return this.signatures[0].signature;
}
return null;
}
/**
* The transaction fee payer
*/
// Construct a transaction with a blockhash and lastValidBlockHeight
// Construct a transaction using a durable nonce
/**
* @deprecated `TransactionCtorFields` has been deprecated and will be removed in a future version.
* Please supply a `TransactionBlockhashCtor` instead.
*/
/**
* Construct an empty Transaction
*/
constructor(opts) {
/**
* Signatures for the transaction. Typically created by invoking the
* `sign()` method
*/
this.signatures = [];
this.feePayer = void 0;
/**
* The instructions to atomically execute
*/
this.instructions = [];
/**
* A recent transaction id. Must be populated by the caller
*/
this.recentBlockhash = void 0;
/**
* the last block chain can advance to before tx is declared expired
* */
this.lastValidBlockHeight = void 0;
/**
* Optional Nonce information. If populated, transaction will use a durable
* Nonce hash instead of a recentBlockhash. Must be populated by the caller
*/
this.nonceInfo = void 0;
/**
* If this is a nonce transaction this represents the minimum slot from which
* to evaluate if the nonce has advanced when attempting to confirm the
* transaction. This protects against a case where the transaction confirmation
* logic loads the nonce account from an old slot and assumes the mismatch in
* nonce value implies that the nonce has been advanced.
*/
this.minNonceContextSlot = void 0;
/**
* @internal
*/
this._message = void 0;
/**
* @internal
*/
this._json = void 0;
if (!opts) {
return;
}
if (opts.feePayer) {
this.feePayer = opts.feePayer;
}
if (opts.signatures) {
this.signatures = opts.signatures;
}
if (Object.prototype.hasOwnProperty.call(opts, 'nonceInfo')) {
const {
minContextSlot,
nonceInfo
} = opts;
this.minNonceContextSlot = minContextSlot;
this.nonceInfo = nonceInfo;
} else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
const {
blockhash,
lastValidBlockHeight
} = opts;
this.recentBlockhash = blockhash;
this.lastValidBlockHeight = lastValidBlockHeight;
} else {
const {
recentBlockhash,
nonceInfo
} = opts;
if (nonceInfo) {
this.nonceInfo = nonceInfo;
}
this.recentBlockhash = recentBlockhash;
}
}
/**
* @internal
*/
toJSON() {
return {
recentBlockhash: this.recentBlockhash || null,
feePayer: this.feePayer ? this.feePayer.toJSON() : null,
nonceInfo: this.nonceInfo ? {
nonce: this.nonceInfo.nonce,
nonceInstruction: this.nonceInfo.nonceInstruction.toJSON()
} : null,
instructions: this.instructions.map(instruction => instruction.toJSON()),
signers: this.signatures.map(({
publicKey
}) => {
return publicKey.toJSON();
})
};
}
/**
* Add one or more instructions to this Transaction
*
* @param {Array< Transaction | TransactionInstruction | TransactionInstructionCtorFields >} items - Instructions to add to the Transaction
*/
add(...items) {
if (items.length === 0) {
throw new Error('No instructions');
}
items.forEach(item => {
if ('instructions' in item) {
this.instructions = this.instructions.concat(item.instructions);
} else if ('data' in item && 'programId' in item && 'keys' in item) {
this.instructions.push(item);
} else {
this.instructions.push(new TransactionInstruction(item));
}
});
return this;
}
/**
* Compile transaction data
*/
compileMessage() {
if (this._message && JSON.stringify(this.toJSON()) === JSON.stringify(this._json)) {
return this._message;
}
let recentBlockhash;
let instructions;
if (this.nonceInfo) {
recentBlockhash = this.nonceInfo.nonce;
if (this.instructions[0] != this.nonceInfo.nonceInstruction) {
instructions = [this.nonceInfo.nonceInstruction, ...this.instructions];
} else {
instructions = this.instructions;
}
} else {
recentBlockhash = this.recentBlockhash;
instructions = this.instructions;
}
if (!recentBlockhash) {
throw new Error('Transaction recentBlockhash required');
}
if (instructions.length < 1) {
console.warn('No instructions provided');
}
let feePayer;
if (this.feePayer) {
feePayer = this.feePayer;
} else if (this.signatures.length > 0 && this.signatures[0].publicKey) {
// Use implicit fee payer
feePayer = this.signatures[0].publicKey;
} else {
throw new Error('Transaction fee payer required');
}
for (let i = 0; i < instructions.length; i++) {
if (instructions[i].programId === undefined) {
throw new Error(`Transaction instruction index ${i} has undefined program id`);
}
}
const programIds = [];
const accountMetas = [];
instructions.forEach(instruction => {
instruction.keys.forEach(accountMeta => {
accountMetas.push({
...accountMeta
});
});
const programId = instruction.programId.toString();
if (!programIds.includes(programId)) {
programIds.push(programId);
}
});
// Append programID account metas
programIds.forEach(programId => {
accountMetas.push({
pubkey: new PublicKey(programId),
isSigner: false,
isWritable: false
});
});
// Cull duplicate account metas
const uniqueMetas = [];
accountMetas.forEach(accountMeta => {
const pubkeyString = accountMeta.pubkey.toString();
const uniqueIndex = uniqueMetas.findIndex(x => {
return x.pubkey.toString() === pubkeyString;
});
if (uniqueIndex > -1) {
uniqueMetas[uniqueIndex].isWritable = uniqueMetas[uniqueIndex].isWritable || accountMeta.isWritable;
uniqueMetas[uniqueIndex].isSigner = uniqueMetas[uniqueIndex].isSigner || accountMeta.isSigner;
} else {
uniqueMetas.push(accountMeta);
}
});
// Sort. Prioritizing first by signer, then by writable
uniqueMetas.sort(function (x, y) {
if (x.isSigner !== y.isSigner) {
// Signers always come before non-signers
return x.isSigner ? -1 : 1;
}
if (x.isWritable !== y.isWritable) {
// Writable accounts always come before read-only accounts
return x.isWritable ? -1 : 1;
}
// Otherwise, sort by pubkey, stringwise.
const options = {
localeMatcher: 'best fit',
usage: 'sort',
sensitivity: 'variant',
ignorePunctuation: false,
numeric: false,
caseFirst: 'lower'
};
return x.pubkey.toBase58().localeCompare(y.pubkey.toBase58(), 'en', options);
});
// Move fee payer to the front
const feePayerIndex = uniqueMetas.findIndex(x => {
return x.pubkey.equals(feePayer);
});
if (feePayerIndex > -1) {
const [payerMeta] = uniqueMetas.splice(feePayerIndex, 1);
payerMeta.isSigner = true;
payerMeta.isWritable = true;
uniqueMetas.unshift(payerMeta);
} else {
uniqueMetas.unshift({
pubkey: feePayer,
isSigner: true,
isWritable: true
});
}
// Disallow unknown signers
for (const signature of this.signatures) {
const uniqueIndex = uniqueMetas.findIndex(x => {
return x.pubkey.equals(signature.publicKey);
});
if (uniqueIndex > -1) {
if (!uniqueMetas[uniqueIndex].isSigner) {
uniqueMetas[uniqueIndex].isSigner = true;
console.warn('Transaction references a signature that is unnecessary, ' + 'only the fee payer and instruction signer accounts should sign a transaction. ' + 'This behavior is deprecated and will throw an error in the next major version release.');
}
} else {
throw new Error(`unknown signer: ${signature.publicKey.toString()}`);
}
}
let numRequiredSignatures = 0;
let numReadonlySignedAccounts = 0;
let numReadonlyUnsignedAccounts = 0;
// Split out signing from non-signing keys and count header values
const signedKeys = [];
const unsignedKeys = [];
uniqueMetas.forEach(({
pubkey,
isSigner,
isWritable
}) => {
if (isSigner) {
signedKeys.push(pubkey.toString());
numRequiredSignatures += 1;
if (!isWritable) {
numReadonlySignedAccounts += 1;
}
} else {
unsignedKeys.push(pubkey.toString());
if (!isWritable) {
numReadonlyUnsignedAccounts += 1;
}
}
});
const accountKeys = signedKeys.concat(unsignedKeys);
const compiledInstructions = instructions.map(instruction => {
const {
data,
programId
} = instruction;
return {
programIdIndex: accountKeys.indexOf(programId.toString()),
accounts: instruction.keys.map(meta => accountKeys.indexOf(meta.pubkey.toString())),
data: bs58__default.default.encode(data)
};
});
compiledInstructions.forEach(instruction => {
assert(instruction.programIdIndex >= 0);
instruction.accounts.forEach(keyIndex => assert(keyIndex >= 0));
});
return new Message({
header: {
numRequiredSignatures,
numReadonlySignedAccounts,
numReadonlyUnsignedAccounts
},
accountKeys,
recentBlockhash,
instructions: compiledInstructions
});
}
/**
* @internal
*/
_compile() {
const message = this.compileMessage();
const signedKeys = message.accountKeys.slice(0, message.header.numRequiredSignatures);
if (this.signatures.length === signedKeys.length) {
const valid = this.signatures.every((pair, index) => {
return signedKeys[index].equals(pair.publicKey);
});
if (valid) return message;
}
this.signatures = signedKeys.map(publicKey => ({
signature: null,
publicKey
}));
return message;
}
/**
* Get a buffer of the Transaction data that need to be covered by signatures
*/
serializeMessage() {
return this._compile().serialize();
}
/**
* Get the estimated fee associated with a transaction
*
* @param {Connection} connection Connection to RPC Endpoint.
*
* @returns {Promise<number | null>} The estimated fee for the transaction
*/
async getEstimatedFee(connection) {
return (await connection.getFeeForMessage(this.compileMessage())).value;
}
/**
* Specify the public keys which will be used to sign the Transaction.
* The first signer will be used as the transaction fee payer account.
*
* Signatures can be added with either `partialSign` or `addSignature`
*
* @deprecated Deprecated since v0.84.0. Only the fee payer needs to be
* specified and it can be set in the Transaction constructor or with the
* `feePayer` property.
*/
setSigners(...signers) {
if (signers.length === 0) {
throw new Error('No signers');
}
const seen = new Set();
this.signatures = signers.filter(publicKey => {
const key = publicKey.toString();
if (seen.has(key)) {
return false;
} else {
seen.add(key);
return true;
}
}).map(publicKey => ({
signature: null,
publicKey
}));
}
/**
* Sign the Transaction with the specified signers. Multiple signatures may
* be applied to a Transaction. The first signature is considered "primary"
* and is used identify and confirm transactions.
*
* If the Transaction `feePayer` is not set, the first signer will be used
* as the transaction fee payer account.
*
* Transaction fields should not be modified after the first call to `sign`,
* as doing so may invalidate the signature and cause the Transaction to be
* rejected.
*
* The Transaction must be assigned a valid `recentBlockhash` before invoking this method
*
* @param {Array<Signer>} signers Array of signers that will sign the transaction
*/
sign(...signers) {
if (signers.length === 0) {
throw new Error('No signers');
}
// Dedupe signers
const seen = new Set();
const uniqueSigners = [];
for (const signer of signers) {
const key = signer.publicKey.toString();
if (seen.has(key)) {
continue;
} else {
seen.add(key);
uniqueSigners.push(signer);
}
}
this.signatures = uniqueSigners.map(signer => ({
signature: null,
publicKey: signer.publicKey
}));
const message = this._compile();
this._partialSign(message, ...uniqueSigners);
}
/**
* Partially sign a transaction with the specified accounts. All accounts must
* correspond to either the fee payer or a signer account in the transaction
* instructions.
*
* All the caveats from the `sign` method apply to `partialSign`
*
* @param {Array<Signer>} signers Array of signers that will sign the transaction
*/
partialSign(...signers) {
if (signers.length === 0) {
throw new Error('No signers');
}
// Dedupe signers
const seen = new Set();
const uniqueSigners = [];
for (const signer of signers) {
const key = signer.publicKey.toString();
if (seen.has(key)) {
continue;
} else {
seen.add(key);
uniqueSigners.push(signer);
}
}
const message = this._compile();
this._partialSign(message, ...uniqueSigners);
}
/**
* @internal
*/
_partialSign(message, ...signers) {
const signData = message.serialize();
signers.forEach(signer => {
const signature = sign(signData, signer.secretKey);
this._addSignature(signer.publicKey, toBuffer(signature));
});
}
/**
* Add an externally created signature to a transaction. The public key
* must correspond to either the fee payer or a signer account in the transaction
* instructions.
*
* @param {PublicKey} pubkey Public key that will be added to the transaction.
* @param {Buffer} signature An externally created signature to add to the transaction.
*/
addSignature(pubkey, signature) {
this._compile(); // Ensure signatures array is populated
this._addSignature(pubkey, signature);
}
/**
* @internal
*/
_addSignature(pubkey, signature) {
assert(signature.length === 64);
const index = this.signatures.findIndex(sigpair => pubkey.equals(sigpair.publicKey));
if (index < 0) {
throw new Error(`unknown signer: ${pubkey.toString()}`);
}
this.signatures[index].signature = buffer.Buffer.from(signature);
}
/**
* Verify signatures of a Transaction
* Optional parameter specifies if we're expecting a fully signed Transaction or a partially signed one.
* If no boolean is provided, we expect a fully signed Transaction by default.
*
* @param {boolean} [requireAllSignatures=true] Require a fully signed Transaction
*/
verifySignatures(requireAllSignatures = true) {
const signatureErrors = this._getMessageSignednessErrors(this.serializeMessage(), requireAllSignatures);
return !signatureErrors;
}
/**
* @internal
*/
_getMessageSignednessErrors(message, requireAllSignatures) {
const errors = {};
for (const {
signature,
publicKey
} of this.signatures) {
if (signature === null) {
if (requireAllSignatures) {
(errors.missing ||= []).push(publicKey);
}
} else {
if (!verify(signature, message, publicKey.toBytes())) {
(errors.invalid ||= []).push(publicKey);
}
}
}
return errors.invalid || errors.missing ? errors : undefined;
}
/**
* Serialize the Transaction in the wire format.
*
* @param {Buffer} [config] Config of transaction.
*
* @returns {Buffer} Signature of transaction in wire format.
*/
serialize(config) {
const {
requireAllSignatures,
verifySignatures
} = Object.assign({
requireAllSignatures: true,
verifySignatures: true
}, config);
const signData = this.serializeMessage();
if (verifySignatures) {
const sigErrors = this._getMessageSignednessErrors(signData, requireAllSignatures);
if (sigErrors) {
let errorMessage = 'Signature verification failed.';
if (sigErrors.invalid) {
errorMessage += `\nInvalid signature for public key${sigErrors.invalid.length === 1 ? '' : '(s)'} [\`${sigErrors.invalid.map(p => p.toBase58()).join('`, `')}\`].`;
}
if (sigErrors.missing) {
errorMessage += `\nMissing signature for public key${sigErrors.missing.length === 1 ? '' : '(s)'} [\`${sigErrors.missing.map(p => p.toBase58()).join('`, `')}\`].`;
}
throw new Error(errorMessage);
}
}
return this._serialize(signData);
}
/**
* @internal
*/
_serialize(signData) {
const {
signatures
} = this;
const signatureCount = [];
encodeLength(signatureCount, signatures.length);
const transactionLength = signatureCount.length + signatures.length * 64 + signData.length;
const wireTransaction = buffer.Buffer.alloc(transactionLength);
assert(signatures.length < 256);
buffer.Buffer.from(signatureCount).copy(wireTransaction, 0);
signatures.forEach(({
signature
}, index) => {
if (signature !== null) {
assert(signature.length === 64, `signature has invalid length`);
buffer.Buffer.from(signature).copy(wireTransaction, signatureCount.length + index * 64);
}
});
signData.copy(wireTransaction, signatureCount.length + signatures.length * 64);
assert(wireTransaction.length <= PACKET_DATA_SIZE, `Transaction too large: ${wireTransaction.length} > ${PACKET_DATA_SIZE}`);
return wireTransaction;
}
/**
* Deprecated method
* @internal
*/
get keys() {
assert(this.instructions.length === 1);
return this.instructions[0].keys.map(keyObj => keyObj.pubkey);
}
/**
* Deprecated method
* @internal
*/
get programId() {
assert(this.instructions.length === 1);
return this.instructions[0].programId;
}
/**
* Deprecated method
* @internal
*/
get data() {
assert(this.instructions.length === 1);
return this.instructions[0].data;
}
/**
* Parse a wire transaction into a Transaction object.
*
* @param {Buffer | Uint8Array | Array<number>} buffer Signature of wire Transaction
*
* @returns {Transaction} Transaction associated with the signature
*/
static from(buffer$1) {
// Slice up wire data
let byteArray = [...buffer$1];
const signatureCount = decodeLength(byteArray);
let signatures = [];
for (let i = 0; i < signatureCount; i++) {
const signature = guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES);
signatures.push(bs58__default.default.encode(buffer.Buffer.from(signature)));
}
return Transaction.populate(Message.from(byteArray), signatures);
}
/**
* Populate Transaction object from message and signatures
*
* @param {Message} message Message of transaction
* @param {Array<string>} signatures List of signatures to assign to the transaction
*
* @returns {Transaction} The populated Transaction
*/
static populate(message, signatures = []) {
const transaction = new Transaction();
transaction.recentBlockhash = message.recentBlockhash;
if (message.header.numRequiredSignatures > 0) {
transaction.feePayer = message.accountKeys[0];
}
signatures.forEach((signature, index) => {
const sigPubkeyPair = {
signature: signature == bs58__default.default.encode(DEFAULT_SIGNATURE) ? null : bs58__default.default.decode(signature),
publicKey: message.accountKeys[index]
};
transaction.signatures.push(sigPubkeyPair);
});
message.instructions.forEach(instruction => {
const keys = instruction.accounts.map(account => {
const pubkey = message.accountKeys[account];
return {
pubkey,
isSigner: transaction.signatures.some(keyObj => keyObj.publicKey.toString() === pubkey.toString()) || message.isAccountSigner(account),
isWritable: message.isAccountWritable(account)
};
});
transaction.instructions.push(new TransactionInstruction({
keys,
programId: message.accountKeys[instruction.programIdIndex],
data: bs58__default.default.decode(instruction.data)
}));
});
transaction._message = message;
transaction._json = transaction.toJSON();
return transaction;
}
}
class TransactionMessage {
constructor(args) {
this.payerKey = void 0;
this.instructions = void 0;
this.recentBlockhash = void 0;
this.payerKey = args.payerKey;
this.instructions = args.instructions;
this.recentBlockhash = args.recentBlockhash;
}
static decompile(message, args) {
const {
header,
compiledInstructions,
recentBlockhash
} = message;
const {
numRequiredSignatures,
numReadonlySignedAccounts,
numReadonlyUnsignedAccounts
} = header;
const numWritableSignedAccounts = numRequiredSignatures - numReadonlySignedAccounts;
assert(numWritableSignedAccounts > 0, 'Message header is invalid');
const numWritableUnsignedAccounts = message.staticAccountKeys.length - numRequiredSignatures - numReadonlyUnsignedAccounts;
assert(numWritableUnsignedAccounts >= 0, 'Message header is invalid');
const accountKeys = message.getAccountKeys(args);
const payerKey = accountKeys.get(0);
if (payerKey === undefined) {
throw new Error('Failed to decompile message because no account keys were found');
}
const instructions = [];
for (const compiledIx of compiledInstructions) {
const keys = [];
for (const keyIndex of compiledIx.accountKeyIndexes) {
const pubkey = accountKeys.get(keyIndex);
if (pubkey === undefined) {
throw new Error(`Failed to find key for account key index ${keyIndex}`);
}
const isSigner = keyIndex < numRequiredSignatures;
let isWritable;
if (isSigner) {
isWritable = keyIndex < numWritableSignedAccounts;
} else if (keyIndex < accountKeys.staticAccountKeys.length) {
isWritable = keyIndex - numRequiredSignatures < numWritableUnsignedAccounts;
} else {
isWritable = keyIndex - accountKeys.staticAccountKeys.length <
// accountKeysFromLookups cannot be undefined because we already found a pubkey for this index above
accountKeys.accountKeysFromLookups.writable.length;
}
keys.push({
pubkey,
isSigner: keyIndex < header.numRequiredSignatures,
isWritable
});
}
const programId = accountKeys.get(compiledIx.programIdIndex);
if (programId === undefined) {
throw new Error(`Failed to find program id for program id index ${compiledIx.programIdIndex}`);
}
instructions.push(new TransactionInstruction({
programId,
data: toBuffer(compiledIx.data),
keys
}));
}
return new TransactionMessage({
payerKey,
instructions,
recentBlockhash
});
}
compileToLegacyMessage() {
return Message.compile({
payerKey: this.payerKey,
recentBlockhash: this.recentBlockhash,
instructions: this.instructions
});
}
compileToV0Message(addressLookupTableAccounts) {
return MessageV0.compile({
payerKey: this.payerKey,
recentBlockhash: this.recentBlockhash,
instructions: this.instructions,
addressLookupTableAccounts
});
}
}
/**
* Versioned transaction class
*/
class VersionedTransaction {
get version() {
return this.message.version;
}
constructor(message, signatures) {
this.signatures = void 0;
this.message = void 0;
if (signatures !== undefined) {
assert(signatures.length === message.header.numRequiredSignatures, 'Expected signatures length to be equal to the number of required signatures');
this.signatures = signatures;
} else {
const defaultSignatures = [];
for (let i = 0; i < message.header.numRequiredSignatures; i++) {
defaultSignatures.push(new Uint8Array(SIGNATURE_LENGTH_IN_BYTES));
}
this.signatures = defaultSignatures;
}
this.message = message;
}
serialize() {
const serializedMessage = this.message.serialize();
const encodedSignaturesLength = Array();
encodeLength(encodedSignaturesLength, this.signatures.length);
const transactionLayout = BufferLayout__namespace.struct([BufferLayout__namespace.blob(encodedSignaturesLength.length, 'encodedSignaturesLength'), BufferLayout__namespace.seq(signature(), this.signatures.length, 'signatures'), BufferLayout__namespace.blob(serializedMessage.length, 'serializedMessage')]);
const serializedTransaction = new Uint8Array(2048);
const serializedTransactionLength = transactionLayout.encode({
encodedSignaturesLength: new Uint8Array(encodedSignaturesLength),
signatures: this.signatures,
serializedMessage
}, serializedTransaction);
return serializedTransaction.slice(0, serializedTransactionLength);
}
static deserialize(serializedTransaction) {
let byteArray = [...serializedTransaction];
const signatures = [];
const signaturesLength = decodeLength(byteArray);
for (let i = 0; i < signaturesLength; i++) {
signatures.push(new Uint8Array(guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES)));
}
const message = VersionedMessage.deserialize(new Uint8Array(byteArray));
return new VersionedTransaction(message, signatures);
}
sign(signers) {
const messageData = this.message.serialize();
const signerPubkeys = this.message.staticAccountKeys.slice(0, this.message.header.numRequiredSignatures);
for (const signer of signers) {
const signerIndex = signerPubkeys.findIndex(pubkey => pubkey.equals(signer.publicKey));
assert(signerIndex >= 0, `Cannot sign with non signer key ${signer.publicKey.toBase58()}`);
this.signatures[signerIndex] = sign(messageData, signer.secretKey);
}
}
addSignature(publicKey, signature) {
assert(signature.byteLength === 64, 'Signature must be 64 bytes long');
const signerPubkeys = this.message.staticAccountKeys.slice(0, this.message.header.numRequiredSignatures);
const signerIndex = signerPubkeys.findIndex(pubkey => pubkey.equals(publicKey));
assert(signerIndex >= 0, `Can not add signature; \`${publicKey.toBase58()}\` is not required to sign this transaction`);
this.signatures[signerIndex] = signature;
}
}
// TODO: These constants should be removed in favor of reading them out of a
// Syscall account
/**
* @internal
*/
const NUM_TICKS_PER_SECOND = 160;
/**
* @internal
*/
const DEFAULT_TICKS_PER_SLOT = 64;
/**
* @internal
*/
const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
/**
* @internal
*/
const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
const SYSVAR_CLOCK_PUBKEY = new PublicKey('SysvarC1ock11111111111111111111111111111111');
const SYSVAR_EPOCH_SCHEDULE_PUBKEY = new PublicKey('SysvarEpochSchedu1e111111111111111111111111');
const SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey('Sysvar1nstructions1111111111111111111111111');
const SYSVAR_RECENT_BLOCKHASHES_PUBKEY = new PublicKey('SysvarRecentB1ockHashes11111111111111111111');
const SYSVAR_RENT_PUBKEY = new PublicKey('SysvarRent111111111111111111111111111111111');
const SYSVAR_REWARDS_PUBKEY = new PublicKey('SysvarRewards111111111111111111111111111111');
const SYSVAR_SLOT_HASHES_PUBKEY = new PublicKey('SysvarS1otHashes111111111111111111111111111');
const SYSVAR_SLOT_HISTORY_PUBKEY = new PublicKey('SysvarS1otHistory11111111111111111111111111');
const SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey('SysvarStakeHistory1111111111111111111111111');
class SendTransactionError extends Error {
constructor({
action,
signature,
transactionMessage,
logs
}) {
const maybeLogsOutput = logs ? `Logs: \n${JSON.stringify(logs.slice(-10), null, 2)}. ` : '';
const guideText = '\nCatch the `SendTransactionError` and call `getLogs()` on it for full details.';
let message;
switch (action) {
case 'send':
message = `Transaction ${signature} resulted in an error. \n` + `${transactionMessage}. ` + maybeLogsOutput + guideText;
break;
case 'simulate':
message = `Simulation failed. \nMessage: ${transactionMessage}. \n` + maybeLogsOutput + guideText;
break;
default:
{
message = `Unknown action '${(a => a)(action)}'`;
}
}
super(message);
this.signature = void 0;
this.transactionMessage = void 0;
this.transactionLogs = void 0;
this.signature = signature;
this.transactionMessage = transactionMessage;
this.transactionLogs = logs ? logs : undefined;
}
get transactionError() {
return {
message: this.transactionMessage,
logs: Array.isArray(this.transactionLogs) ? this.transactionLogs : undefined
};
}
/* @deprecated Use `await getLogs()` instead */
get logs() {
const cachedLogs = this.transactionLogs;
if (cachedLogs != null && typeof cachedLogs === 'object' && 'then' in cachedLogs) {
return undefined;
}
return cachedLogs;
}
async getLogs(connection) {
if (!Array.isArray(this.transactionLogs)) {
this.transactionLogs = new Promise((resolve, reject) => {
connection.getTransaction(this.signature).then(tx => {
if (tx && tx.meta && tx.meta.logMessages) {
const logs = tx.meta.logMessages;
this.transactionLogs = logs;
resolve(logs);
} else {
reject(new Error('Log messages not found'));
}
}).catch(reject);
});
}
return await this.transactionLogs;
}
}
// Keep in sync with client/src/rpc_custom_errors.rs
// Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
const SolanaJSONRPCErrorCode = {
JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: -32001,
JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: -32002,
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: -32003,
JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: -32004,
JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: -32005,
JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: -32006,
JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: -32007,
JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: -32008,
JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: -32009,
JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: -32010,
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: -32011,
JSON_RPC_SCAN_ERROR: -32012,
JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: -32013,
JSON_RPC_SERVER_ERROR_BLOCK_STATUS_NOT_AVAILABLE_YET: -32014,
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION: -32015,
JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED: -32016
};
class SolanaJSONRPCError extends Error {
constructor({
code,
message,
data
}, customMessage) {
super(customMessage != null ? `${customMessage}: ${message}` : message);
this.code = void 0;
this.data = void 0;
this.code = code;
this.data = data;
this.name = 'SolanaJSONRPCError';
}
}
/**
* Sign, send and confirm a transaction.
*
* If `commitment` option is not specified, defaults to 'max' commitment.
*
* @param {Connection} connection
* @param {Transaction} transaction
* @param {Array<Signer>} signers
* @param {ConfirmOptions} [options]
* @returns {Promise<TransactionSignature>}
*/
async function sendAndConfirmTransaction(connection, transaction, signers, options) {
const sendOptions = options && {
skipPreflight: options.skipPreflight,
preflightCommitment: options.preflightCommitment || options.commitment,
maxRetries: options.maxRetries,
minContextSlot: options.minContextSlot
};
const signature = await connection.sendTransaction(transaction, signers, sendOptions);
let status;
if (transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null) {
status = (await connection.confirmTransaction({
abortSignal: options?.abortSignal,
signature: signature,
blockhash: transaction.recentBlockhash,
lastValidBlockHeight: transaction.lastValidBlockHeight
}, options && options.commitment)).value;
} else if (transaction.minNonceContextSlot != null && transaction.nonceInfo != null) {
const {
nonceInstruction
} = transaction.nonceInfo;
const nonceAccountPubkey = nonceInstruction.keys[0].pubkey;
status = (await connection.confirmTransaction({
abortSignal: options?.abortSignal,
minContextSlot: transaction.minNonceContextSlot,
nonceAccountPubkey,
nonceValue: transaction.nonceInfo.nonce,
signature
}, options && options.commitment)).value;
} else {
if (options?.abortSignal != null) {
console.warn('sendAndConfirmTransaction(): A transaction with a deprecated confirmation strategy was ' + 'supplied along with an `abortSignal`. Only transactions having `lastValidBlockHeight` ' + 'or a combination of `nonceInfo` and `minNonceContextSlot` are abortable.');
}
status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
}
if (status.err) {
if (signature != null) {
throw new SendTransactionError({
action: 'send',
signature: signature,
transactionMessage: `Status: (${JSON.stringify(status)})`
});
}
throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
}
return signature;
}
// zzz
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* @internal
*/
/**
* Populate a buffer of instruction data using an InstructionType
* @internal
*/
function encodeData(type, fields) {
const allocLength = type.layout.span >= 0 ? type.layout.span : getAlloc(type, fields);
const data = buffer.Buffer.alloc(allocLength);
const layoutFields = Object.assign({
instruction: type.index
}, fields);
type.layout.encode(layoutFields, data);
return data;
}
/**
* Decode instruction data buffer using an InstructionType
* @internal
*/
function decodeData$1(type, buffer) {
let data;
try {
data = type.layout.decode(buffer);
} catch (err) {
throw new Error('invalid instruction; ' + err);
}
if (data.instruction !== type.index) {
throw new Error(`invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`);
}
return data;
}
/**
* https://github.com/solana-labs/solana/blob/90bedd7e067b5b8f3ddbb45da00a4e9cabb22c62/sdk/src/fee_calculator.rs#L7-L11
*
* @internal
*/
const FeeCalculatorLayout = BufferLayout__namespace.nu64('lamportsPerSignature');
/**
* Calculator for transaction fees.
*
* @deprecated Deprecated since Solana v1.8.0.
*/
/**
* See https://github.com/solana-labs/solana/blob/0ea2843ec9cdc517572b8e62c959f41b55cf4453/sdk/src/nonce_state.rs#L29-L32
*
* @internal
*/
const NonceAccountLayout = BufferLayout__namespace.struct([BufferLayout__namespace.u32('version'), BufferLayout__namespace.u32('state'), publicKey('authorizedPubkey'), publicKey('nonce'), BufferLayout__namespace.struct([FeeCalculatorLayout], 'feeCalculator')]);
const NONCE_ACCOUNT_LENGTH = NonceAccountLayout.span;
/**
* A durable nonce is a 32 byte value encoded as a base58 string.
*/
/**
* NonceAccount class
*/
class NonceAccount {
/**
* @internal
*/
constructor(args) {
this.authorizedPubkey = void 0;
this.nonce = void 0;
this.feeCalculator = void 0;
this.authorizedPubkey = args.authorizedPubkey;
this.nonce = args.nonce;
this.feeCalculator = args.feeCalculator;
}
/**
* Deserialize NonceAccount from the account data.
*
* @param buffer account data
* @return NonceAccount
*/
static fromAccountData(buffer) {
const nonceAccount = NonceAccountLayout.decode(toBuffer(buffer), 0);
return new NonceAccount({
authorizedPubkey: new PublicKey(nonceAccount.authorizedPubkey),
nonce: new PublicKey(nonceAccount.nonce).toString(),
feeCalculator: nonceAccount.feeCalculator
});
}
}
function u64(property) {
const layout = BufferLayout.blob(8 /* bytes */, property);
const decode = layout.decode.bind(layout);
const encode = layout.encode.bind(layout);
const bigIntLayout = layout;
const codec = codecsNumbers.getU64Codec();
bigIntLayout.decode = (buffer, offset) => {
const src = decode(buffer, offset);
return codec.decode(src);
};
bigIntLayout.encode = (bigInt, buffer, offset) => {
const src = codec.encode(bigInt);
return encode(src, buffer, offset);
};
return bigIntLayout;
}
/**
* Create account system transaction params
*/
/**
* Transfer system transaction params
*/
/**
* Assign system transaction params
*/
/**
* Create account with seed system transaction params
*/
/**
* Create nonce account system transaction params
*/
/**
* Create nonce account with seed system transaction params
*/
/**
* Initialize nonce account system instruction params
*/
/**
* Advance nonce account system instruction params
*/
/**
* Withdraw nonce account system transaction params
*/
/**
* Authorize nonce account system transaction params
*/
/**
* Allocate account system transaction params
*/
/**
* Allocate account with seed system transaction params
*/
/**
* Assign account with seed system transaction params
*/
/**
* Transfer with seed system transaction params
*/
/** Decoded transfer system transaction instruction */
/** Decoded transferWithSeed system transaction instruction */
/**
* System Instruction class
*/
class SystemInstruction {
/**
* @internal
*/
constructor() {}
/**
* Decode a system instruction and retrieve the instruction type.
*/
static decodeInstructionType(instruction) {
this.checkProgramId(instruction.programId);
const instructionTypeLayout = BufferLayout__namespace.u32('instruction');
const typeIndex = instructionTypeLayout.decode(instruction.data);
let type;
for (const [ixType, layout] of Object.entries(SYSTEM_INSTRUCTION_LAYOUTS)) {
if (layout.index == typeIndex) {
type = ixType;
break;
}
}
if (!type) {
throw new Error('Instruction type incorrect; not a SystemInstruction');
}
return type;
}
/**
* Decode a create account system instruction and retrieve the instruction params.
*/
static decodeCreateAccount(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {
lamports,
space,
programId
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Create, instruction.data);
return {
fromPubkey: instruction.keys[0].pubkey,
newAccountPubkey: instruction.keys[1].pubkey,
lamports,
space,
programId: new PublicKey(programId)
};
}
/**
* Decode a transfer system instruction and retrieve the instruction params.
*/
static decodeTransfer(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {
lamports
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Transfer, instruction.data);
return {
fromPubkey: instruction.keys[0].pubkey,
toPubkey: instruction.keys[1].pubkey,
lamports
};
}
/**
* Decode a transfer with seed system instruction and retrieve the instruction params.
*/
static decodeTransferWithSeed(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
lamports,
seed,
programId
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed, instruction.data);
return {
fromPubkey: instruction.keys[0].pubkey,
basePubkey: instruction.keys[1].pubkey,
toPubkey: instruction.keys[2].pubkey,
lamports,
seed,
programId: new PublicKey(programId)
};
}
/**
* Decode an allocate system instruction and retrieve the instruction params.
*/
static decodeAllocate(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 1);
const {
space
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Allocate, instruction.data);
return {
accountPubkey: instruction.keys[0].pubkey,
space
};
}
/**
* Decode an allocate with seed system instruction and retrieve the instruction params.
*/
static decodeAllocateWithSeed(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 1);
const {
base,
seed,
space,
programId
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed, instruction.data);
return {
accountPubkey: instruction.keys[0].pubkey,
basePubkey: new PublicKey(base),
seed,
space,
programId: new PublicKey(programId)
};
}
/**
* Decode an assign system instruction and retrieve the instruction params.
*/
static decodeAssign(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 1);
const {
programId
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Assign, instruction.data);
return {
accountPubkey: instruction.keys[0].pubkey,
programId: new PublicKey(programId)
};
}
/**
* Decode an assign with seed system instruction and retrieve the instruction params.
*/
static decodeAssignWithSeed(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 1);
const {
base,
seed,
programId
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed, instruction.data);
return {
accountPubkey: instruction.keys[0].pubkey,
basePubkey: new PublicKey(base),
seed,
programId: new PublicKey(programId)
};
}
/**
* Decode a create account with seed system instruction and retrieve the instruction params.
*/
static decodeCreateWithSeed(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {
base,
seed,
lamports,
space,
programId
} = decodeData$1(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) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
authorized
} = decodeData$1(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) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
decodeData$1(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) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 5);
const {
lamports
} = decodeData$1(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) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {
authorized
} = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount, instruction.data);
return {
noncePubkey: instruction.keys[0].pubkey,
authorizedPubkey: instruction.keys[1].pubkey,
newAuthorizedPubkey: new PublicKey(authorized)
};
}
/**
* @internal
*/
static checkProgramId(programId) {
if (!programId.equals(SystemProgram.programId)) {
throw new Error('invalid instruction; programId is not SystemProgram');
}
}
/**
* @internal
*/
static checkKeyLength(keys, expectedLength) {
if (keys.length < expectedLength) {
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
}
}
}
/**
* An enumeration of valid SystemInstructionType's
*/
/**
* An enumeration of valid system InstructionType's
* @internal
*/
const SYSTEM_INSTRUCTION_LAYOUTS = Object.freeze({
Create: {
index: 0,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.ns64('lamports'), BufferLayout__namespace.ns64('space'), publicKey('programId')])
},
Assign: {
index: 1,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('programId')])
},
Transfer: {
index: 2,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), u64('lamports')])
},
CreateWithSeed: {
index: 3,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('base'), rustString('seed'), BufferLayout__namespace.ns64('lamports'), BufferLayout__namespace.ns64('space'), publicKey('programId')])
},
AdvanceNonceAccount: {
index: 4,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
WithdrawNonceAccount: {
index: 5,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.ns64('lamports')])
},
InitializeNonceAccount: {
index: 6,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('authorized')])
},
AuthorizeNonceAccount: {
index: 7,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('authorized')])
},
Allocate: {
index: 8,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.ns64('space')])
},
AllocateWithSeed: {
index: 9,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('base'), rustString('seed'), BufferLayout__namespace.ns64('space'), publicKey('programId')])
},
AssignWithSeed: {
index: 10,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('base'), rustString('seed'), publicKey('programId')])
},
TransferWithSeed: {
index: 11,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), u64('lamports'), rustString('seed'), publicKey('programId')])
},
UpgradeNonceAccount: {
index: 12,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
}
});
/**
* Factory class for transactions to interact with the System program
*/
class SystemProgram {
/**
* @internal
*/
constructor() {}
/**
* Public key that identifies the System program
*/
/**
* Generate a transaction instruction that creates a new account
*/
static createAccount(params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Create;
const data = encodeData(type, {
lamports: params.lamports,
space: params.space,
programId: toBuffer(params.programId.toBuffer())
});
return new TransactionInstruction({
keys: [{
pubkey: params.fromPubkey,
isSigner: true,
isWritable: true
}, {
pubkey: params.newAccountPubkey,
isSigner: true,
isWritable: true
}],
programId: this.programId,
data
});
}
/**
* Generate a transaction instruction that transfers lamports from one account to another
*/
static transfer(params) {
let data;
let keys;
if ('basePubkey' in params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed;
data = encodeData(type, {
lamports: BigInt(params.lamports),
seed: params.seed,
programId: toBuffer(params.programId.toBuffer())
});
keys = [{
pubkey: params.fromPubkey,
isSigner: false,
isWritable: true
}, {
pubkey: params.basePubkey,
isSigner: true,
isWritable: false
}, {
pubkey: params.toPubkey,
isSigner: false,
isWritable: true
}];
} else {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Transfer;
data = encodeData(type, {
lamports: BigInt(params.lamports)
});
keys = [{
pubkey: params.fromPubkey,
isSigner: true,
isWritable: true
}, {
pubkey: params.toPubkey,
isSigner: false,
isWritable: true
}];
}
return new TransactionInstruction({
keys,
programId: this.programId,
data
});
}
/**
* Generate a transaction instruction that assigns an account to a program
*/
static assign(params) {
let data;
let keys;
if ('basePubkey' in params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed;
data = encodeData(type, {
base: toBuffer(params.basePubkey.toBuffer()),
seed: params.seed,
programId: toBuffer(params.programId.toBuffer())
});
keys = [{
pubkey: params.accountPubkey,
isSigner: false,
isWritable: true
}, {
pubkey: params.basePubkey,
isSigner: true,
isWritable: false
}];
} else {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Assign;
data = encodeData(type, {
programId: toBuffer(params.programId.toBuffer())
});
keys = [{
pubkey: params.accountPubkey,
isSigner: true,
isWritable: true
}];
}
return new TransactionInstruction({
keys,
programId: this.programId,
data
});
}
/**
* Generate a transaction instruction that creates a new account at
* an address generated with `from`, a seed, and programId
*/
static createAccountWithSeed(params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.CreateWithSeed;
const data = encodeData(type, {
base: toBuffer(params.basePubkey.toBuffer()),
seed: params.seed,
lamports: params.lamports,
space: params.space,
programId: toBuffer(params.programId.toBuffer())
});
let keys = [{
pubkey: params.fromPubkey,
isSigner: true,
isWritable: true
}, {
pubkey: params.newAccountPubkey,
isSigner: false,
isWritable: true
}];
if (!params.basePubkey.equals(params.fromPubkey)) {
keys.push({
pubkey: params.basePubkey,
isSigner: true,
isWritable: false
});
}
return new TransactionInstruction({
keys,
programId: this.programId,
data
});
}
/**
* Generate a transaction that creates a new Nonce account
*/
static createNonceAccount(params) {
const transaction = new Transaction();
if ('basePubkey' in params && 'seed' in params) {
transaction.add(SystemProgram.createAccountWithSeed({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
basePubkey: params.basePubkey,
seed: params.seed,
lamports: params.lamports,
space: NONCE_ACCOUNT_LENGTH,
programId: this.programId
}));
} else {
transaction.add(SystemProgram.createAccount({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
lamports: params.lamports,
space: NONCE_ACCOUNT_LENGTH,
programId: this.programId
}));
}
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) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount;
const data = encodeData(type, {
authorized: toBuffer(params.authorizedPubkey.toBuffer())
});
const instructionData = {
keys: [{
pubkey: params.noncePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false
}],
programId: this.programId,
data
};
return new TransactionInstruction(instructionData);
}
/**
* Generate an instruction to advance the nonce in a Nonce account
*/
static nonceAdvance(params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.AdvanceNonceAccount;
const data = encodeData(type);
const instructionData = {
keys: [{
pubkey: params.noncePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: params.authorizedPubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
};
return new TransactionInstruction(instructionData);
}
/**
* Generate a transaction instruction that withdraws lamports from a Nonce account
*/
static nonceWithdraw(params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.WithdrawNonceAccount;
const data = encodeData(type, {
lamports: params.lamports
});
return new TransactionInstruction({
keys: [{
pubkey: params.noncePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: params.toPubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: params.authorizedPubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
});
}
/**
* Generate a transaction instruction that authorizes a new PublicKey as the authority
* on a Nonce account.
*/
static nonceAuthorize(params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.AuthorizeNonceAccount;
const data = encodeData(type, {
authorized: toBuffer(params.newAuthorizedPubkey.toBuffer())
});
return new TransactionInstruction({
keys: [{
pubkey: params.noncePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: params.authorizedPubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
});
}
/**
* Generate a transaction instruction that allocates space in an account without funding
*/
static allocate(params) {
let data;
let keys;
if ('basePubkey' in params) {
const type = SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed;
data = encodeData(type, {
base: toBuffer(params.basePubkey.toBuffer()),
seed: params.seed,
space: params.space,
programId: toBuffer(params.programId.toBuffer())
});
keys = [{
pubkey: params.accountPubkey,
isSigner: false,
isWritable: true
}, {
pubkey: params.basePubkey,
isSigner: true,
isWritable: false
}];
} else {
const type = SYSTEM_INSTRUCTION_LAYOUTS.Allocate;
data = encodeData(type, {
space: params.space
});
keys = [{
pubkey: params.accountPubkey,
isSigner: true,
isWritable: true
}];
}
return new TransactionInstruction({
keys,
programId: this.programId,
data
});
}
}
SystemProgram.programId = new PublicKey('11111111111111111111111111111111');
// Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the
// rest of the Transaction fields
//
// TODO: replace 300 with a proper constant for the size of the other
// Transaction fields
const CHUNK_SIZE = PACKET_DATA_SIZE - 300;
/**
* Program loader interface
*/
class Loader {
/**
* @internal
*/
constructor() {}
/**
* Amount of program data placed in each load Transaction
*/
/**
* Minimum number of signatures required to load a program not including
* retries
*
* Can be used to calculate transaction fees
*/
static getMinNumSignatures(dataLength) {
return 2 * (
// Every transaction requires two signatures (payer + program)
Math.ceil(dataLength / Loader.chunkSize) + 1 +
// Add one for Create transaction
1) // Add one for Finalize transaction
;
}
/**
* Loads a generic program
*
* @param connection The connection to use
* @param payer System account that pays to load the program
* @param program Account to load the program into
* @param programId Public key that identifies the loader
* @param data Program octets
* @return true if program was loaded successfully, false if program was already loaded
*/
static async load(connection, payer, program, programId, data) {
{
const balanceNeeded = await connection.getMinimumBalanceForRentExemption(data.length);
// Fetch program account info to check if it has already been created
const programInfo = await connection.getAccountInfo(program.publicKey, 'confirmed');
let transaction = null;
if (programInfo !== null) {
if (programInfo.executable) {
console.error('Program load failed, account is already executable');
return false;
}
if (programInfo.data.length !== data.length) {
transaction = transaction || new Transaction();
transaction.add(SystemProgram.allocate({
accountPubkey: program.publicKey,
space: data.length
}));
}
if (!programInfo.owner.equals(programId)) {
transaction = transaction || new Transaction();
transaction.add(SystemProgram.assign({
accountPubkey: program.publicKey,
programId
}));
}
if (programInfo.lamports < balanceNeeded) {
transaction = transaction || new Transaction();
transaction.add(SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: program.publicKey,
lamports: balanceNeeded - programInfo.lamports
}));
}
} else {
transaction = new Transaction().add(SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: program.publicKey,
lamports: balanceNeeded > 0 ? balanceNeeded : 1,
space: data.length,
programId
}));
}
// If the account is already created correctly, skip this step
// and proceed directly to loading instructions
if (transaction !== null) {
await sendAndConfirmTransaction(connection, transaction, [payer, program], {
commitment: 'confirmed'
});
}
}
const dataLayout = BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.u32('offset'), BufferLayout__namespace.u32('bytesLength'), BufferLayout__namespace.u32('bytesLengthPadding'), BufferLayout__namespace.seq(BufferLayout__namespace.u8('byte'), BufferLayout__namespace.offset(BufferLayout__namespace.u32(), -8), 'bytes')]);
const chunkSize = Loader.chunkSize;
let offset = 0;
let array = data;
let transactions = [];
while (array.length > 0) {
const bytes = array.slice(0, chunkSize);
const data = buffer.Buffer.alloc(chunkSize + 16);
dataLayout.encode({
instruction: 0,
// Load instruction
offset,
bytes: bytes,
bytesLength: 0,
bytesLengthPadding: 0
}, data);
const transaction = new Transaction().add({
keys: [{
pubkey: program.publicKey,
isSigner: true,
isWritable: true
}],
programId,
data
});
transactions.push(sendAndConfirmTransaction(connection, transaction, [payer, program], {
commitment: 'confirmed'
}));
// Delay between sends in an attempt to reduce rate limit errors
if (connection._rpcEndpoint.includes('solana.com')) {
const REQUESTS_PER_SECOND = 4;
await sleep(1000 / REQUESTS_PER_SECOND);
}
offset += chunkSize;
array = array.slice(chunkSize);
}
await Promise.all(transactions);
// Finalize the account loaded with program data for execution
{
const dataLayout = BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')]);
const data = buffer.Buffer.alloc(dataLayout.span);
dataLayout.encode({
instruction: 1 // Finalize instruction
}, data);
const transaction = new Transaction().add({
keys: [{
pubkey: program.publicKey,
isSigner: true,
isWritable: true
}, {
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false
}],
programId,
data
});
const deployCommitment = 'processed';
const finalizeSignature = await connection.sendTransaction(transaction, [payer, program], {
preflightCommitment: deployCommitment
});
const {
context,
value
} = await connection.confirmTransaction({
signature: finalizeSignature,
lastValidBlockHeight: transaction.lastValidBlockHeight,
blockhash: transaction.recentBlockhash
}, deployCommitment);
if (value.err) {
throw new Error(`Transaction ${finalizeSignature} failed (${JSON.stringify(value)})`);
}
// We prevent programs from being usable until the slot after their deployment.
// See https://github.com/solana-labs/solana/pull/29654
while (true // eslint-disable-line no-constant-condition
) {
try {
const currentSlot = await connection.getSlot({
commitment: deployCommitment
});
if (currentSlot > context.slot) {
break;
}
} catch {
/* empty */
}
await new Promise(resolve => setTimeout(resolve, Math.round(MS_PER_SLOT / 2)));
}
}
// success
return true;
}
}
Loader.chunkSize = CHUNK_SIZE;
/**
* @deprecated Deprecated since Solana v1.17.20.
*/
const BPF_LOADER_PROGRAM_ID = new PublicKey('BPFLoader2111111111111111111111111111111111');
/**
* Factory class for transactions to interact with a program loader
*
* @deprecated Deprecated since Solana v1.17.20.
*/
class BpfLoader {
/**
* Minimum number of signatures required to load a program not including
* retries
*
* Can be used to calculate transaction fees
*/
static getMinNumSignatures(dataLength) {
return Loader.getMinNumSignatures(dataLength);
}
/**
* Load a SBF program
*
* @param connection The connection to use
* @param payer Account that will pay program loading fees
* @param program Account to load the program into
* @param elf The entire ELF containing the SBF program
* @param loaderProgramId The program id of the BPF loader to use
* @return true if program was loaded successfully, false if program was already loaded
*/
static load(connection, payer, program, elf, loaderProgramId) {
return Loader.load(connection, payer, program, loaderProgramId, elf);
}
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var agentkeepalive = {exports: {}};
/**
* Helpers.
*/
var ms;
var hasRequiredMs;
function requireMs () {
if (hasRequiredMs) return ms;
hasRequiredMs = 1;
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var w = d * 7;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} [options]
* @throws {Error} throw an error if val is not a non-empty string or a number
* @return {String|Number}
* @api public
*/
ms = function (val, options) {
options = options || {};
var type = typeof val;
if (type === 'string' && val.length > 0) {
return parse(val);
} else if (type === 'number' && isFinite(val)) {
return options.long ? fmtLong(val) : fmtShort(val);
}
throw new Error(
'val is not a non-empty string or a valid number. val=' +
JSON.stringify(val)
);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = String(str);
if (str.length > 100) {
return;
}
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
str
);
if (!match) {
return;
}
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y;
case 'weeks':
case 'week':
case 'w':
return n * w;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s;
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n;
default:
return undefined;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtShort(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return Math.round(ms / d) + 'd';
}
if (msAbs >= h) {
return Math.round(ms / h) + 'h';
}
if (msAbs >= m) {
return Math.round(ms / m) + 'm';
}
if (msAbs >= s) {
return Math.round(ms / s) + 's';
}
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtLong(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return plural(ms, msAbs, d, 'day');
}
if (msAbs >= h) {
return plural(ms, msAbs, h, 'hour');
}
if (msAbs >= m) {
return plural(ms, msAbs, m, 'minute');
}
if (msAbs >= s) {
return plural(ms, msAbs, s, 'second');
}
return ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, msAbs, n, name) {
var isPlural = msAbs >= n * 1.5;
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
}
return ms;
}
/*!
* humanize-ms - index.js
* Copyright(c) 2014 dead_horse <dead_horse@qq.com>
* MIT Licensed
*/
var humanizeMs;
var hasRequiredHumanizeMs;
function requireHumanizeMs () {
if (hasRequiredHumanizeMs) return humanizeMs;
hasRequiredHumanizeMs = 1;
/**
* Module dependencies.
*/
var util = require$$0__default.default;
var ms = /*@__PURE__*/ requireMs();
humanizeMs = function (t) {
if (typeof t === 'number') return t;
var r = ms(t);
if (r === undefined) {
var err = new Error(util.format('humanize-ms(%j) result undefined', t));
console.warn(err.stack);
}
return r;
};
return humanizeMs;
}
var constants;
var hasRequiredConstants;
function requireConstants () {
if (hasRequiredConstants) return constants;
hasRequiredConstants = 1;
constants = {
// agent
CURRENT_ID: Symbol('agentkeepalive#currentId'),
CREATE_ID: Symbol('agentkeepalive#createId'),
INIT_SOCKET: Symbol('agentkeepalive#initSocket'),
CREATE_HTTPS_CONNECTION: Symbol('agentkeepalive#createHttpsConnection'),
// socket
SOCKET_CREATED_TIME: Symbol('agentkeepalive#socketCreatedTime'),
SOCKET_NAME: Symbol('agentkeepalive#socketName'),
SOCKET_REQUEST_COUNT: Symbol('agentkeepalive#socketRequestCount'),
SOCKET_REQUEST_FINISHED_COUNT: Symbol('agentkeepalive#socketRequestFinishedCount'),
};
return constants;
}
var agent;
var hasRequiredAgent;
function requireAgent () {
if (hasRequiredAgent) return agent;
hasRequiredAgent = 1;
const OriginalAgent = require$$0__default$1.default.Agent;
const ms = /*@__PURE__*/ requireHumanizeMs();
const debug = require$$0__default.default.debuglog('agentkeepalive');
const {
INIT_SOCKET,
CURRENT_ID,
CREATE_ID,
SOCKET_CREATED_TIME,
SOCKET_NAME,
SOCKET_REQUEST_COUNT,
SOCKET_REQUEST_FINISHED_COUNT,
} = /*@__PURE__*/ requireConstants();
// OriginalAgent come from
// - https://github.com/nodejs/node/blob/v8.12.0/lib/_http_agent.js
// - https://github.com/nodejs/node/blob/v10.12.0/lib/_http_agent.js
// node <= 10
let defaultTimeoutListenerCount = 1;
const majorVersion = parseInt(process.version.split('.', 1)[0].substring(1));
if (majorVersion >= 11 && majorVersion <= 12) {
defaultTimeoutListenerCount = 2;
} else if (majorVersion >= 13) {
defaultTimeoutListenerCount = 3;
}
function deprecate(message) {
console.log('[agentkeepalive:deprecated] %s', message);
}
class Agent extends OriginalAgent {
constructor(options) {
options = options || {};
options.keepAlive = options.keepAlive !== false;
// default is keep-alive and 4s free socket timeout
// see https://medium.com/ssense-tech/reduce-networking-errors-in-nodejs-23b4eb9f2d83
if (options.freeSocketTimeout === undefined) {
options.freeSocketTimeout = 4000;
}
// Legacy API: keepAliveTimeout should be rename to `freeSocketTimeout`
if (options.keepAliveTimeout) {
deprecate('options.keepAliveTimeout is deprecated, please use options.freeSocketTimeout instead');
options.freeSocketTimeout = options.keepAliveTimeout;
delete options.keepAliveTimeout;
}
// Legacy API: freeSocketKeepAliveTimeout should be rename to `freeSocketTimeout`
if (options.freeSocketKeepAliveTimeout) {
deprecate('options.freeSocketKeepAliveTimeout is deprecated, please use options.freeSocketTimeout instead');
options.freeSocketTimeout = options.freeSocketKeepAliveTimeout;
delete options.freeSocketKeepAliveTimeout;
}
// Sets the socket to timeout after timeout milliseconds of inactivity on the socket.
// By default is double free socket timeout.
if (options.timeout === undefined) {
// make sure socket default inactivity timeout >= 8s
options.timeout = Math.max(options.freeSocketTimeout * 2, 8000);
}
// support humanize format
options.timeout = ms(options.timeout);
options.freeSocketTimeout = ms(options.freeSocketTimeout);
options.socketActiveTTL = options.socketActiveTTL ? ms(options.socketActiveTTL) : 0;
super(options);
this[CURRENT_ID] = 0;
// create socket success counter
this.createSocketCount = 0;
this.createSocketCountLastCheck = 0;
this.createSocketErrorCount = 0;
this.createSocketErrorCountLastCheck = 0;
this.closeSocketCount = 0;
this.closeSocketCountLastCheck = 0;
// socket error event count
this.errorSocketCount = 0;
this.errorSocketCountLastCheck = 0;
// request finished counter
this.requestCount = 0;
this.requestCountLastCheck = 0;
// including free socket timeout counter
this.timeoutSocketCount = 0;
this.timeoutSocketCountLastCheck = 0;
this.on('free', socket => {
// https://github.com/nodejs/node/pull/32000
// Node.js native agent will check socket timeout eqs agent.options.timeout.
// Use the ttl or freeSocketTimeout to overwrite.
const timeout = this.calcSocketTimeout(socket);
if (timeout > 0 && socket.timeout !== timeout) {
socket.setTimeout(timeout);
}
});
}
get freeSocketKeepAliveTimeout() {
deprecate('agent.freeSocketKeepAliveTimeout is deprecated, please use agent.options.freeSocketTimeout instead');
return this.options.freeSocketTimeout;
}
get timeout() {
deprecate('agent.timeout is deprecated, please use agent.options.timeout instead');
return this.options.timeout;
}
get socketActiveTTL() {
deprecate('agent.socketActiveTTL is deprecated, please use agent.options.socketActiveTTL instead');
return this.options.socketActiveTTL;
}
calcSocketTimeout(socket) {
/**
* return <= 0: should free socket
* return > 0: should update socket timeout
* return undefined: not find custom timeout
*/
let freeSocketTimeout = this.options.freeSocketTimeout;
const socketActiveTTL = this.options.socketActiveTTL;
if (socketActiveTTL) {
// check socketActiveTTL
const aliveTime = Date.now() - socket[SOCKET_CREATED_TIME];
const diff = socketActiveTTL - aliveTime;
if (diff <= 0) {
return diff;
}
if (freeSocketTimeout && diff < freeSocketTimeout) {
freeSocketTimeout = diff;
}
}
// set freeSocketTimeout
if (freeSocketTimeout) {
// set free keepalive timer
// try to use socket custom freeSocketTimeout first, support headers['keep-alive']
// https://github.com/node-modules/urllib/blob/b76053020923f4d99a1c93cf2e16e0c5ba10bacf/lib/urllib.js#L498
const customFreeSocketTimeout = socket.freeSocketTimeout || socket.freeSocketKeepAliveTimeout;
return customFreeSocketTimeout || freeSocketTimeout;
}
}
keepSocketAlive(socket) {
const result = super.keepSocketAlive(socket);
// should not keepAlive, do nothing
if (!result) return result;
const customTimeout = this.calcSocketTimeout(socket);
if (typeof customTimeout === 'undefined') {
return true;
}
if (customTimeout <= 0) {
debug('%s(requests: %s, finished: %s) free but need to destroy by TTL, request count %s, diff is %s',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT], customTimeout);
return false;
}
if (socket.timeout !== customTimeout) {
socket.setTimeout(customTimeout);
}
return true;
}
// only call on addRequest
reuseSocket(...args) {
// reuseSocket(socket, req)
super.reuseSocket(...args);
const socket = args[0];
const req = args[1];
req.reusedSocket = true;
const agentTimeout = this.options.timeout;
if (getSocketTimeout(socket) !== agentTimeout) {
// reset timeout before use
socket.setTimeout(agentTimeout);
debug('%s reset timeout to %sms', socket[SOCKET_NAME], agentTimeout);
}
socket[SOCKET_REQUEST_COUNT]++;
debug('%s(requests: %s, finished: %s) reuse on addRequest, timeout %sms',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT],
getSocketTimeout(socket));
}
[CREATE_ID]() {
const id = this[CURRENT_ID]++;
if (this[CURRENT_ID] === Number.MAX_SAFE_INTEGER) this[CURRENT_ID] = 0;
return id;
}
[INIT_SOCKET](socket, options) {
// bugfix here.
// https on node 8, 10 won't set agent.options.timeout by default
// TODO: need to fix on node itself
if (options.timeout) {
const timeout = getSocketTimeout(socket);
if (!timeout) {
socket.setTimeout(options.timeout);
}
}
if (this.options.keepAlive) {
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/
// https://fengmk2.com/benchmark/nagle-algorithm-delayed-ack-mock.html
socket.setNoDelay(true);
}
this.createSocketCount++;
if (this.options.socketActiveTTL) {
socket[SOCKET_CREATED_TIME] = Date.now();
}
// don't show the hole '-----BEGIN CERTIFICATE----' key string
socket[SOCKET_NAME] = `sock[${this[CREATE_ID]()}#${options._agentKey}]`.split('-----BEGIN', 1)[0];
socket[SOCKET_REQUEST_COUNT] = 1;
socket[SOCKET_REQUEST_FINISHED_COUNT] = 0;
installListeners(this, socket, options);
}
createConnection(options, oncreate) {
let called = false;
const onNewCreate = (err, socket) => {
if (called) return;
called = true;
if (err) {
this.createSocketErrorCount++;
return oncreate(err);
}
this[INIT_SOCKET](socket, options);
oncreate(err, socket);
};
const newSocket = super.createConnection(options, onNewCreate);
if (newSocket) onNewCreate(null, newSocket);
return newSocket;
}
get statusChanged() {
const changed = this.createSocketCount !== this.createSocketCountLastCheck ||
this.createSocketErrorCount !== this.createSocketErrorCountLastCheck ||
this.closeSocketCount !== this.closeSocketCountLastCheck ||
this.errorSocketCount !== this.errorSocketCountLastCheck ||
this.timeoutSocketCount !== this.timeoutSocketCountLastCheck ||
this.requestCount !== this.requestCountLastCheck;
if (changed) {
this.createSocketCountLastCheck = this.createSocketCount;
this.createSocketErrorCountLastCheck = this.createSocketErrorCount;
this.closeSocketCountLastCheck = this.closeSocketCount;
this.errorSocketCountLastCheck = this.errorSocketCount;
this.timeoutSocketCountLastCheck = this.timeoutSocketCount;
this.requestCountLastCheck = this.requestCount;
}
return changed;
}
getCurrentStatus() {
return {
createSocketCount: this.createSocketCount,
createSocketErrorCount: this.createSocketErrorCount,
closeSocketCount: this.closeSocketCount,
errorSocketCount: this.errorSocketCount,
timeoutSocketCount: this.timeoutSocketCount,
requestCount: this.requestCount,
freeSockets: inspect(this.freeSockets),
sockets: inspect(this.sockets),
requests: inspect(this.requests),
};
}
}
// node 8 don't has timeout attribute on socket
// https://github.com/nodejs/node/pull/21204/files#diff-e6ef024c3775d787c38487a6309e491dR408
function getSocketTimeout(socket) {
return socket.timeout || socket._idleTimeout;
}
function installListeners(agent, socket, options) {
debug('%s create, timeout %sms', socket[SOCKET_NAME], getSocketTimeout(socket));
// listener socket events: close, timeout, error, free
function onFree() {
// create and socket.emit('free') logic
// https://github.com/nodejs/node/blob/master/lib/_http_agent.js#L311
// no req on the socket, it should be the new socket
if (!socket._httpMessage && socket[SOCKET_REQUEST_COUNT] === 1) return;
socket[SOCKET_REQUEST_FINISHED_COUNT]++;
agent.requestCount++;
debug('%s(requests: %s, finished: %s) free',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT]);
// should reuse on pedding requests?
const name = agent.getName(options);
if (socket.writable && agent.requests[name] && agent.requests[name].length) {
// will be reuse on agent free listener
socket[SOCKET_REQUEST_COUNT]++;
debug('%s(requests: %s, finished: %s) will be reuse on agent free event',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT]);
}
}
socket.on('free', onFree);
function onClose(isError) {
debug('%s(requests: %s, finished: %s) close, isError: %s',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT], isError);
agent.closeSocketCount++;
}
socket.on('close', onClose);
// start socket timeout handler
function onTimeout() {
// onTimeout and emitRequestTimeout(_http_client.js)
// https://github.com/nodejs/node/blob/v12.x/lib/_http_client.js#L711
const listenerCount = socket.listeners('timeout').length;
// node <= 10, default listenerCount is 1, onTimeout
// 11 < node <= 12, default listenerCount is 2, onTimeout and emitRequestTimeout
// node >= 13, default listenerCount is 3, onTimeout,
// onTimeout(https://github.com/nodejs/node/pull/32000/files#diff-5f7fb0850412c6be189faeddea6c5359R333)
// and emitRequestTimeout
const timeout = getSocketTimeout(socket);
const req = socket._httpMessage;
const reqTimeoutListenerCount = req && req.listeners('timeout').length || 0;
debug('%s(requests: %s, finished: %s) timeout after %sms, listeners %s, defaultTimeoutListenerCount %s, hasHttpRequest %s, HttpRequest timeoutListenerCount %s',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT],
timeout, listenerCount, defaultTimeoutListenerCount, !!req, reqTimeoutListenerCount);
if (debug.enabled) {
debug('timeout listeners: %s', socket.listeners('timeout').map(f => f.name).join(', '));
}
agent.timeoutSocketCount++;
const name = agent.getName(options);
if (agent.freeSockets[name] && agent.freeSockets[name].indexOf(socket) !== -1) {
// free socket timeout, destroy quietly
socket.destroy();
// Remove it from freeSockets list immediately to prevent new requests
// from being sent through this socket.
agent.removeSocket(socket, options);
debug('%s is free, destroy quietly', socket[SOCKET_NAME]);
} else {
// if there is no any request socket timeout handler,
// agent need to handle socket timeout itself.
//
// custom request socket timeout handle logic must follow these rules:
// 1. Destroy socket first
// 2. Must emit socket 'agentRemove' event tell agent remove socket
// from freeSockets list immediately.
// Otherise you may be get 'socket hang up' error when reuse
// free socket and timeout happen in the same time.
if (reqTimeoutListenerCount === 0) {
const error = new Error('Socket timeout');
error.code = 'ERR_SOCKET_TIMEOUT';
error.timeout = timeout;
// must manually call socket.end() or socket.destroy() to end the connection.
// https://nodejs.org/dist/latest-v10.x/docs/api/net.html#net_socket_settimeout_timeout_callback
socket.destroy(error);
agent.removeSocket(socket, options);
debug('%s destroy with timeout error', socket[SOCKET_NAME]);
}
}
}
socket.on('timeout', onTimeout);
function onError(err) {
const listenerCount = socket.listeners('error').length;
debug('%s(requests: %s, finished: %s) error: %s, listenerCount: %s',
socket[SOCKET_NAME], socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT],
err, listenerCount);
agent.errorSocketCount++;
if (listenerCount === 1) {
// if socket don't contain error event handler, don't catch it, emit it again
debug('%s emit uncaught error event', socket[SOCKET_NAME]);
socket.removeListener('error', onError);
socket.emit('error', err);
}
}
socket.on('error', onError);
function onRemove() {
debug('%s(requests: %s, finished: %s) agentRemove',
socket[SOCKET_NAME],
socket[SOCKET_REQUEST_COUNT], socket[SOCKET_REQUEST_FINISHED_COUNT]);
// We need this function for cases like HTTP 'upgrade'
// (defined by WebSockets) where we need to remove a socket from the
// pool because it'll be locked up indefinitely
socket.removeListener('close', onClose);
socket.removeListener('error', onError);
socket.removeListener('free', onFree);
socket.removeListener('timeout', onTimeout);
socket.removeListener('agentRemove', onRemove);
}
socket.on('agentRemove', onRemove);
}
agent = Agent;
function inspect(obj) {
const res = {};
for (const key in obj) {
res[key] = obj[key].length;
}
return res;
}
return agent;
}
var https_agent;
var hasRequiredHttps_agent;
function requireHttps_agent () {
if (hasRequiredHttps_agent) return https_agent;
hasRequiredHttps_agent = 1;
const OriginalHttpsAgent = require$$0__default$2.default.Agent;
const HttpAgent = /*@__PURE__*/ requireAgent();
const {
INIT_SOCKET,
CREATE_HTTPS_CONNECTION,
} = /*@__PURE__*/ requireConstants();
class HttpsAgent extends HttpAgent {
constructor(options) {
super(options);
this.defaultPort = 443;
this.protocol = 'https:';
this.maxCachedSessions = this.options.maxCachedSessions;
/* istanbul ignore next */
if (this.maxCachedSessions === undefined) {
this.maxCachedSessions = 100;
}
this._sessionCache = {
map: {},
list: [],
};
}
createConnection(options, oncreate) {
const socket = this[CREATE_HTTPS_CONNECTION](options, oncreate);
this[INIT_SOCKET](socket, options);
return socket;
}
}
// https://github.com/nodejs/node/blob/master/lib/https.js#L89
HttpsAgent.prototype[CREATE_HTTPS_CONNECTION] = OriginalHttpsAgent.prototype.createConnection;
[
'getName',
'_getSession',
'_cacheSession',
// https://github.com/nodejs/node/pull/4982
'_evictSession',
].forEach(function(method) {
/* istanbul ignore next */
if (typeof OriginalHttpsAgent.prototype[method] === 'function') {
HttpsAgent.prototype[method] = OriginalHttpsAgent.prototype[method];
}
});
https_agent = HttpsAgent;
return https_agent;
}
var hasRequiredAgentkeepalive;
function requireAgentkeepalive () {
if (hasRequiredAgentkeepalive) return agentkeepalive.exports;
hasRequiredAgentkeepalive = 1;
agentkeepalive.exports = /*@__PURE__*/ requireAgent();
agentkeepalive.exports.HttpsAgent = /*@__PURE__*/ requireHttps_agent();
agentkeepalive.exports.constants = /*@__PURE__*/ requireConstants();
return agentkeepalive.exports;
}
var agentkeepaliveExports = /*@__PURE__*/ requireAgentkeepalive();
var HttpKeepAliveAgent = /*@__PURE__*/getDefaultExportFromCjs(agentkeepaliveExports);
var fastStableStringify$1;
var hasRequiredFastStableStringify;
function requireFastStableStringify () {
if (hasRequiredFastStableStringify) return fastStableStringify$1;
hasRequiredFastStableStringify = 1;
var objToString = Object.prototype.toString;
var objKeys = Object.keys || function(obj) {
var keys = [];
for (var name in obj) {
keys.push(name);
}
return keys;
};
function stringify(val, isArrayProp) {
var i, max, str, keys, key, propVal, toStr;
if (val === true) {
return "true";
}
if (val === false) {
return "false";
}
switch (typeof val) {
case "object":
if (val === null) {
return null;
} else if (val.toJSON && typeof val.toJSON === "function") {
return stringify(val.toJSON(), isArrayProp);
} else {
toStr = objToString.call(val);
if (toStr === "[object Array]") {
str = '[';
max = val.length - 1;
for(i = 0; i < max; i++) {
str += stringify(val[i], true) + ',';
}
if (max > -1) {
str += stringify(val[i], true);
}
return str + ']';
} else if (toStr === "[object Object]") {
// only object is left
keys = objKeys(val).sort();
max = keys.length;
str = "";
i = 0;
while (i < max) {
key = keys[i];
propVal = stringify(val[key], false);
if (propVal !== undefined) {
if (str) {
str += ',';
}
str += JSON.stringify(key) + ':' + propVal;
}
i++;
}
return '{' + str + '}';
} else {
return JSON.stringify(val);
}
}
case "function":
case "undefined":
return isArrayProp ? null : undefined;
case "string":
return JSON.stringify(val);
default:
return isFinite(val) ? val : null;
}
}
fastStableStringify$1 = function(val) {
var returnVal = stringify(val, false);
if (returnVal !== undefined) {
return ''+ returnVal;
}
};
return fastStableStringify$1;
}
var fastStableStringifyExports = /*@__PURE__*/ requireFastStableStringify();
var fastStableStringify = /*@__PURE__*/getDefaultExportFromCjs(fastStableStringifyExports);
const MINIMUM_SLOT_PER_EPOCH = 32;
// Returns the number of trailing zeros in the binary representation of self.
function trailingZeros(n) {
let trailingZeros = 0;
while (n > 1) {
n /= 2;
trailingZeros++;
}
return trailingZeros;
}
// Returns the smallest power of two greater than or equal to n
function nextPowerOfTwo(n) {
if (n === 0) return 1;
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n + 1;
}
/**
* Epoch schedule
* (see https://docs.solana.com/terminology#epoch)
* Can be retrieved with the {@link Connection.getEpochSchedule} method
*/
class EpochSchedule {
constructor(slotsPerEpoch, leaderScheduleSlotOffset, warmup, firstNormalEpoch, firstNormalSlot) {
/** The maximum number of slots in each epoch */
this.slotsPerEpoch = void 0;
/** The number of slots before beginning of an epoch to calculate a leader schedule for that epoch */
this.leaderScheduleSlotOffset = void 0;
/** Indicates whether epochs start short and grow */
this.warmup = void 0;
/** The first epoch with `slotsPerEpoch` slots */
this.firstNormalEpoch = void 0;
/** The first slot of `firstNormalEpoch` */
this.firstNormalSlot = void 0;
this.slotsPerEpoch = slotsPerEpoch;
this.leaderScheduleSlotOffset = leaderScheduleSlotOffset;
this.warmup = warmup;
this.firstNormalEpoch = firstNormalEpoch;
this.firstNormalSlot = firstNormalSlot;
}
getEpoch(slot) {
return this.getEpochAndSlotIndex(slot)[0];
}
getEpochAndSlotIndex(slot) {
if (slot < this.firstNormalSlot) {
const epoch = trailingZeros(nextPowerOfTwo(slot + MINIMUM_SLOT_PER_EPOCH + 1)) - trailingZeros(MINIMUM_SLOT_PER_EPOCH) - 1;
const epochLen = this.getSlotsInEpoch(epoch);
const slotIndex = slot - (epochLen - MINIMUM_SLOT_PER_EPOCH);
return [epoch, slotIndex];
} else {
const normalSlotIndex = slot - this.firstNormalSlot;
const normalEpochIndex = Math.floor(normalSlotIndex / this.slotsPerEpoch);
const epoch = this.firstNormalEpoch + normalEpochIndex;
const slotIndex = normalSlotIndex % this.slotsPerEpoch;
return [epoch, slotIndex];
}
}
getFirstSlotInEpoch(epoch) {
if (epoch <= this.firstNormalEpoch) {
return (Math.pow(2, epoch) - 1) * MINIMUM_SLOT_PER_EPOCH;
} else {
return (epoch - this.firstNormalEpoch) * this.slotsPerEpoch + this.firstNormalSlot;
}
}
getLastSlotInEpoch(epoch) {
return this.getFirstSlotInEpoch(epoch) + this.getSlotsInEpoch(epoch) - 1;
}
getSlotsInEpoch(epoch) {
if (epoch < this.firstNormalEpoch) {
return Math.pow(2, epoch + trailingZeros(MINIMUM_SLOT_PER_EPOCH));
} else {
return this.slotsPerEpoch;
}
}
}
var fetchImpl = typeof globalThis.fetch === 'function' ?
// The Fetch API is supported experimentally in Node 17.5+ and natively in Node 18+.
globalThis.fetch :
// Otherwise use the polyfill.
async function (input, init) {
const processedInput = typeof input === 'string' && input.slice(0, 2) === '//' ? 'https:' + input : input;
return await nodeFetch__namespace.default(processedInput, init);
};
class RpcWebSocketClient extends rpcWebsockets.CommonClient {
constructor(address, options, generate_request_id) {
const webSocketFactory = url => {
const rpc = rpcWebsockets.WebSocket(url, {
autoconnect: true,
max_reconnects: 5,
reconnect: true,
reconnect_interval: 1000,
...options
});
if ('socket' in rpc) {
this.underlyingSocket = rpc.socket;
} else {
this.underlyingSocket = rpc;
}
return rpc;
};
super(webSocketFactory, address, options, generate_request_id);
this.underlyingSocket = void 0;
}
call(...args) {
const readyState = this.underlyingSocket?.readyState;
if (readyState === 1 /* WebSocket.OPEN */) {
return super.call(...args);
}
return Promise.reject(new Error('Tried to call a JSON-RPC method `' + args[0] + '` but the socket was not `CONNECTING` or `OPEN` (`readyState` was ' + readyState + ')'));
}
notify(...args) {
const readyState = this.underlyingSocket?.readyState;
if (readyState === 1 /* WebSocket.OPEN */) {
return super.notify(...args);
}
return Promise.reject(new Error('Tried to send a JSON-RPC notification `' + args[0] + '` but the socket was not `CONNECTING` or `OPEN` (`readyState` was ' + readyState + ')'));
}
}
/**
* @internal
*/
/**
* Decode account data buffer using an AccountType
* @internal
*/
function decodeData(type, data) {
let decoded;
try {
decoded = type.layout.decode(data);
} catch (err) {
throw new Error('invalid instruction; ' + err);
}
if (decoded.typeIndex !== type.index) {
throw new Error(`invalid account data; account type mismatch ${decoded.typeIndex} != ${type.index}`);
}
return decoded;
}
/// The serialized size of lookup table metadata
const LOOKUP_TABLE_META_SIZE = 56;
class AddressLookupTableAccount {
constructor(args) {
this.key = void 0;
this.state = void 0;
this.key = args.key;
this.state = args.state;
}
isActive() {
const U64_MAX = BigInt('0xffffffffffffffff');
return this.state.deactivationSlot === U64_MAX;
}
static deserialize(accountData) {
const meta = decodeData(LookupTableMetaLayout, accountData);
const serializedAddressesLen = accountData.length - LOOKUP_TABLE_META_SIZE;
assert(serializedAddressesLen >= 0, 'lookup table is invalid');
assert(serializedAddressesLen % 32 === 0, 'lookup table is invalid');
const numSerializedAddresses = serializedAddressesLen / 32;
const {
addresses
} = BufferLayout__namespace.struct([BufferLayout__namespace.seq(publicKey(), numSerializedAddresses, 'addresses')]).decode(accountData.slice(LOOKUP_TABLE_META_SIZE));
return {
deactivationSlot: meta.deactivationSlot,
lastExtendedSlot: meta.lastExtendedSlot,
lastExtendedSlotStartIndex: meta.lastExtendedStartIndex,
authority: meta.authority.length !== 0 ? new PublicKey(meta.authority[0]) : undefined,
addresses: addresses.map(address => new PublicKey(address))
};
}
}
const LookupTableMetaLayout = {
index: 1,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('typeIndex'), u64('deactivationSlot'), BufferLayout__namespace.nu64('lastExtendedSlot'), BufferLayout__namespace.u8('lastExtendedStartIndex'), BufferLayout__namespace.u8(),
// option
BufferLayout__namespace.seq(publicKey(), BufferLayout__namespace.offset(BufferLayout__namespace.u8(), -1), 'authority')])
};
const URL_RE = /^[^:]+:\/\/([^:[]+|\[[^\]]+\])(:\d+)?(.*)/i;
function makeWebsocketUrl(endpoint) {
const matches = endpoint.match(URL_RE);
if (matches == null) {
throw TypeError(`Failed to validate endpoint URL \`${endpoint}\``);
}
const [_,
// eslint-disable-line @typescript-eslint/no-unused-vars
hostish, portWithColon, rest] = matches;
const protocol = endpoint.startsWith('https:') ? 'wss:' : 'ws:';
const startPort = portWithColon == null ? null : parseInt(portWithColon.slice(1), 10);
const websocketPort =
// Only shift the port by +1 as a convention for ws(s) only if given endpoint
// is explicitly specifying the endpoint port (HTTP-based RPC), assuming
// we're directly trying to connect to agave-validator's ws listening port.
// When the endpoint omits the port, we're connecting to the protocol
// default ports: http(80) or https(443) and it's assumed we're behind a reverse
// proxy which manages WebSocket upgrade and backend port redirection.
startPort == null ? '' : `:${startPort + 1}`;
return `${protocol}//${hostish}${websocketPort}${rest}`;
}
const PublicKeyFromString = superstruct.coerce(superstruct.instance(PublicKey), superstruct.string(), value => new PublicKey(value));
const RawAccountDataResult = superstruct.tuple([superstruct.string(), superstruct.literal('base64')]);
const BufferFromRawAccountData = superstruct.coerce(superstruct.instance(buffer.Buffer), RawAccountDataResult, value => buffer.Buffer.from(value[0], 'base64'));
/**
* Attempt to use a recent blockhash for up to 30 seconds
* @internal
*/
const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000;
/**
* HACK.
* Copied from rpc-websockets/dist/lib/client.
* Otherwise, `yarn build` fails with:
* https://gist.github.com/steveluscher/c057eca81d479ef705cdb53162f9971d
*/
/** @internal */
/** @internal */
/** @internal */
/** @internal */
/** @internal */
/**
* @internal
* Every subscription contains the args used to open the subscription with
* the server, and a list of callers interested in notifications.
*/
/**
* @internal
* A subscription may be in various states of connectedness. Only when it is
* fully connected will it have a server subscription id associated with it.
* This id can be returned to the server to unsubscribe the client entirely.
*/
/**
* A type that encapsulates a subscription's RPC method
* names and notification (callback) signature.
*/
/**
* @internal
* Utility type that keeps tagged unions intact while omitting properties.
*/
/**
* @internal
* This type represents a single subscribable 'topic.' It's made up of:
*
* - The args used to open the subscription with the server,
* - The state of the subscription, in terms of its connectedness, and
* - The set of callbacks to call when the server publishes notifications
*
* This record gets indexed by `SubscriptionConfigHash` and is used to
* set up subscriptions, fan out notifications, and track subscription state.
*/
/**
* @internal
*/
/**
* Extra contextual information for RPC responses
*/
/**
* Options for sending transactions
*/
/**
* Options for confirming transactions
*/
/**
* Options for getConfirmedSignaturesForAddress2
*/
/**
* Options for getSignaturesForAddress
*/
/**
* RPC Response with extra contextual information
*/
/**
* A strategy for confirming transactions that uses the last valid
* block height for a given blockhash to check for transaction expiration.
*/
/**
* A strategy for confirming durable nonce transactions.
*/
/**
* Properties shared by all transaction confirmation strategies
*/
/**
* This type represents all transaction confirmation strategies
*/
/* @internal */
function assertEndpointUrl(putativeUrl) {
if (/^https?:/.test(putativeUrl) === false) {
throw new TypeError('Endpoint URL must start with `http:` or `https:`.');
}
return putativeUrl;
}
/** @internal */
function extractCommitmentFromConfig(commitmentOrConfig) {
let commitment;
let config;
if (typeof commitmentOrConfig === 'string') {
commitment = commitmentOrConfig;
} else if (commitmentOrConfig) {
const {
commitment: specifiedCommitment,
...specifiedConfig
} = commitmentOrConfig;
commitment = specifiedCommitment;
config = specifiedConfig;
}
return {
commitment,
config
};
}
/**
* @internal
*/
function applyDefaultMemcmpEncodingToFilters(filters) {
return filters.map(filter => 'memcmp' in filter ? {
...filter,
memcmp: {
...filter.memcmp,
encoding: filter.memcmp.encoding ?? 'base58'
}
} : filter);
}
/**
* @internal
*/
function createRpcResult(result) {
return superstruct.union([superstruct.type({
jsonrpc: superstruct.literal('2.0'),
id: superstruct.string(),
result
}), superstruct.type({
jsonrpc: superstruct.literal('2.0'),
id: superstruct.string(),
error: superstruct.type({
code: superstruct.unknown(),
message: superstruct.string(),
data: superstruct.optional(superstruct.any())
})
})]);
}
const UnknownRpcResult = createRpcResult(superstruct.unknown());
/**
* @internal
*/
function jsonRpcResult(schema) {
return superstruct.coerce(createRpcResult(schema), UnknownRpcResult, value => {
if ('error' in value) {
return value;
} else {
return {
...value,
result: superstruct.create(value.result, schema)
};
}
});
}
/**
* @internal
*/
function jsonRpcResultAndContext(value) {
return jsonRpcResult(superstruct.type({
context: superstruct.type({
slot: superstruct.number()
}),
value
}));
}
/**
* @internal
*/
function notificationResultAndContext(value) {
return superstruct.type({
context: superstruct.type({
slot: superstruct.number()
}),
value
});
}
/**
* @internal
*/
function versionedMessageFromResponse(version, response) {
if (version === 0) {
return new MessageV0({
header: response.header,
staticAccountKeys: response.accountKeys.map(accountKey => new PublicKey(accountKey)),
recentBlockhash: response.recentBlockhash,
compiledInstructions: response.instructions.map(ix => ({
programIdIndex: ix.programIdIndex,
accountKeyIndexes: ix.accounts,
data: bs58__default.default.decode(ix.data)
})),
addressTableLookups: response.addressTableLookups
});
} else {
return new Message(response);
}
}
/**
* The level of commitment desired when querying state
* <pre>
* 'processed': Query the most recent block which has reached 1 confirmation by the connected node
* 'confirmed': Query the most recent block which has reached 1 confirmation by the cluster
* 'finalized': Query the most recent block which has been finalized by the cluster
* </pre>
*/
// Deprecated as of v1.5.5
/**
* A subset of Commitment levels, which are at least optimistically confirmed
* <pre>
* 'confirmed': Query the most recent block which has reached 1 confirmation by the cluster
* 'finalized': Query the most recent block which has been finalized by the cluster
* </pre>
*/
/**
* Filter for largest accounts query
* <pre>
* 'circulating': Return the largest accounts that are part of the circulating supply
* 'nonCirculating': Return the largest accounts that are not part of the circulating supply
* </pre>
*/
/**
* Configuration object for changing `getAccountInfo` query behavior
*/
/**
* Configuration object for changing `getBalance` query behavior
*/
/**
* Configuration object for changing `getBlock` query behavior
*/
/**
* Configuration object for changing `getBlock` query behavior
*/
/**
* Configuration object for changing `getStakeMinimumDelegation` query behavior
*/
/**
* Configuration object for changing `getBlockHeight` query behavior
*/
/**
* Configuration object for changing `getEpochInfo` query behavior
*/
/**
* Configuration object for changing `getInflationReward` query behavior
*/
/**
* Configuration object for changing `getLatestBlockhash` query behavior
*/
/**
* Configuration object for changing `isBlockhashValid` query behavior
*/
/**
* Configuration object for changing `getSlot` query behavior
*/
/**
* Configuration object for changing `getSlotLeader` query behavior
*/
/**
* Configuration object for changing `getTransaction` query behavior
*/
/**
* Configuration object for changing `getTransaction` query behavior
*/
/**
* Configuration object for changing `getLargestAccounts` query behavior
*/
/**
* Configuration object for changing `getSupply` request behavior
*/
/**
* Configuration object for changing query behavior
*/
/**
* Information describing a cluster node
*/
/**
* Information describing a vote account
*/
/**
* A collection of cluster vote accounts
*/
/**
* Network Inflation
* (see https://docs.solana.com/implemented-proposals/ed_overview)
*/
const GetInflationGovernorResult = superstruct.type({
foundation: superstruct.number(),
foundationTerm: superstruct.number(),
initial: superstruct.number(),
taper: superstruct.number(),
terminal: superstruct.number()
});
/**
* The inflation reward for an epoch
*/
/**
* Expected JSON RPC response for the "getInflationReward" message
*/
const GetInflationRewardResult = jsonRpcResult(superstruct.array(superstruct.nullable(superstruct.type({
epoch: superstruct.number(),
effectiveSlot: superstruct.number(),
amount: superstruct.number(),
postBalance: superstruct.number(),
commission: superstruct.optional(superstruct.nullable(superstruct.number()))
}))));
/**
* Configuration object for changing `getRecentPrioritizationFees` query behavior
*/
/**
* Expected JSON RPC response for the "getRecentPrioritizationFees" message
*/
const GetRecentPrioritizationFeesResult = superstruct.array(superstruct.type({
slot: superstruct.number(),
prioritizationFee: superstruct.number()
}));
/**
* Expected JSON RPC response for the "getInflationRate" message
*/
const GetInflationRateResult = superstruct.type({
total: superstruct.number(),
validator: superstruct.number(),
foundation: superstruct.number(),
epoch: superstruct.number()
});
/**
* Information about the current epoch
*/
const GetEpochInfoResult = superstruct.type({
epoch: superstruct.number(),
slotIndex: superstruct.number(),
slotsInEpoch: superstruct.number(),
absoluteSlot: superstruct.number(),
blockHeight: superstruct.optional(superstruct.number()),
transactionCount: superstruct.optional(superstruct.number())
});
const GetEpochScheduleResult = superstruct.type({
slotsPerEpoch: superstruct.number(),
leaderScheduleSlotOffset: superstruct.number(),
warmup: superstruct.boolean(),
firstNormalEpoch: superstruct.number(),
firstNormalSlot: superstruct.number()
});
/**
* Leader schedule
* (see https://docs.solana.com/terminology#leader-schedule)
*/
const GetLeaderScheduleResult = superstruct.record(superstruct.string(), superstruct.array(superstruct.number()));
/**
* Transaction error or null
*/
const TransactionErrorResult = superstruct.nullable(superstruct.union([superstruct.type({}), superstruct.string()]));
/**
* Signature status for a transaction
*/
const SignatureStatusResult = superstruct.type({
err: TransactionErrorResult
});
/**
* Transaction signature received notification
*/
const SignatureReceivedResult = superstruct.literal('receivedSignature');
/**
* Version info for a node
*/
const VersionResult = superstruct.type({
'solana-core': superstruct.string(),
'feature-set': superstruct.optional(superstruct.number())
});
const ParsedInstructionStruct = superstruct.type({
program: superstruct.string(),
programId: PublicKeyFromString,
parsed: superstruct.unknown()
});
const PartiallyDecodedInstructionStruct = superstruct.type({
programId: PublicKeyFromString,
accounts: superstruct.array(PublicKeyFromString),
data: superstruct.string()
});
const SimulatedTransactionResponseStruct = jsonRpcResultAndContext(superstruct.type({
err: superstruct.nullable(superstruct.union([superstruct.type({}), superstruct.string()])),
logs: superstruct.nullable(superstruct.array(superstruct.string())),
accounts: superstruct.optional(superstruct.nullable(superstruct.array(superstruct.nullable(superstruct.type({
executable: superstruct.boolean(),
owner: superstruct.string(),
lamports: superstruct.number(),
data: superstruct.array(superstruct.string()),
rentEpoch: superstruct.optional(superstruct.number())
}))))),
unitsConsumed: superstruct.optional(superstruct.number()),
returnData: superstruct.optional(superstruct.nullable(superstruct.type({
programId: superstruct.string(),
data: superstruct.tuple([superstruct.string(), superstruct.literal('base64')])
}))),
innerInstructions: superstruct.optional(superstruct.nullable(superstruct.array(superstruct.type({
index: superstruct.number(),
instructions: superstruct.array(superstruct.union([ParsedInstructionStruct, PartiallyDecodedInstructionStruct]))
}))))
}));
/**
* Metadata for a parsed confirmed transaction on the ledger
*
* @deprecated Deprecated since RPC v1.8.0. Please use {@link ParsedTransactionMeta} instead.
*/
/**
* Collection of addresses loaded by a transaction using address table lookups
*/
/**
* Metadata for a parsed transaction on the ledger
*/
/**
* Metadata for a confirmed transaction on the ledger
*/
/**
* A processed transaction from the RPC API
*/
/**
* A processed transaction from the RPC API
*/
/**
* A processed transaction message from the RPC API
*/
/**
* A confirmed transaction on the ledger
*
* @deprecated Deprecated since RPC v1.8.0.
*/
/**
* A partially decoded transaction instruction
*/
/**
* A parsed transaction message account
*/
/**
* A parsed transaction instruction
*/
/**
* A parsed address table lookup
*/
/**
* A parsed transaction message
*/
/**
* A parsed transaction
*/
/**
* A parsed and confirmed transaction on the ledger
*
* @deprecated Deprecated since RPC v1.8.0. Please use {@link ParsedTransactionWithMeta} instead.
*/
/**
* A parsed transaction on the ledger with meta
*/
/**
* A processed block fetched from the RPC API
*/
/**
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
*/
/**
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
*/
/**
* A block with parsed transactions
*/
/**
* A block with parsed transactions where the `transactionDetails` mode is `accounts`
*/
/**
* A block with parsed transactions where the `transactionDetails` mode is `none`
*/
/**
* A processed block fetched from the RPC API
*/
/**
* A processed block fetched from the RPC API where the `transactionDetails` mode is `accounts`
*/
/**
* A processed block fetched from the RPC API where the `transactionDetails` mode is `none`
*/
/**
* A confirmed block on the ledger
*
* @deprecated Deprecated since RPC v1.8.0.
*/
/**
* A Block on the ledger with signatures only
*/
/**
* recent block production information
*/
/**
* Expected JSON RPC response for the "getBlockProduction" message
*/
const BlockProductionResponseStruct = jsonRpcResultAndContext(superstruct.type({
byIdentity: superstruct.record(superstruct.string(), superstruct.array(superstruct.number())),
range: superstruct.type({
firstSlot: superstruct.number(),
lastSlot: superstruct.number()
})
}));
/**
* A performance sample
*/
function createRpcClient(url, httpHeaders, customFetch, fetchMiddleware, disableRetryOnRateLimit, httpAgent) {
const fetch = customFetch ? customFetch : fetchImpl;
let agent;
{
if (httpAgent == null) {
{
const agentOptions = {
// One second fewer than the Solana RPC's keepalive timeout.
// Read more: https://github.com/solana-labs/solana/issues/27859#issuecomment-1340097889
freeSocketTimeout: 19000,
keepAlive: true,
maxSockets: 25
};
if (url.startsWith('https:')) {
agent = new agentkeepaliveExports.HttpsAgent(agentOptions);
} else {
agent = new HttpKeepAliveAgent(agentOptions);
}
}
} else {
if (httpAgent !== false) {
const isHttps = url.startsWith('https:');
if (isHttps && !(httpAgent instanceof require$$0$2.Agent)) {
throw new Error('The endpoint `' + url + '` can only be paired with an `https.Agent`. You have, instead, supplied an ' + '`http.Agent` through `httpAgent`.');
} else if (!isHttps && httpAgent instanceof require$$0$2.Agent) {
throw new Error('The endpoint `' + url + '` can only be paired with an `http.Agent`. You have, instead, supplied an ' + '`https.Agent` through `httpAgent`.');
}
agent = httpAgent;
}
}
}
let fetchWithMiddleware;
if (fetchMiddleware) {
fetchWithMiddleware = async (info, init) => {
const modifiedFetchArgs = await new Promise((resolve, reject) => {
try {
fetchMiddleware(info, init, (modifiedInfo, modifiedInit) => resolve([modifiedInfo, modifiedInit]));
} catch (error) {
reject(error);
}
});
return await fetch(...modifiedFetchArgs);
};
}
const clientBrowser = new RpcClient__default.default(async (request, callback) => {
const options = {
method: 'POST',
body: request,
agent,
headers: Object.assign({
'Content-Type': 'application/json'
}, httpHeaders || {}, COMMON_HTTP_HEADERS)
};
try {
let too_many_requests_retries = 5;
let res;
let waitTime = 500;
for (;;) {
if (fetchWithMiddleware) {
res = await fetchWithMiddleware(url, options);
} else {
res = await fetch(url, options);
}
if (res.status !== 429 /* Too many requests */) {
break;
}
if (disableRetryOnRateLimit === true) {
break;
}
too_many_requests_retries -= 1;
if (too_many_requests_retries === 0) {
break;
}
console.error(`Server responded with ${res.status} ${res.statusText}. Retrying after ${waitTime}ms delay...`);
await sleep(waitTime);
waitTime *= 2;
}
const text = await res.text();
if (res.ok) {
callback(null, text);
} else {
callback(new Error(`${res.status} ${res.statusText}: ${text}`));
}
} catch (err) {
if (err instanceof Error) callback(err);
}
}, {});
return clientBrowser;
}
function createRpcRequest(client) {
return (method, args) => {
return new Promise((resolve, reject) => {
client.request(method, args, (err, response) => {
if (err) {
reject(err);
return;
}
resolve(response);
});
});
};
}
function createRpcBatchRequest(client) {
return requests => {
return new Promise((resolve, reject) => {
// Do nothing if requests is empty
if (requests.length === 0) resolve([]);
const batch = requests.map(params => {
return client.request(params.methodName, params.args);
});
client.request(batch, (err, response) => {
if (err) {
reject(err);
return;
}
resolve(response);
});
});
};
}
/**
* Expected JSON RPC response for the "getInflationGovernor" message
*/
const GetInflationGovernorRpcResult = jsonRpcResult(GetInflationGovernorResult);
/**
* Expected JSON RPC response for the "getInflationRate" message
*/
const GetInflationRateRpcResult = jsonRpcResult(GetInflationRateResult);
/**
* Expected JSON RPC response for the "getRecentPrioritizationFees" message
*/
const GetRecentPrioritizationFeesRpcResult = jsonRpcResult(GetRecentPrioritizationFeesResult);
/**
* Expected JSON RPC response for the "getEpochInfo" message
*/
const GetEpochInfoRpcResult = jsonRpcResult(GetEpochInfoResult);
/**
* Expected JSON RPC response for the "getEpochSchedule" message
*/
const GetEpochScheduleRpcResult = jsonRpcResult(GetEpochScheduleResult);
/**
* Expected JSON RPC response for the "getLeaderSchedule" message
*/
const GetLeaderScheduleRpcResult = jsonRpcResult(GetLeaderScheduleResult);
/**
* Expected JSON RPC response for the "minimumLedgerSlot" and "getFirstAvailableBlock" messages
*/
const SlotRpcResult = jsonRpcResult(superstruct.number());
/**
* Supply
*/
/**
* Expected JSON RPC response for the "getSupply" message
*/
const GetSupplyRpcResult = jsonRpcResultAndContext(superstruct.type({
total: superstruct.number(),
circulating: superstruct.number(),
nonCirculating: superstruct.number(),
nonCirculatingAccounts: superstruct.array(PublicKeyFromString)
}));
/**
* Token amount object which returns a token amount in different formats
* for various client use cases.
*/
/**
* Expected JSON RPC structure for token amounts
*/
const TokenAmountResult = superstruct.type({
amount: superstruct.string(),
uiAmount: superstruct.nullable(superstruct.number()),
decimals: superstruct.number(),
uiAmountString: superstruct.optional(superstruct.string())
});
/**
* Token address and balance.
*/
/**
* Expected JSON RPC response for the "getTokenLargestAccounts" message
*/
const GetTokenLargestAccountsResult = jsonRpcResultAndContext(superstruct.array(superstruct.type({
address: PublicKeyFromString,
amount: superstruct.string(),
uiAmount: superstruct.nullable(superstruct.number()),
decimals: superstruct.number(),
uiAmountString: superstruct.optional(superstruct.string())
})));
/**
* Expected JSON RPC response for the "getTokenAccountsByOwner" message
*/
const GetTokenAccountsByOwner = jsonRpcResultAndContext(superstruct.array(superstruct.type({
pubkey: PublicKeyFromString,
account: superstruct.type({
executable: superstruct.boolean(),
owner: PublicKeyFromString,
lamports: superstruct.number(),
data: BufferFromRawAccountData,
rentEpoch: superstruct.number()
})
})));
const ParsedAccountDataResult = superstruct.type({
program: superstruct.string(),
parsed: superstruct.unknown(),
space: superstruct.number()
});
/**
* Expected JSON RPC response for the "getTokenAccountsByOwner" message with parsed data
*/
const GetParsedTokenAccountsByOwner = jsonRpcResultAndContext(superstruct.array(superstruct.type({
pubkey: PublicKeyFromString,
account: superstruct.type({
executable: superstruct.boolean(),
owner: PublicKeyFromString,
lamports: superstruct.number(),
data: ParsedAccountDataResult,
rentEpoch: superstruct.number()
})
})));
/**
* Pair of an account address and its balance
*/
/**
* Expected JSON RPC response for the "getLargestAccounts" message
*/
const GetLargestAccountsRpcResult = jsonRpcResultAndContext(superstruct.array(superstruct.type({
lamports: superstruct.number(),
address: PublicKeyFromString
})));
/**
* @internal
*/
const AccountInfoResult = superstruct.type({
executable: superstruct.boolean(),
owner: PublicKeyFromString,
lamports: superstruct.number(),
data: BufferFromRawAccountData,
rentEpoch: superstruct.number()
});
/**
* @internal
*/
const KeyedAccountInfoResult = superstruct.type({
pubkey: PublicKeyFromString,
account: AccountInfoResult
});
const ParsedOrRawAccountData = superstruct.coerce(superstruct.union([superstruct.instance(buffer.Buffer), ParsedAccountDataResult]), superstruct.union([RawAccountDataResult, ParsedAccountDataResult]), value => {
if (Array.isArray(value)) {
return superstruct.create(value, BufferFromRawAccountData);
} else {
return value;
}
});
/**
* @internal
*/
const ParsedAccountInfoResult = superstruct.type({
executable: superstruct.boolean(),
owner: PublicKeyFromString,
lamports: superstruct.number(),
data: ParsedOrRawAccountData,
rentEpoch: superstruct.number()
});
const KeyedParsedAccountInfoResult = superstruct.type({
pubkey: PublicKeyFromString,
account: ParsedAccountInfoResult
});
/**
* @internal
*/
const StakeActivationResult = superstruct.type({
state: superstruct.union([superstruct.literal('active'), superstruct.literal('inactive'), superstruct.literal('activating'), superstruct.literal('deactivating')]),
active: superstruct.number(),
inactive: superstruct.number()
});
/**
* Expected JSON RPC response for the "getConfirmedSignaturesForAddress2" message
*/
const GetConfirmedSignaturesForAddress2RpcResult = jsonRpcResult(superstruct.array(superstruct.type({
signature: superstruct.string(),
slot: superstruct.number(),
err: TransactionErrorResult,
memo: superstruct.nullable(superstruct.string()),
blockTime: superstruct.optional(superstruct.nullable(superstruct.number()))
})));
/**
* Expected JSON RPC response for the "getSignaturesForAddress" message
*/
const GetSignaturesForAddressRpcResult = jsonRpcResult(superstruct.array(superstruct.type({
signature: superstruct.string(),
slot: superstruct.number(),
err: TransactionErrorResult,
memo: superstruct.nullable(superstruct.string()),
blockTime: superstruct.optional(superstruct.nullable(superstruct.number()))
})));
/***
* Expected JSON RPC response for the "accountNotification" message
*/
const AccountNotificationResult = superstruct.type({
subscription: superstruct.number(),
result: notificationResultAndContext(AccountInfoResult)
});
/**
* @internal
*/
const ProgramAccountInfoResult = superstruct.type({
pubkey: PublicKeyFromString,
account: AccountInfoResult
});
/***
* Expected JSON RPC response for the "programNotification" message
*/
const ProgramAccountNotificationResult = superstruct.type({
subscription: superstruct.number(),
result: notificationResultAndContext(ProgramAccountInfoResult)
});
/**
* @internal
*/
const SlotInfoResult = superstruct.type({
parent: superstruct.number(),
slot: superstruct.number(),
root: superstruct.number()
});
/**
* Expected JSON RPC response for the "slotNotification" message
*/
const SlotNotificationResult = superstruct.type({
subscription: superstruct.number(),
result: SlotInfoResult
});
/**
* Slot updates which can be used for tracking the live progress of a cluster.
* - `"firstShredReceived"`: connected node received the first shred of a block.
* Indicates that a new block that is being produced.
* - `"completed"`: connected node has received all shreds of a block. Indicates
* a block was recently produced.
* - `"optimisticConfirmation"`: block was optimistically confirmed by the
* cluster. It is not guaranteed that an optimistic confirmation notification
* will be sent for every finalized blocks.
* - `"root"`: the connected node rooted this block.
* - `"createdBank"`: the connected node has started validating this block.
* - `"frozen"`: the connected node has validated this block.
* - `"dead"`: the connected node failed to validate this block.
*/
/**
* @internal
*/
const SlotUpdateResult = superstruct.union([superstruct.type({
type: superstruct.union([superstruct.literal('firstShredReceived'), superstruct.literal('completed'), superstruct.literal('optimisticConfirmation'), superstruct.literal('root')]),
slot: superstruct.number(),
timestamp: superstruct.number()
}), superstruct.type({
type: superstruct.literal('createdBank'),
parent: superstruct.number(),
slot: superstruct.number(),
timestamp: superstruct.number()
}), superstruct.type({
type: superstruct.literal('frozen'),
slot: superstruct.number(),
timestamp: superstruct.number(),
stats: superstruct.type({
numTransactionEntries: superstruct.number(),
numSuccessfulTransactions: superstruct.number(),
numFailedTransactions: superstruct.number(),
maxTransactionsPerEntry: superstruct.number()
})
}), superstruct.type({
type: superstruct.literal('dead'),
slot: superstruct.number(),
timestamp: superstruct.number(),
err: superstruct.string()
})]);
/**
* Expected JSON RPC response for the "slotsUpdatesNotification" message
*/
const SlotUpdateNotificationResult = superstruct.type({
subscription: superstruct.number(),
result: SlotUpdateResult
});
/**
* Expected JSON RPC response for the "signatureNotification" message
*/
const SignatureNotificationResult = superstruct.type({
subscription: superstruct.number(),
result: notificationResultAndContext(superstruct.union([SignatureStatusResult, SignatureReceivedResult]))
});
/**
* Expected JSON RPC response for the "rootNotification" message
*/
const RootNotificationResult = superstruct.type({
subscription: superstruct.number(),
result: superstruct.number()
});
const ContactInfoResult = superstruct.type({
pubkey: superstruct.string(),
gossip: superstruct.nullable(superstruct.string()),
tpu: superstruct.nullable(superstruct.string()),
rpc: superstruct.nullable(superstruct.string()),
version: superstruct.nullable(superstruct.string())
});
const VoteAccountInfoResult = superstruct.type({
votePubkey: superstruct.string(),
nodePubkey: superstruct.string(),
activatedStake: superstruct.number(),
epochVoteAccount: superstruct.boolean(),
epochCredits: superstruct.array(superstruct.tuple([superstruct.number(), superstruct.number(), superstruct.number()])),
commission: superstruct.number(),
lastVote: superstruct.number(),
rootSlot: superstruct.nullable(superstruct.number())
});
/**
* Expected JSON RPC response for the "getVoteAccounts" message
*/
const GetVoteAccounts = jsonRpcResult(superstruct.type({
current: superstruct.array(VoteAccountInfoResult),
delinquent: superstruct.array(VoteAccountInfoResult)
}));
const ConfirmationStatus = superstruct.union([superstruct.literal('processed'), superstruct.literal('confirmed'), superstruct.literal('finalized')]);
const SignatureStatusResponse = superstruct.type({
slot: superstruct.number(),
confirmations: superstruct.nullable(superstruct.number()),
err: TransactionErrorResult,
confirmationStatus: superstruct.optional(ConfirmationStatus)
});
/**
* Expected JSON RPC response for the "getSignatureStatuses" message
*/
const GetSignatureStatusesRpcResult = jsonRpcResultAndContext(superstruct.array(superstruct.nullable(SignatureStatusResponse)));
/**
* Expected JSON RPC response for the "getMinimumBalanceForRentExemption" message
*/
const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult(superstruct.number());
const AddressTableLookupStruct = superstruct.type({
accountKey: PublicKeyFromString,
writableIndexes: superstruct.array(superstruct.number()),
readonlyIndexes: superstruct.array(superstruct.number())
});
const ConfirmedTransactionResult = superstruct.type({
signatures: superstruct.array(superstruct.string()),
message: superstruct.type({
accountKeys: superstruct.array(superstruct.string()),
header: superstruct.type({
numRequiredSignatures: superstruct.number(),
numReadonlySignedAccounts: superstruct.number(),
numReadonlyUnsignedAccounts: superstruct.number()
}),
instructions: superstruct.array(superstruct.type({
accounts: superstruct.array(superstruct.number()),
data: superstruct.string(),
programIdIndex: superstruct.number()
})),
recentBlockhash: superstruct.string(),
addressTableLookups: superstruct.optional(superstruct.array(AddressTableLookupStruct))
})
});
const AnnotatedAccountKey = superstruct.type({
pubkey: PublicKeyFromString,
signer: superstruct.boolean(),
writable: superstruct.boolean(),
source: superstruct.optional(superstruct.union([superstruct.literal('transaction'), superstruct.literal('lookupTable')]))
});
const ConfirmedTransactionAccountsModeResult = superstruct.type({
accountKeys: superstruct.array(AnnotatedAccountKey),
signatures: superstruct.array(superstruct.string())
});
const ParsedInstructionResult = superstruct.type({
parsed: superstruct.unknown(),
program: superstruct.string(),
programId: PublicKeyFromString
});
const RawInstructionResult = superstruct.type({
accounts: superstruct.array(PublicKeyFromString),
data: superstruct.string(),
programId: PublicKeyFromString
});
const InstructionResult = superstruct.union([RawInstructionResult, ParsedInstructionResult]);
const UnknownInstructionResult = superstruct.union([superstruct.type({
parsed: superstruct.unknown(),
program: superstruct.string(),
programId: superstruct.string()
}), superstruct.type({
accounts: superstruct.array(superstruct.string()),
data: superstruct.string(),
programId: superstruct.string()
})]);
const ParsedOrRawInstruction = superstruct.coerce(InstructionResult, UnknownInstructionResult, value => {
if ('accounts' in value) {
return superstruct.create(value, RawInstructionResult);
} else {
return superstruct.create(value, ParsedInstructionResult);
}
});
/**
* @internal
*/
const ParsedConfirmedTransactionResult = superstruct.type({
signatures: superstruct.array(superstruct.string()),
message: superstruct.type({
accountKeys: superstruct.array(AnnotatedAccountKey),
instructions: superstruct.array(ParsedOrRawInstruction),
recentBlockhash: superstruct.string(),
addressTableLookups: superstruct.optional(superstruct.nullable(superstruct.array(AddressTableLookupStruct)))
})
});
const TokenBalanceResult = superstruct.type({
accountIndex: superstruct.number(),
mint: superstruct.string(),
owner: superstruct.optional(superstruct.string()),
programId: superstruct.optional(superstruct.string()),
uiTokenAmount: TokenAmountResult
});
const LoadedAddressesResult = superstruct.type({
writable: superstruct.array(PublicKeyFromString),
readonly: superstruct.array(PublicKeyFromString)
});
/**
* @internal
*/
const ConfirmedTransactionMetaResult = superstruct.type({
err: TransactionErrorResult,
fee: superstruct.number(),
innerInstructions: superstruct.optional(superstruct.nullable(superstruct.array(superstruct.type({
index: superstruct.number(),
instructions: superstruct.array(superstruct.type({
accounts: superstruct.array(superstruct.number()),
data: superstruct.string(),
programIdIndex: superstruct.number()
}))
})))),
preBalances: superstruct.array(superstruct.number()),
postBalances: superstruct.array(superstruct.number()),
logMessages: superstruct.optional(superstruct.nullable(superstruct.array(superstruct.string()))),
preTokenBalances: superstruct.optional(superstruct.nullable(superstruct.array(TokenBalanceResult))),
postTokenBalances: superstruct.optional(superstruct.nullable(superstruct.array(TokenBalanceResult))),
loadedAddresses: superstruct.optional(LoadedAddressesResult),
computeUnitsConsumed: superstruct.optional(superstruct.number())
});
/**
* @internal
*/
const ParsedConfirmedTransactionMetaResult = superstruct.type({
err: TransactionErrorResult,
fee: superstruct.number(),
innerInstructions: superstruct.optional(superstruct.nullable(superstruct.array(superstruct.type({
index: superstruct.number(),
instructions: superstruct.array(ParsedOrRawInstruction)
})))),
preBalances: superstruct.array(superstruct.number()),
postBalances: superstruct.array(superstruct.number()),
logMessages: superstruct.optional(superstruct.nullable(superstruct.array(superstruct.string()))),
preTokenBalances: superstruct.optional(superstruct.nullable(superstruct.array(TokenBalanceResult))),
postTokenBalances: superstruct.optional(superstruct.nullable(superstruct.array(TokenBalanceResult))),
loadedAddresses: superstruct.optional(LoadedAddressesResult),
computeUnitsConsumed: superstruct.optional(superstruct.number())
});
const TransactionVersionStruct = superstruct.union([superstruct.literal(0), superstruct.literal('legacy')]);
/** @internal */
const RewardsResult = superstruct.type({
pubkey: superstruct.string(),
lamports: superstruct.number(),
postBalance: superstruct.nullable(superstruct.number()),
rewardType: superstruct.nullable(superstruct.string()),
commission: superstruct.optional(superstruct.nullable(superstruct.number()))
});
/**
* Expected JSON RPC response for the "getBlock" message
*/
const GetBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
transactions: superstruct.array(superstruct.type({
transaction: ConfirmedTransactionResult,
meta: superstruct.nullable(ConfirmedTransactionMetaResult),
version: superstruct.optional(TransactionVersionStruct)
})),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number()),
blockHeight: superstruct.nullable(superstruct.number())
})));
/**
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
*/
const GetNoneModeBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number()),
blockHeight: superstruct.nullable(superstruct.number())
})));
/**
* Expected JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
*/
const GetAccountsModeBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
transactions: superstruct.array(superstruct.type({
transaction: ConfirmedTransactionAccountsModeResult,
meta: superstruct.nullable(ConfirmedTransactionMetaResult),
version: superstruct.optional(TransactionVersionStruct)
})),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number()),
blockHeight: superstruct.nullable(superstruct.number())
})));
/**
* Expected parsed JSON RPC response for the "getBlock" message
*/
const GetParsedBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
transactions: superstruct.array(superstruct.type({
transaction: ParsedConfirmedTransactionResult,
meta: superstruct.nullable(ParsedConfirmedTransactionMetaResult),
version: superstruct.optional(TransactionVersionStruct)
})),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number()),
blockHeight: superstruct.nullable(superstruct.number())
})));
/**
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `accounts`
*/
const GetParsedAccountsModeBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
transactions: superstruct.array(superstruct.type({
transaction: ConfirmedTransactionAccountsModeResult,
meta: superstruct.nullable(ParsedConfirmedTransactionMetaResult),
version: superstruct.optional(TransactionVersionStruct)
})),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number()),
blockHeight: superstruct.nullable(superstruct.number())
})));
/**
* Expected parsed JSON RPC response for the "getBlock" message when `transactionDetails` is `none`
*/
const GetParsedNoneModeBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number()),
blockHeight: superstruct.nullable(superstruct.number())
})));
/**
* Expected JSON RPC response for the "getConfirmedBlock" message
*
* @deprecated Deprecated since RPC v1.8.0. Please use {@link GetBlockRpcResult} instead.
*/
const GetConfirmedBlockRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
transactions: superstruct.array(superstruct.type({
transaction: ConfirmedTransactionResult,
meta: superstruct.nullable(ConfirmedTransactionMetaResult)
})),
rewards: superstruct.optional(superstruct.array(RewardsResult)),
blockTime: superstruct.nullable(superstruct.number())
})));
/**
* Expected JSON RPC response for the "getBlock" message
*/
const GetBlockSignaturesRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
blockhash: superstruct.string(),
previousBlockhash: superstruct.string(),
parentSlot: superstruct.number(),
signatures: superstruct.array(superstruct.string()),
blockTime: superstruct.nullable(superstruct.number())
})));
/**
* Expected JSON RPC response for the "getTransaction" message
*/
const GetTransactionRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
slot: superstruct.number(),
meta: superstruct.nullable(ConfirmedTransactionMetaResult),
blockTime: superstruct.optional(superstruct.nullable(superstruct.number())),
transaction: ConfirmedTransactionResult,
version: superstruct.optional(TransactionVersionStruct)
})));
/**
* Expected parsed JSON RPC response for the "getTransaction" message
*/
const GetParsedTransactionRpcResult = jsonRpcResult(superstruct.nullable(superstruct.type({
slot: superstruct.number(),
transaction: ParsedConfirmedTransactionResult,
meta: superstruct.nullable(ParsedConfirmedTransactionMetaResult),
blockTime: superstruct.optional(superstruct.nullable(superstruct.number())),
version: superstruct.optional(TransactionVersionStruct)
})));
/**
* Expected JSON RPC response for the "getLatestBlockhash" message
*/
const GetLatestBlockhashRpcResult = jsonRpcResultAndContext(superstruct.type({
blockhash: superstruct.string(),
lastValidBlockHeight: superstruct.number()
}));
/**
* Expected JSON RPC response for the "isBlockhashValid" message
*/
const IsBlockhashValidRpcResult = jsonRpcResultAndContext(superstruct.boolean());
const PerfSampleResult = superstruct.type({
slot: superstruct.number(),
numTransactions: superstruct.number(),
numSlots: superstruct.number(),
samplePeriodSecs: superstruct.number()
});
/*
* Expected JSON RPC response for "getRecentPerformanceSamples" message
*/
const GetRecentPerformanceSamplesRpcResult = jsonRpcResult(superstruct.array(PerfSampleResult));
/**
* Expected JSON RPC response for the "getFeeCalculatorForBlockhash" message
*/
const GetFeeCalculatorRpcResult = jsonRpcResultAndContext(superstruct.nullable(superstruct.type({
feeCalculator: superstruct.type({
lamportsPerSignature: superstruct.number()
})
})));
/**
* Expected JSON RPC response for the "requestAirdrop" message
*/
const RequestAirdropRpcResult = jsonRpcResult(superstruct.string());
/**
* Expected JSON RPC response for the "sendTransaction" message
*/
const SendTransactionRpcResult = jsonRpcResult(superstruct.string());
/**
* Information about the latest slot being processed by a node
*/
/**
* Parsed account data
*/
/**
* Stake Activation data
*/
/**
* Data slice argument for getProgramAccounts
*/
/**
* Memory comparison filter for getProgramAccounts
*/
/**
* Data size comparison filter for getProgramAccounts
*/
/**
* A filter object for getProgramAccounts
*/
/**
* Configuration object for getProgramAccounts requests
*/
/**
* Configuration object for getParsedProgramAccounts
*/
/**
* Configuration object for getMultipleAccounts
*/
/**
* Configuration object for `getStakeActivation`
*/
/**
* Configuration object for `getStakeActivation`
*/
/**
* Configuration object for `getStakeActivation`
*/
/**
* Configuration object for `getNonce`
*/
/**
* Configuration object for `getNonceAndContext`
*/
/**
* Information describing an account
*/
/**
* Account information identified by pubkey
*/
/**
* Callback function for account change notifications
*/
/**
* Callback function for program account change notifications
*/
/**
* Callback function for slot change notifications
*/
/**
* Callback function for slot update notifications
*/
/**
* Callback function for signature status notifications
*/
/**
* Signature status notification with transaction result
*/
/**
* Signature received notification
*/
/**
* Callback function for signature notifications
*/
/**
* Signature subscription options
*/
/**
* Callback function for root change notifications
*/
/**
* @internal
*/
const LogsResult = superstruct.type({
err: TransactionErrorResult,
logs: superstruct.array(superstruct.string()),
signature: superstruct.string()
});
/**
* Logs result.
*/
/**
* Expected JSON RPC response for the "logsNotification" message.
*/
const LogsNotificationResult = superstruct.type({
result: notificationResultAndContext(LogsResult),
subscription: superstruct.number()
});
/**
* Filter for log subscriptions.
*/
/**
* Callback function for log notifications.
*/
/**
* Signature result
*/
/**
* Transaction error
*/
/**
* Transaction confirmation status
* <pre>
* 'processed': Transaction landed in a block which has reached 1 confirmation by the connected node
* 'confirmed': Transaction landed in a block which has reached 1 confirmation by the cluster
* 'finalized': Transaction landed in a block which has been finalized by the cluster
* </pre>
*/
/**
* Signature status
*/
/**
* A confirmed signature with its status
*/
/**
* An object defining headers to be passed to the RPC server
*/
/**
* The type of the JavaScript `fetch()` API
*/
/**
* A callback used to augment the outgoing HTTP request
*/
/**
* Configuration for instantiating a Connection
*/
/** @internal */
const COMMON_HTTP_HEADERS = {
'solana-client': `js/${"1.0.0-maintenance"}`
};
/**
* A connection to a fullnode JSON RPC endpoint
*/
class Connection {
/**
* Establish a JSON RPC connection
*
* @param endpoint URL to the fullnode JSON RPC endpoint
* @param commitmentOrConfig optional default commitment level or optional ConnectionConfig configuration object
*/
constructor(endpoint, _commitmentOrConfig) {
/** @internal */
this._commitment = void 0;
/** @internal */
this._confirmTransactionInitialTimeout = void 0;
/** @internal */
this._rpcEndpoint = void 0;
/** @internal */
this._rpcWsEndpoint = void 0;
/** @internal */
this._rpcClient = void 0;
/** @internal */
this._rpcRequest = void 0;
/** @internal */
this._rpcBatchRequest = void 0;
/** @internal */
this._rpcWebSocket = void 0;
/** @internal */
this._rpcWebSocketConnected = false;
/** @internal */
this._rpcWebSocketHeartbeat = null;
/** @internal */
this._rpcWebSocketIdleTimeout = null;
/** @internal
* A number that we increment every time an active connection closes.
* Used to determine whether the same socket connection that was open
* when an async operation started is the same one that's active when
* its continuation fires.
*
*/
this._rpcWebSocketGeneration = 0;
/** @internal */
this._disableBlockhashCaching = false;
/** @internal */
this._pollingBlockhash = false;
/** @internal */
this._blockhashInfo = {
latestBlockhash: null,
lastFetch: 0,
transactionSignatures: [],
simulatedSignatures: []
};
/** @internal */
this._nextClientSubscriptionId = 0;
/** @internal */
this._subscriptionDisposeFunctionsByClientSubscriptionId = {};
/** @internal */
this._subscriptionHashByClientSubscriptionId = {};
/** @internal */
this._subscriptionStateChangeCallbacksByHash = {};
/** @internal */
this._subscriptionCallbacksByServerSubscriptionId = {};
/** @internal */
this._subscriptionsByHash = {};
/**
* Special case.
* After a signature is processed, RPCs automatically dispose of the
* subscription on the server side. We need to track which of these
* subscriptions have been disposed in such a way, so that we know
* whether the client is dealing with a not-yet-processed signature
* (in which case we must tear down the server subscription) or an
* already-processed signature (in which case the client can simply
* clear out the subscription locally without telling the server).
*
* NOTE: There is a proposal to eliminate this special case, here:
* https://github.com/solana-labs/solana/issues/18892
*/
/** @internal */
this._subscriptionsAutoDisposedByRpc = new Set();
/*
* Returns the current block height of the node
*/
this.getBlockHeight = (() => {
const requestPromises = {};
return async commitmentOrConfig => {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
const requestHash = fastStableStringify(args);
requestPromises[requestHash] = requestPromises[requestHash] ?? (async () => {
try {
const unsafeRes = await this._rpcRequest('getBlockHeight', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.number()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get block height information');
}
return res.result;
} finally {
delete requestPromises[requestHash];
}
})();
return await requestPromises[requestHash];
};
})();
let wsEndpoint;
let httpHeaders;
let fetch;
let fetchMiddleware;
let disableRetryOnRateLimit;
let httpAgent;
if (_commitmentOrConfig && typeof _commitmentOrConfig === 'string') {
this._commitment = _commitmentOrConfig;
} else if (_commitmentOrConfig) {
this._commitment = _commitmentOrConfig.commitment;
this._confirmTransactionInitialTimeout = _commitmentOrConfig.confirmTransactionInitialTimeout;
wsEndpoint = _commitmentOrConfig.wsEndpoint;
httpHeaders = _commitmentOrConfig.httpHeaders;
fetch = _commitmentOrConfig.fetch;
fetchMiddleware = _commitmentOrConfig.fetchMiddleware;
disableRetryOnRateLimit = _commitmentOrConfig.disableRetryOnRateLimit;
httpAgent = _commitmentOrConfig.httpAgent;
}
this._rpcEndpoint = assertEndpointUrl(endpoint);
this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint);
this._rpcClient = createRpcClient(endpoint, httpHeaders, fetch, fetchMiddleware, disableRetryOnRateLimit, httpAgent);
this._rpcRequest = createRpcRequest(this._rpcClient);
this._rpcBatchRequest = createRpcBatchRequest(this._rpcClient);
this._rpcWebSocket = new RpcWebSocketClient(this._rpcWsEndpoint, {
autoconnect: false,
max_reconnects: Infinity
});
this._rpcWebSocket.on('open', this._wsOnOpen.bind(this));
this._rpcWebSocket.on('error', this._wsOnError.bind(this));
this._rpcWebSocket.on('close', this._wsOnClose.bind(this));
this._rpcWebSocket.on('accountNotification', this._wsOnAccountNotification.bind(this));
this._rpcWebSocket.on('programNotification', this._wsOnProgramAccountNotification.bind(this));
this._rpcWebSocket.on('slotNotification', this._wsOnSlotNotification.bind(this));
this._rpcWebSocket.on('slotsUpdatesNotification', this._wsOnSlotUpdatesNotification.bind(this));
this._rpcWebSocket.on('signatureNotification', this._wsOnSignatureNotification.bind(this));
this._rpcWebSocket.on('rootNotification', this._wsOnRootNotification.bind(this));
this._rpcWebSocket.on('logsNotification', this._wsOnLogsNotification.bind(this));
}
/**
* The default commitment used for requests
*/
get commitment() {
return this._commitment;
}
/**
* The RPC endpoint
*/
get rpcEndpoint() {
return this._rpcEndpoint;
}
/**
* Fetch the balance for the specified public key, return with context
*/
async getBalanceAndContext(publicKey, commitmentOrConfig) {
/** @internal */
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([publicKey.toBase58()], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getBalance', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.number()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get balance for ${publicKey.toBase58()}`);
}
return res.result;
}
/**
* Fetch the balance for the specified public key
*/
async getBalance(publicKey, commitmentOrConfig) {
return await this.getBalanceAndContext(publicKey, commitmentOrConfig).then(x => x.value).catch(e => {
throw new Error('failed to get balance of account ' + publicKey.toBase58() + ': ' + e);
});
}
/**
* Fetch the estimated production time of a block
*/
async getBlockTime(slot) {
const unsafeRes = await this._rpcRequest('getBlockTime', [slot]);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.nullable(superstruct.number())));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get block time for slot ${slot}`);
}
return res.result;
}
/**
* Fetch the lowest slot that the node has information about in its ledger.
* This value may increase over time if the node is configured to purge older ledger data
*/
async getMinimumLedgerSlot() {
const unsafeRes = await this._rpcRequest('minimumLedgerSlot', []);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.number()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get minimum ledger slot');
}
return res.result;
}
/**
* Fetch the slot of the lowest confirmed block that has not been purged from the ledger
*/
async getFirstAvailableBlock() {
const unsafeRes = await this._rpcRequest('getFirstAvailableBlock', []);
const res = superstruct.create(unsafeRes, SlotRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get first available block');
}
return res.result;
}
/**
* Fetch information about the current supply
*/
async getSupply(config) {
let configArg = {};
if (typeof config === 'string') {
configArg = {
commitment: config
};
} else if (config) {
configArg = {
...config,
commitment: config && config.commitment || this.commitment
};
} else {
configArg = {
commitment: this.commitment
};
}
const unsafeRes = await this._rpcRequest('getSupply', [configArg]);
const res = superstruct.create(unsafeRes, GetSupplyRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get supply');
}
return res.result;
}
/**
* Fetch the current supply of a token mint
*/
async getTokenSupply(tokenMintAddress, commitment) {
const args = this._buildArgs([tokenMintAddress.toBase58()], commitment);
const unsafeRes = await this._rpcRequest('getTokenSupply', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get token supply');
}
return res.result;
}
/**
* Fetch the current balance of a token account
*/
async getTokenAccountBalance(tokenAddress, commitment) {
const args = this._buildArgs([tokenAddress.toBase58()], commitment);
const unsafeRes = await this._rpcRequest('getTokenAccountBalance', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(TokenAmountResult));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get token account balance');
}
return res.result;
}
/**
* Fetch all the token accounts owned by the specified account
*
* @return {Promise<RpcResponseAndContext<GetProgramAccountsResponse>}
*/
async getTokenAccountsByOwner(ownerAddress, filter, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
let _args = [ownerAddress.toBase58()];
if ('mint' in filter) {
_args.push({
mint: filter.mint.toBase58()
});
} else {
_args.push({
programId: filter.programId.toBase58()
});
}
const args = this._buildArgs(_args, commitment, 'base64', config);
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
const res = superstruct.create(unsafeRes, GetTokenAccountsByOwner);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get token accounts owned by account ${ownerAddress.toBase58()}`);
}
return res.result;
}
/**
* Fetch parsed token accounts owned by the specified account
*
* @return {Promise<RpcResponseAndContext<Array<{pubkey: PublicKey, account: AccountInfo<ParsedAccountData>}>>>}
*/
async getParsedTokenAccountsByOwner(ownerAddress, filter, commitment) {
let _args = [ownerAddress.toBase58()];
if ('mint' in filter) {
_args.push({
mint: filter.mint.toBase58()
});
} else {
_args.push({
programId: filter.programId.toBase58()
});
}
const args = this._buildArgs(_args, commitment, 'jsonParsed');
const unsafeRes = await this._rpcRequest('getTokenAccountsByOwner', args);
const res = superstruct.create(unsafeRes, GetParsedTokenAccountsByOwner);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get token accounts owned by account ${ownerAddress.toBase58()}`);
}
return res.result;
}
/**
* Fetch the 20 largest accounts with their current balances
*/
async getLargestAccounts(config) {
const arg = {
...config,
commitment: config && config.commitment || this.commitment
};
const args = arg.filter || arg.commitment ? [arg] : [];
const unsafeRes = await this._rpcRequest('getLargestAccounts', args);
const res = superstruct.create(unsafeRes, GetLargestAccountsRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get largest accounts');
}
return res.result;
}
/**
* Fetch the 20 largest token accounts with their current balances
* for a given mint.
*/
async getTokenLargestAccounts(mintAddress, commitment) {
const args = this._buildArgs([mintAddress.toBase58()], commitment);
const unsafeRes = await this._rpcRequest('getTokenLargestAccounts', args);
const res = superstruct.create(unsafeRes, GetTokenLargestAccountsResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get token largest accounts');
}
return res.result;
}
/**
* Fetch all the account info for the specified public key, return with context
*/
async getAccountInfoAndContext(publicKey, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([publicKey.toBase58()], commitment, 'base64', config);
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.nullable(AccountInfoResult)));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get info about account ${publicKey.toBase58()}`);
}
return res.result;
}
/**
* Fetch parsed account info for the specified public key
*/
async getParsedAccountInfo(publicKey, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([publicKey.toBase58()], commitment, 'jsonParsed', config);
const unsafeRes = await this._rpcRequest('getAccountInfo', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.nullable(ParsedAccountInfoResult)));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get info about account ${publicKey.toBase58()}`);
}
return res.result;
}
/**
* Fetch all the account info for the specified public key
*/
async getAccountInfo(publicKey, commitmentOrConfig) {
try {
const res = await this.getAccountInfoAndContext(publicKey, commitmentOrConfig);
return res.value;
} catch (e) {
throw new Error('failed to get info about account ' + publicKey.toBase58() + ': ' + e);
}
}
/**
* Fetch all the account info for multiple accounts specified by an array of public keys, return with context
*/
async getMultipleParsedAccounts(publicKeys, rawConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(rawConfig);
const keys = publicKeys.map(key => key.toBase58());
const args = this._buildArgs([keys], commitment, 'jsonParsed', config);
const unsafeRes = await this._rpcRequest('getMultipleAccounts', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.array(superstruct.nullable(ParsedAccountInfoResult))));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get info for accounts ${keys}`);
}
return res.result;
}
/**
* Fetch all the account info for multiple accounts specified by an array of public keys, return with context
*/
async getMultipleAccountsInfoAndContext(publicKeys, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const keys = publicKeys.map(key => key.toBase58());
const args = this._buildArgs([keys], commitment, 'base64', config);
const unsafeRes = await this._rpcRequest('getMultipleAccounts', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.array(superstruct.nullable(AccountInfoResult))));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get info for accounts ${keys}`);
}
return res.result;
}
/**
* Fetch all the account info for multiple accounts specified by an array of public keys
*/
async getMultipleAccountsInfo(publicKeys, commitmentOrConfig) {
const res = await this.getMultipleAccountsInfoAndContext(publicKeys, commitmentOrConfig);
return res.value;
}
/**
* Returns epoch activation information for a stake account that has been delegated
*
* @deprecated Deprecated since RPC v1.18; will be removed in a future version.
*/
async getStakeActivation(publicKey, commitmentOrConfig, epoch) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([publicKey.toBase58()], commitment, undefined /* encoding */, {
...config,
epoch: epoch != null ? epoch : config?.epoch
});
const unsafeRes = await this._rpcRequest('getStakeActivation', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(StakeActivationResult));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get Stake Activation ${publicKey.toBase58()}`);
}
return res.result;
}
/**
* Fetch all the accounts owned by the specified program id
*
* @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer>}>>}
*/
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
async getProgramAccounts(programId, configOrCommitment) {
const {
commitment,
config
} = extractCommitmentFromConfig(configOrCommitment);
const {
encoding,
...configWithoutEncoding
} = config || {};
const args = this._buildArgs([programId.toBase58()], commitment, encoding || 'base64', {
...configWithoutEncoding,
...(configWithoutEncoding.filters ? {
filters: applyDefaultMemcmpEncodingToFilters(configWithoutEncoding.filters)
} : null)
});
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
const baseSchema = superstruct.array(KeyedAccountInfoResult);
const res = configWithoutEncoding.withContext === true ? superstruct.create(unsafeRes, jsonRpcResultAndContext(baseSchema)) : superstruct.create(unsafeRes, jsonRpcResult(baseSchema));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get accounts owned by program ${programId.toBase58()}`);
}
return res.result;
}
/**
* Fetch and parse all the accounts owned by the specified program id
*
* @return {Promise<Array<{pubkey: PublicKey, account: AccountInfo<Buffer | ParsedAccountData>}>>}
*/
async getParsedProgramAccounts(programId, configOrCommitment) {
const {
commitment,
config
} = extractCommitmentFromConfig(configOrCommitment);
const args = this._buildArgs([programId.toBase58()], commitment, 'jsonParsed', config);
const unsafeRes = await this._rpcRequest('getProgramAccounts', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.array(KeyedParsedAccountInfoResult)));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get accounts owned by program ${programId.toBase58()}`);
}
return res.result;
}
/** @deprecated Instead, call `confirmTransaction` and pass in {@link TransactionConfirmationStrategy} */
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
async confirmTransaction(strategy, commitment) {
let rawSignature;
if (typeof strategy == 'string') {
rawSignature = strategy;
} else {
const config = strategy;
if (config.abortSignal?.aborted) {
return Promise.reject(config.abortSignal.reason);
}
rawSignature = config.signature;
}
let decodedSignature;
try {
decodedSignature = bs58__default.default.decode(rawSignature);
} catch (err) {
throw new Error('signature must be base58 encoded: ' + rawSignature);
}
assert(decodedSignature.length === 64, 'signature has invalid length');
if (typeof strategy === 'string') {
return await this.confirmTransactionUsingLegacyTimeoutStrategy({
commitment: commitment || this.commitment,
signature: rawSignature
});
} else if ('lastValidBlockHeight' in strategy) {
return await this.confirmTransactionUsingBlockHeightExceedanceStrategy({
commitment: commitment || this.commitment,
strategy
});
} else {
return await this.confirmTransactionUsingDurableNonceStrategy({
commitment: commitment || this.commitment,
strategy
});
}
}
getCancellationPromise(signal) {
return new Promise((_, reject) => {
if (signal == null) {
return;
}
if (signal.aborted) {
reject(signal.reason);
} else {
signal.addEventListener('abort', () => {
reject(signal.reason);
});
}
});
}
getTransactionConfirmationPromise({
commitment,
signature
}) {
let signatureSubscriptionId;
let disposeSignatureSubscriptionStateChangeObserver;
let done = false;
const confirmationPromise = new Promise((resolve, reject) => {
try {
signatureSubscriptionId = this.onSignature(signature, (result, context) => {
signatureSubscriptionId = undefined;
const response = {
context,
value: result
};
resolve({
__type: TransactionStatus.PROCESSED,
response
});
}, commitment);
const subscriptionSetupPromise = new Promise(resolveSubscriptionSetup => {
if (signatureSubscriptionId == null) {
resolveSubscriptionSetup();
} else {
disposeSignatureSubscriptionStateChangeObserver = this._onSubscriptionStateChange(signatureSubscriptionId, nextState => {
if (nextState === 'subscribed') {
resolveSubscriptionSetup();
}
});
}
});
(async () => {
await subscriptionSetupPromise;
if (done) return;
const response = await this.getSignatureStatus(signature);
if (done) return;
if (response == null) {
return;
}
const {
context,
value
} = response;
if (value == null) {
return;
}
if (value?.err) {
reject(value.err);
} else {
switch (commitment) {
case 'confirmed':
case 'single':
case 'singleGossip':
{
if (value.confirmationStatus === 'processed') {
return;
}
break;
}
case 'finalized':
case 'max':
case 'root':
{
if (value.confirmationStatus === 'processed' || value.confirmationStatus === 'confirmed') {
return;
}
break;
}
// exhaust enums to ensure full coverage
case 'processed':
case 'recent':
}
done = true;
resolve({
__type: TransactionStatus.PROCESSED,
response: {
context,
value
}
});
}
})();
} catch (err) {
reject(err);
}
});
const abortConfirmation = () => {
if (disposeSignatureSubscriptionStateChangeObserver) {
disposeSignatureSubscriptionStateChangeObserver();
disposeSignatureSubscriptionStateChangeObserver = undefined;
}
if (signatureSubscriptionId != null) {
this.removeSignatureListener(signatureSubscriptionId);
signatureSubscriptionId = undefined;
}
};
return {
abortConfirmation,
confirmationPromise
};
}
async confirmTransactionUsingBlockHeightExceedanceStrategy({
commitment,
strategy: {
abortSignal,
lastValidBlockHeight,
signature
}
}) {
let done = false;
const expiryPromise = new Promise(resolve => {
const checkBlockHeight = async () => {
try {
const blockHeight = await this.getBlockHeight(commitment);
return blockHeight;
} catch (_e) {
return -1;
}
};
(async () => {
let currentBlockHeight = await checkBlockHeight();
if (done) return;
while (currentBlockHeight <= lastValidBlockHeight) {
await sleep(1000);
if (done) return;
currentBlockHeight = await checkBlockHeight();
if (done) return;
}
resolve({
__type: TransactionStatus.BLOCKHEIGHT_EXCEEDED
});
})();
});
const {
abortConfirmation,
confirmationPromise
} = this.getTransactionConfirmationPromise({
commitment,
signature
});
const cancellationPromise = this.getCancellationPromise(abortSignal);
let result;
try {
const outcome = await Promise.race([cancellationPromise, confirmationPromise, expiryPromise]);
if (outcome.__type === TransactionStatus.PROCESSED) {
result = outcome.response;
} else {
throw new TransactionExpiredBlockheightExceededError(signature);
}
} finally {
done = true;
abortConfirmation();
}
return result;
}
async confirmTransactionUsingDurableNonceStrategy({
commitment,
strategy: {
abortSignal,
minContextSlot,
nonceAccountPubkey,
nonceValue,
signature
}
}) {
let done = false;
const expiryPromise = new Promise(resolve => {
let currentNonceValue = nonceValue;
let lastCheckedSlot = null;
const getCurrentNonceValue = async () => {
try {
const {
context,
value: nonceAccount
} = await this.getNonceAndContext(nonceAccountPubkey, {
commitment,
minContextSlot
});
lastCheckedSlot = context.slot;
return nonceAccount?.nonce;
} catch (e) {
// If for whatever reason we can't reach/read the nonce
// account, just keep using the last-known value.
return currentNonceValue;
}
};
(async () => {
currentNonceValue = await getCurrentNonceValue();
if (done) return;
while (true // eslint-disable-line no-constant-condition
) {
if (nonceValue !== currentNonceValue) {
resolve({
__type: TransactionStatus.NONCE_INVALID,
slotInWhichNonceDidAdvance: lastCheckedSlot
});
return;
}
await sleep(2000);
if (done) return;
currentNonceValue = await getCurrentNonceValue();
if (done) return;
}
})();
});
const {
abortConfirmation,
confirmationPromise
} = this.getTransactionConfirmationPromise({
commitment,
signature
});
const cancellationPromise = this.getCancellationPromise(abortSignal);
let result;
try {
const outcome = await Promise.race([cancellationPromise, confirmationPromise, expiryPromise]);
if (outcome.__type === TransactionStatus.PROCESSED) {
result = outcome.response;
} else {
// Double check that the transaction is indeed unconfirmed.
let signatureStatus;
while (true // eslint-disable-line no-constant-condition
) {
const status = await this.getSignatureStatus(signature);
if (status == null) {
break;
}
if (status.context.slot < (outcome.slotInWhichNonceDidAdvance ?? minContextSlot)) {
await sleep(400);
continue;
}
signatureStatus = status;
break;
}
if (signatureStatus?.value) {
const commitmentForStatus = commitment || 'finalized';
const {
confirmationStatus
} = signatureStatus.value;
switch (commitmentForStatus) {
case 'processed':
case 'recent':
if (confirmationStatus !== 'processed' && confirmationStatus !== 'confirmed' && confirmationStatus !== 'finalized') {
throw new TransactionExpiredNonceInvalidError(signature);
}
break;
case 'confirmed':
case 'single':
case 'singleGossip':
if (confirmationStatus !== 'confirmed' && confirmationStatus !== 'finalized') {
throw new TransactionExpiredNonceInvalidError(signature);
}
break;
case 'finalized':
case 'max':
case 'root':
if (confirmationStatus !== 'finalized') {
throw new TransactionExpiredNonceInvalidError(signature);
}
break;
default:
// Exhaustive switch.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(_ => {})(commitmentForStatus);
}
result = {
context: signatureStatus.context,
value: {
err: signatureStatus.value.err
}
};
} else {
throw new TransactionExpiredNonceInvalidError(signature);
}
}
} finally {
done = true;
abortConfirmation();
}
return result;
}
async confirmTransactionUsingLegacyTimeoutStrategy({
commitment,
signature
}) {
let timeoutId;
const expiryPromise = new Promise(resolve => {
let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
switch (commitment) {
case 'processed':
case 'recent':
case 'single':
case 'confirmed':
case 'singleGossip':
{
timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
break;
}
}
timeoutId = setTimeout(() => resolve({
__type: TransactionStatus.TIMED_OUT,
timeoutMs
}), timeoutMs);
});
const {
abortConfirmation,
confirmationPromise
} = this.getTransactionConfirmationPromise({
commitment,
signature
});
let result;
try {
const outcome = await Promise.race([confirmationPromise, expiryPromise]);
if (outcome.__type === TransactionStatus.PROCESSED) {
result = outcome.response;
} else {
throw new TransactionExpiredTimeoutError(signature, outcome.timeoutMs / 1000);
}
} finally {
clearTimeout(timeoutId);
abortConfirmation();
}
return result;
}
/**
* Return the list of nodes that are currently participating in the cluster
*/
async getClusterNodes() {
const unsafeRes = await this._rpcRequest('getClusterNodes', []);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.array(ContactInfoResult)));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get cluster nodes');
}
return res.result;
}
/**
* Return the list of nodes that are currently participating in the cluster
*/
async getVoteAccounts(commitment) {
const args = this._buildArgs([], commitment);
const unsafeRes = await this._rpcRequest('getVoteAccounts', args);
const res = superstruct.create(unsafeRes, GetVoteAccounts);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get vote accounts');
}
return res.result;
}
/**
* Fetch the current slot that the node is processing
*/
async getSlot(commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getSlot', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.number()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get slot');
}
return res.result;
}
/**
* Fetch the current slot leader of the cluster
*/
async getSlotLeader(commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getSlotLeader', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.string()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get slot leader');
}
return res.result;
}
/**
* Fetch `limit` number of slot leaders starting from `startSlot`
*
* @param startSlot fetch slot leaders starting from this slot
* @param limit number of slot leaders to return
*/
async getSlotLeaders(startSlot, limit) {
const args = [startSlot, limit];
const unsafeRes = await this._rpcRequest('getSlotLeaders', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.array(PublicKeyFromString)));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get slot leaders');
}
return res.result;
}
/**
* Fetch the current status of a signature
*/
async getSignatureStatus(signature, config) {
const {
context,
value: values
} = await this.getSignatureStatuses([signature], config);
assert(values.length === 1);
const value = values[0];
return {
context,
value
};
}
/**
* Fetch the current statuses of a batch of signatures
*/
async getSignatureStatuses(signatures, config) {
const params = [signatures];
if (config) {
params.push(config);
}
const unsafeRes = await this._rpcRequest('getSignatureStatuses', params);
const res = superstruct.create(unsafeRes, GetSignatureStatusesRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get signature status');
}
return res.result;
}
/**
* Fetch the current transaction count of the cluster
*/
async getTransactionCount(commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getTransactionCount', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.number()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get transaction count');
}
return res.result;
}
/**
* Fetch the current total currency supply of the cluster in lamports
*
* @deprecated Deprecated since RPC v1.2.8. Please use {@link getSupply} instead.
*/
async getTotalSupply(commitment) {
const result = await this.getSupply({
commitment,
excludeNonCirculatingAccountsList: true
});
return result.value.total;
}
/**
* Fetch the cluster InflationGovernor parameters
*/
async getInflationGovernor(commitment) {
const args = this._buildArgs([], commitment);
const unsafeRes = await this._rpcRequest('getInflationGovernor', args);
const res = superstruct.create(unsafeRes, GetInflationGovernorRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get inflation');
}
return res.result;
}
/**
* Fetch the inflation reward for a list of addresses for an epoch
*/
async getInflationReward(addresses, epoch, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([addresses.map(pubkey => pubkey.toBase58())], commitment, undefined /* encoding */, {
...config,
epoch: epoch != null ? epoch : config?.epoch
});
const unsafeRes = await this._rpcRequest('getInflationReward', args);
const res = superstruct.create(unsafeRes, GetInflationRewardResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get inflation reward');
}
return res.result;
}
/**
* Fetch the specific inflation values for the current epoch
*/
async getInflationRate() {
const unsafeRes = await this._rpcRequest('getInflationRate', []);
const res = superstruct.create(unsafeRes, GetInflationRateRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get inflation rate');
}
return res.result;
}
/**
* Fetch the Epoch Info parameters
*/
async getEpochInfo(commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getEpochInfo', args);
const res = superstruct.create(unsafeRes, GetEpochInfoRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get epoch info');
}
return res.result;
}
/**
* Fetch the Epoch Schedule parameters
*/
async getEpochSchedule() {
const unsafeRes = await this._rpcRequest('getEpochSchedule', []);
const res = superstruct.create(unsafeRes, GetEpochScheduleRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get epoch schedule');
}
const epochSchedule = res.result;
return new EpochSchedule(epochSchedule.slotsPerEpoch, epochSchedule.leaderScheduleSlotOffset, epochSchedule.warmup, epochSchedule.firstNormalEpoch, epochSchedule.firstNormalSlot);
}
/**
* Fetch the leader schedule for the current epoch
* @return {Promise<RpcResponseAndContext<LeaderSchedule>>}
*/
async getLeaderSchedule() {
const unsafeRes = await this._rpcRequest('getLeaderSchedule', []);
const res = superstruct.create(unsafeRes, GetLeaderScheduleRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get leader schedule');
}
return res.result;
}
/**
* Fetch the minimum balance needed to exempt an account of `dataLength`
* size from rent
*/
async getMinimumBalanceForRentExemption(dataLength, commitment) {
const args = this._buildArgs([dataLength], commitment);
const unsafeRes = await this._rpcRequest('getMinimumBalanceForRentExemption', args);
const res = superstruct.create(unsafeRes, GetMinimumBalanceForRentExemptionRpcResult);
if ('error' in res) {
console.warn('Unable to fetch minimum balance for rent exemption');
return 0;
}
return res.result;
}
/**
* Fetch a recent blockhash from the cluster, return with context
* @return {Promise<RpcResponseAndContext<{blockhash: Blockhash, feeCalculator: FeeCalculator}>>}
*
* @deprecated Deprecated since RPC v1.9.0. Please use {@link getLatestBlockhash} instead.
*/
async getRecentBlockhashAndContext(commitment) {
const {
context,
value: {
blockhash
}
} = await this.getLatestBlockhashAndContext(commitment);
const feeCalculator = {
get lamportsPerSignature() {
throw new Error('The capability to fetch `lamportsPerSignature` using the `getRecentBlockhash` API is ' + 'no longer offered by the network. Use the `getFeeForMessage` API to obtain the fee ' + 'for a given message.');
},
toJSON() {
return {};
}
};
return {
context,
value: {
blockhash,
feeCalculator
}
};
}
/**
* Fetch recent performance samples
* @return {Promise<Array<PerfSample>>}
*/
async getRecentPerformanceSamples(limit) {
const unsafeRes = await this._rpcRequest('getRecentPerformanceSamples', limit ? [limit] : []);
const res = superstruct.create(unsafeRes, GetRecentPerformanceSamplesRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get recent performance samples');
}
return res.result;
}
/**
* Fetch the fee calculator for a recent blockhash from the cluster, return with context
*
* @deprecated Deprecated since RPC v1.9.0. Please use {@link getFeeForMessage} instead.
*/
async getFeeCalculatorForBlockhash(blockhash, commitment) {
const args = this._buildArgs([blockhash], commitment);
const unsafeRes = await this._rpcRequest('getFeeCalculatorForBlockhash', args);
const res = superstruct.create(unsafeRes, GetFeeCalculatorRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get fee calculator');
}
const {
context,
value
} = res.result;
return {
context,
value: value !== null ? value.feeCalculator : null
};
}
/**
* Fetch the fee for a message from the cluster, return with context
*/
async getFeeForMessage(message, commitment) {
const wireMessage = toBuffer(message.serialize()).toString('base64');
const args = this._buildArgs([wireMessage], commitment);
const unsafeRes = await this._rpcRequest('getFeeForMessage', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.nullable(superstruct.number())));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get fee for message');
}
if (res.result === null) {
throw new Error('invalid blockhash');
}
return res.result;
}
/**
* Fetch a list of prioritization fees from recent blocks.
*/
async getRecentPrioritizationFees(config) {
const accounts = config?.lockedWritableAccounts?.map(key => key.toBase58());
const args = accounts?.length ? [accounts] : [];
const unsafeRes = await this._rpcRequest('getRecentPrioritizationFees', args);
const res = superstruct.create(unsafeRes, GetRecentPrioritizationFeesRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get recent prioritization fees');
}
return res.result;
}
/**
* Fetch a recent blockhash from the cluster
* @return {Promise<{blockhash: Blockhash, feeCalculator: FeeCalculator}>}
*
* @deprecated Deprecated since RPC v1.8.0. Please use {@link getLatestBlockhash} instead.
*/
async getRecentBlockhash(commitment) {
try {
const res = await this.getRecentBlockhashAndContext(commitment);
return res.value;
} catch (e) {
throw new Error('failed to get recent blockhash: ' + e);
}
}
/**
* Fetch the latest blockhash from the cluster
* @return {Promise<BlockhashWithExpiryBlockHeight>}
*/
async getLatestBlockhash(commitmentOrConfig) {
try {
const res = await this.getLatestBlockhashAndContext(commitmentOrConfig);
return res.value;
} catch (e) {
throw new Error('failed to get recent blockhash: ' + e);
}
}
/**
* Fetch the latest blockhash from the cluster
* @return {Promise<BlockhashWithExpiryBlockHeight>}
*/
async getLatestBlockhashAndContext(commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getLatestBlockhash', args);
const res = superstruct.create(unsafeRes, GetLatestBlockhashRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get latest blockhash');
}
return res.result;
}
/**
* Returns whether a blockhash is still valid or not
*/
async isBlockhashValid(blockhash, rawConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(rawConfig);
const args = this._buildArgs([blockhash], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('isBlockhashValid', args);
const res = superstruct.create(unsafeRes, IsBlockhashValidRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to determine if the blockhash `' + blockhash + '`is valid');
}
return res.result;
}
/**
* Fetch the node version
*/
async getVersion() {
const unsafeRes = await this._rpcRequest('getVersion', []);
const res = superstruct.create(unsafeRes, jsonRpcResult(VersionResult));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get version');
}
return res.result;
}
/**
* Fetch the genesis hash
*/
async getGenesisHash() {
const unsafeRes = await this._rpcRequest('getGenesisHash', []);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.string()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get genesis hash');
}
return res.result;
}
/**
* Fetch a processed block from the cluster.
*
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
* setting the `maxSupportedTransactionVersion` property.
*/
/**
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
* setting the `maxSupportedTransactionVersion` property.
*/
// eslint-disable-next-line no-dupe-class-members
/**
* @deprecated Instead, call `getBlock` using a `GetVersionedBlockConfig` by
* setting the `maxSupportedTransactionVersion` property.
*/
// eslint-disable-next-line no-dupe-class-members
/**
* Fetch a processed block from the cluster.
*/
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
/**
* Fetch a processed block from the cluster.
*/
// eslint-disable-next-line no-dupe-class-members
async getBlock(slot, rawConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(rawConfig);
const args = this._buildArgsAtLeastConfirmed([slot], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getBlock', args);
try {
switch (config?.transactionDetails) {
case 'accounts':
{
const res = superstruct.create(unsafeRes, GetAccountsModeBlockRpcResult);
if ('error' in res) {
throw res.error;
}
return res.result;
}
case 'none':
{
const res = superstruct.create(unsafeRes, GetNoneModeBlockRpcResult);
if ('error' in res) {
throw res.error;
}
return res.result;
}
default:
{
const res = superstruct.create(unsafeRes, GetBlockRpcResult);
if ('error' in res) {
throw res.error;
}
const {
result
} = res;
return result ? {
...result,
transactions: result.transactions.map(({
transaction,
meta,
version
}) => ({
meta,
transaction: {
...transaction,
message: versionedMessageFromResponse(version, transaction.message)
},
version
}))
} : null;
}
}
} catch (e) {
throw new SolanaJSONRPCError(e, 'failed to get confirmed block');
}
}
/**
* Fetch parsed transaction details for a confirmed or finalized block
*/
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
async getParsedBlock(slot, rawConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(rawConfig);
const args = this._buildArgsAtLeastConfirmed([slot], commitment, 'jsonParsed', config);
const unsafeRes = await this._rpcRequest('getBlock', args);
try {
switch (config?.transactionDetails) {
case 'accounts':
{
const res = superstruct.create(unsafeRes, GetParsedAccountsModeBlockRpcResult);
if ('error' in res) {
throw res.error;
}
return res.result;
}
case 'none':
{
const res = superstruct.create(unsafeRes, GetParsedNoneModeBlockRpcResult);
if ('error' in res) {
throw res.error;
}
return res.result;
}
default:
{
const res = superstruct.create(unsafeRes, GetParsedBlockRpcResult);
if ('error' in res) {
throw res.error;
}
return res.result;
}
}
} catch (e) {
throw new SolanaJSONRPCError(e, 'failed to get block');
}
}
/*
* Returns recent block production information from the current or previous epoch
*/
async getBlockProduction(configOrCommitment) {
let extra;
let commitment;
if (typeof configOrCommitment === 'string') {
commitment = configOrCommitment;
} else if (configOrCommitment) {
const {
commitment: c,
...rest
} = configOrCommitment;
commitment = c;
extra = rest;
}
const args = this._buildArgs([], commitment, 'base64', extra);
const unsafeRes = await this._rpcRequest('getBlockProduction', args);
const res = superstruct.create(unsafeRes, BlockProductionResponseStruct);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get block production information');
}
return res.result;
}
/**
* Fetch a confirmed or finalized transaction from the cluster.
*
* @deprecated Instead, call `getTransaction` using a
* `GetVersionedTransactionConfig` by setting the
* `maxSupportedTransactionVersion` property.
*/
/**
* Fetch a confirmed or finalized transaction from the cluster.
*/
// eslint-disable-next-line no-dupe-class-members
/**
* Fetch a confirmed or finalized transaction from the cluster.
*/
// eslint-disable-next-line no-dupe-class-members
async getTransaction(signature, rawConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(rawConfig);
const args = this._buildArgsAtLeastConfirmed([signature], commitment, undefined /* encoding */, config);
const unsafeRes = await this._rpcRequest('getTransaction', args);
const res = superstruct.create(unsafeRes, GetTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
}
const result = res.result;
if (!result) return result;
return {
...result,
transaction: {
...result.transaction,
message: versionedMessageFromResponse(result.version, result.transaction.message)
}
};
}
/**
* Fetch parsed transaction details for a confirmed or finalized transaction
*/
async getParsedTransaction(signature, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed', config);
const unsafeRes = await this._rpcRequest('getTransaction', args);
const res = superstruct.create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
}
return res.result;
}
/**
* Fetch parsed transaction details for a batch of confirmed transactions
*/
async getParsedTransactions(signatures, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const batch = signatures.map(signature => {
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed', config);
return {
methodName: 'getTransaction',
args
};
});
const unsafeRes = await this._rpcBatchRequest(batch);
const res = unsafeRes.map(unsafeRes => {
const res = superstruct.create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
}
return res.result;
});
return res;
}
/**
* Fetch transaction details for a batch of confirmed transactions.
* Similar to {@link getParsedTransactions} but returns a {@link TransactionResponse}.
*
* @deprecated Instead, call `getTransactions` using a
* `GetVersionedTransactionConfig` by setting the
* `maxSupportedTransactionVersion` property.
*/
/**
* Fetch transaction details for a batch of confirmed transactions.
* Similar to {@link getParsedTransactions} but returns a {@link
* VersionedTransactionResponse}.
*/
// eslint-disable-next-line no-dupe-class-members
/**
* Fetch transaction details for a batch of confirmed transactions.
* Similar to {@link getParsedTransactions} but returns a {@link
* VersionedTransactionResponse}.
*/
// eslint-disable-next-line no-dupe-class-members
async getTransactions(signatures, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const batch = signatures.map(signature => {
const args = this._buildArgsAtLeastConfirmed([signature], commitment, undefined /* encoding */, config);
return {
methodName: 'getTransaction',
args
};
});
const unsafeRes = await this._rpcBatchRequest(batch);
const res = unsafeRes.map(unsafeRes => {
const res = superstruct.create(unsafeRes, GetTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get transactions');
}
const result = res.result;
if (!result) return result;
return {
...result,
transaction: {
...result.transaction,
message: versionedMessageFromResponse(result.version, result.transaction.message)
}
};
});
return res;
}
/**
* Fetch a list of Transactions and transaction statuses from the cluster
* for a confirmed block.
*
* @deprecated Deprecated since RPC v1.7.0. Please use {@link getBlock} instead.
*/
async getConfirmedBlock(slot, commitment) {
const args = this._buildArgsAtLeastConfirmed([slot], commitment);
const unsafeRes = await this._rpcRequest('getBlock', args);
const res = superstruct.create(unsafeRes, GetConfirmedBlockRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
}
const result = res.result;
if (!result) {
throw new Error('Confirmed block ' + slot + ' not found');
}
const block = {
...result,
transactions: result.transactions.map(({
transaction,
meta
}) => {
const message = new Message(transaction.message);
return {
meta,
transaction: {
...transaction,
message
}
};
})
};
return {
...block,
transactions: block.transactions.map(({
transaction,
meta
}) => {
return {
meta,
transaction: Transaction.populate(transaction.message, transaction.signatures)
};
})
};
}
/**
* Fetch confirmed blocks between two slots
*/
async getBlocks(startSlot, endSlot, commitment) {
const args = this._buildArgsAtLeastConfirmed(endSlot !== undefined ? [startSlot, endSlot] : [startSlot], commitment);
const unsafeRes = await this._rpcRequest('getBlocks', args);
const res = superstruct.create(unsafeRes, jsonRpcResult(superstruct.array(superstruct.number())));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get blocks');
}
return res.result;
}
/**
* Fetch a list of Signatures from the cluster for a block, excluding rewards
*/
async getBlockSignatures(slot, commitment) {
const args = this._buildArgsAtLeastConfirmed([slot], commitment, undefined, {
transactionDetails: 'signatures',
rewards: false
});
const unsafeRes = await this._rpcRequest('getBlock', args);
const res = superstruct.create(unsafeRes, GetBlockSignaturesRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get block');
}
const result = res.result;
if (!result) {
throw new Error('Block ' + slot + ' not found');
}
return result;
}
/**
* Fetch a list of Signatures from the cluster for a confirmed block, excluding rewards
*
* @deprecated Deprecated since RPC v1.7.0. Please use {@link getBlockSignatures} instead.
*/
async getConfirmedBlockSignatures(slot, commitment) {
const args = this._buildArgsAtLeastConfirmed([slot], commitment, undefined, {
transactionDetails: 'signatures',
rewards: false
});
const unsafeRes = await this._rpcRequest('getBlock', args);
const res = superstruct.create(unsafeRes, GetBlockSignaturesRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed block');
}
const result = res.result;
if (!result) {
throw new Error('Confirmed block ' + slot + ' not found');
}
return result;
}
/**
* Fetch a transaction details for a confirmed transaction
*
* @deprecated Deprecated since RPC v1.7.0. Please use {@link getTransaction} instead.
*/
async getConfirmedTransaction(signature, commitment) {
const args = this._buildArgsAtLeastConfirmed([signature], commitment);
const unsafeRes = await this._rpcRequest('getTransaction', args);
const res = superstruct.create(unsafeRes, GetTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get transaction');
}
const result = res.result;
if (!result) return result;
const message = new Message(result.transaction.message);
const signatures = result.transaction.signatures;
return {
...result,
transaction: Transaction.populate(message, signatures)
};
}
/**
* Fetch parsed transaction details for a confirmed transaction
*
* @deprecated Deprecated since RPC v1.7.0. Please use {@link getParsedTransaction} instead.
*/
async getParsedConfirmedTransaction(signature, commitment) {
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed');
const unsafeRes = await this._rpcRequest('getTransaction', args);
const res = superstruct.create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed transaction');
}
return res.result;
}
/**
* Fetch parsed transaction details for a batch of confirmed transactions
*
* @deprecated Deprecated since RPC v1.7.0. Please use {@link getParsedTransactions} instead.
*/
async getParsedConfirmedTransactions(signatures, commitment) {
const batch = signatures.map(signature => {
const args = this._buildArgsAtLeastConfirmed([signature], commitment, 'jsonParsed');
return {
methodName: 'getTransaction',
args
};
});
const unsafeRes = await this._rpcBatchRequest(batch);
const res = unsafeRes.map(unsafeRes => {
const res = superstruct.create(unsafeRes, GetParsedTransactionRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed transactions');
}
return res.result;
});
return res;
}
/**
* Fetch a list of all the confirmed signatures for transactions involving an address
* within a specified slot range. Max range allowed is 10,000 slots.
*
* @deprecated Deprecated since RPC v1.3. Please use {@link getConfirmedSignaturesForAddress2} instead.
*
* @param address queried address
* @param startSlot start slot, inclusive
* @param endSlot end slot, inclusive
*/
async getConfirmedSignaturesForAddress(address, startSlot, endSlot) {
let options = {};
let firstAvailableBlock = await this.getFirstAvailableBlock();
while (!('until' in options)) {
startSlot--;
if (startSlot <= 0 || startSlot < firstAvailableBlock) {
break;
}
try {
const block = await this.getConfirmedBlockSignatures(startSlot, 'finalized');
if (block.signatures.length > 0) {
options.until = block.signatures[block.signatures.length - 1].toString();
}
} catch (err) {
if (err instanceof Error && err.message.includes('skipped')) {
continue;
} else {
throw err;
}
}
}
let highestConfirmedRoot = await this.getSlot('finalized');
while (!('before' in options)) {
endSlot++;
if (endSlot > highestConfirmedRoot) {
break;
}
try {
const block = await this.getConfirmedBlockSignatures(endSlot);
if (block.signatures.length > 0) {
options.before = block.signatures[block.signatures.length - 1].toString();
}
} catch (err) {
if (err instanceof Error && err.message.includes('skipped')) {
continue;
} else {
throw err;
}
}
}
const confirmedSignatureInfo = await this.getConfirmedSignaturesForAddress2(address, options);
return confirmedSignatureInfo.map(info => info.signature);
}
/**
* Returns confirmed signatures for transactions involving an
* address backwards in time from the provided signature or most recent confirmed block
*
* @deprecated Deprecated since RPC v1.7.0. Please use {@link getSignaturesForAddress} instead.
*/
async getConfirmedSignaturesForAddress2(address, options, commitment) {
const args = this._buildArgsAtLeastConfirmed([address.toBase58()], commitment, undefined, options);
const unsafeRes = await this._rpcRequest('getConfirmedSignaturesForAddress2', args);
const res = superstruct.create(unsafeRes, GetConfirmedSignaturesForAddress2RpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get confirmed signatures for address');
}
return res.result;
}
/**
* Returns confirmed signatures for transactions involving an
* address backwards in time from the provided signature or most recent confirmed block
*
*
* @param address queried address
* @param options
*/
async getSignaturesForAddress(address, options, commitment) {
const args = this._buildArgsAtLeastConfirmed([address.toBase58()], commitment, undefined, options);
const unsafeRes = await this._rpcRequest('getSignaturesForAddress', args);
const res = superstruct.create(unsafeRes, GetSignaturesForAddressRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, 'failed to get signatures for address');
}
return res.result;
}
async getAddressLookupTable(accountKey, config) {
const {
context,
value: accountInfo
} = await this.getAccountInfoAndContext(accountKey, config);
let value = null;
if (accountInfo !== null) {
value = new AddressLookupTableAccount({
key: accountKey,
state: AddressLookupTableAccount.deserialize(accountInfo.data)
});
}
return {
context,
value
};
}
/**
* Fetch the contents of a Nonce account from the cluster, return with context
*/
async getNonceAndContext(nonceAccount, commitmentOrConfig) {
const {
context,
value: accountInfo
} = await this.getAccountInfoAndContext(nonceAccount, commitmentOrConfig);
let value = null;
if (accountInfo !== null) {
value = NonceAccount.fromAccountData(accountInfo.data);
}
return {
context,
value
};
}
/**
* Fetch the contents of a Nonce account from the cluster
*/
async getNonce(nonceAccount, commitmentOrConfig) {
return await this.getNonceAndContext(nonceAccount, commitmentOrConfig).then(x => x.value).catch(e => {
throw new Error('failed to get nonce for account ' + nonceAccount.toBase58() + ': ' + e);
});
}
/**
* Request an allocation of lamports to the specified address
*
* ```typescript
* import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
*
* (async () => {
* const connection = new Connection("https://api.testnet.solana.com", "confirmed");
* const myAddress = new PublicKey("2nr1bHFT86W9tGnyvmYW4vcHKsQB3sVQfnddasz4kExM");
* const signature = await connection.requestAirdrop(myAddress, LAMPORTS_PER_SOL);
* await connection.confirmTransaction(signature);
* })();
* ```
*/
async requestAirdrop(to, lamports) {
const unsafeRes = await this._rpcRequest('requestAirdrop', [to.toBase58(), lamports]);
const res = superstruct.create(unsafeRes, RequestAirdropRpcResult);
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `airdrop to ${to.toBase58()} failed`);
}
return res.result;
}
/**
* @internal
*/
async _blockhashWithExpiryBlockHeight(disableCache) {
if (!disableCache) {
// Wait for polling to finish
while (this._pollingBlockhash) {
await sleep(100);
}
const timeSinceFetch = Date.now() - this._blockhashInfo.lastFetch;
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
if (this._blockhashInfo.latestBlockhash !== null && !expired) {
return this._blockhashInfo.latestBlockhash;
}
}
return await this._pollNewBlockhash();
}
/**
* @internal
*/
async _pollNewBlockhash() {
this._pollingBlockhash = true;
try {
const startTime = Date.now();
const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
for (let i = 0; i < 50; i++) {
const latestBlockhash = await this.getLatestBlockhash('finalized');
if (cachedBlockhash !== latestBlockhash.blockhash) {
this._blockhashInfo = {
latestBlockhash,
lastFetch: Date.now(),
transactionSignatures: [],
simulatedSignatures: []
};
return latestBlockhash;
}
// Sleep for approximately half a slot
await sleep(MS_PER_SLOT / 2);
}
throw new Error(`Unable to obtain a new blockhash after ${Date.now() - startTime}ms`);
} finally {
this._pollingBlockhash = false;
}
}
/**
* get the stake minimum delegation
*/
async getStakeMinimumDelegation(config) {
const {
commitment,
config: configArg
} = extractCommitmentFromConfig(config);
const args = this._buildArgs([], commitment, 'base64', configArg);
const unsafeRes = await this._rpcRequest('getStakeMinimumDelegation', args);
const res = superstruct.create(unsafeRes, jsonRpcResultAndContext(superstruct.number()));
if ('error' in res) {
throw new SolanaJSONRPCError(res.error, `failed to get stake minimum delegation`);
}
return res.result;
}
/**
* Simulate a transaction
*
* @deprecated Instead, call {@link simulateTransaction} with {@link
* VersionedTransaction} and {@link SimulateTransactionConfig} parameters
*/
/**
* Simulate a transaction
*/
// eslint-disable-next-line no-dupe-class-members
/**
* Simulate a transaction
*/
// eslint-disable-next-line no-dupe-class-members
async simulateTransaction(transactionOrMessage, configOrSigners, includeAccounts) {
if ('message' in transactionOrMessage) {
const versionedTx = transactionOrMessage;
const wireTransaction = versionedTx.serialize();
const encodedTransaction = buffer.Buffer.from(wireTransaction).toString('base64');
if (Array.isArray(configOrSigners) || includeAccounts !== undefined) {
throw new Error('Invalid arguments');
}
const config = configOrSigners || {};
config.encoding = 'base64';
if (!('commitment' in config)) {
config.commitment = this.commitment;
}
if (configOrSigners && typeof configOrSigners === 'object' && 'innerInstructions' in configOrSigners) {
config.innerInstructions = configOrSigners.innerInstructions;
}
const args = [encodedTransaction, config];
const unsafeRes = await this._rpcRequest('simulateTransaction', args);
const res = superstruct.create(unsafeRes, SimulatedTransactionResponseStruct);
if ('error' in res) {
throw new Error('failed to simulate transaction: ' + res.error.message);
}
return res.result;
}
let transaction;
if (transactionOrMessage instanceof Transaction) {
let originalTx = transactionOrMessage;
transaction = new Transaction();
transaction.feePayer = originalTx.feePayer;
transaction.instructions = transactionOrMessage.instructions;
transaction.nonceInfo = originalTx.nonceInfo;
transaction.signatures = originalTx.signatures;
} else {
transaction = Transaction.populate(transactionOrMessage);
// HACK: this function relies on mutating the populated transaction
transaction._message = transaction._json = undefined;
}
if (configOrSigners !== undefined && !Array.isArray(configOrSigners)) {
throw new Error('Invalid arguments');
}
const signers = configOrSigners;
if (transaction.nonceInfo && signers) {
transaction.sign(...signers);
} else {
let disableCache = this._disableBlockhashCaching;
for (;;) {
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
transaction.recentBlockhash = latestBlockhash.blockhash;
if (!signers) break;
transaction.sign(...signers);
if (!transaction.signature) {
throw new Error('!signature'); // should never happen
}
const signature = transaction.signature.toString('base64');
if (!this._blockhashInfo.simulatedSignatures.includes(signature) && !this._blockhashInfo.transactionSignatures.includes(signature)) {
// The signature of this transaction has not been seen before with the
// current recentBlockhash, all done. Let's break
this._blockhashInfo.simulatedSignatures.push(signature);
break;
} else {
// This transaction would be treated as duplicate (its derived signature
// matched to one of already recorded signatures).
// So, we must fetch a new blockhash for a different signature by disabling
// our cache not to wait for the cache expiration (BLOCKHASH_CACHE_TIMEOUT_MS).
disableCache = true;
}
}
}
const message = transaction._compile();
const signData = message.serialize();
const wireTransaction = transaction._serialize(signData);
const encodedTransaction = wireTransaction.toString('base64');
const config = {
encoding: 'base64',
commitment: this.commitment
};
if (includeAccounts) {
const addresses = (Array.isArray(includeAccounts) ? includeAccounts : message.nonProgramIds()).map(key => key.toBase58());
config['accounts'] = {
encoding: 'base64',
addresses
};
}
if (signers) {
config.sigVerify = true;
}
if (configOrSigners && typeof configOrSigners === 'object' && 'innerInstructions' in configOrSigners) {
config.innerInstructions = configOrSigners.innerInstructions;
}
const args = [encodedTransaction, config];
const unsafeRes = await this._rpcRequest('simulateTransaction', args);
const res = superstruct.create(unsafeRes, SimulatedTransactionResponseStruct);
if ('error' in res) {
let logs;
if ('data' in res.error) {
logs = res.error.data.logs;
if (logs && Array.isArray(logs)) {
const traceIndent = '\n ';
const logTrace = traceIndent + logs.join(traceIndent);
console.error(res.error.message, logTrace);
}
}
throw new SendTransactionError({
action: 'simulate',
signature: '',
transactionMessage: res.error.message,
logs: logs
});
}
return res.result;
}
/**
* Sign and send a transaction
*
* @deprecated Instead, call {@link sendTransaction} with a {@link
* VersionedTransaction}
*/
/**
* Send a signed transaction
*/
// eslint-disable-next-line no-dupe-class-members
/**
* Sign and send a transaction
*/
// eslint-disable-next-line no-dupe-class-members
async sendTransaction(transaction, signersOrOptions, options) {
if ('version' in transaction) {
if (signersOrOptions && Array.isArray(signersOrOptions)) {
throw new Error('Invalid arguments');
}
const wireTransaction = transaction.serialize();
return await this.sendRawTransaction(wireTransaction, signersOrOptions);
}
if (signersOrOptions === undefined || !Array.isArray(signersOrOptions)) {
throw new Error('Invalid arguments');
}
const signers = signersOrOptions;
if (transaction.nonceInfo) {
transaction.sign(...signers);
} else {
let disableCache = this._disableBlockhashCaching;
for (;;) {
const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
transaction.recentBlockhash = latestBlockhash.blockhash;
transaction.sign(...signers);
if (!transaction.signature) {
throw new Error('!signature'); // should never happen
}
const signature = transaction.signature.toString('base64');
if (!this._blockhashInfo.transactionSignatures.includes(signature)) {
// The signature of this transaction has not been seen before with the
// current recentBlockhash, all done. Let's break
this._blockhashInfo.transactionSignatures.push(signature);
break;
} else {
// This transaction would be treated as duplicate (its derived signature
// matched to one of already recorded signatures).
// So, we must fetch a new blockhash for a different signature by disabling
// our cache not to wait for the cache expiration (BLOCKHASH_CACHE_TIMEOUT_MS).
disableCache = true;
}
}
}
const wireTransaction = transaction.serialize();
return await this.sendRawTransaction(wireTransaction, options);
}
/**
* Send a transaction that has already been signed and serialized into the
* wire format
*/
async sendRawTransaction(rawTransaction, options) {
const encodedTransaction = toBuffer(rawTransaction).toString('base64');
const result = await this.sendEncodedTransaction(encodedTransaction, options);
return result;
}
/**
* Send a transaction that has already been signed, serialized into the
* wire format, and encoded as a base64 string
*/
async sendEncodedTransaction(encodedTransaction, options) {
const config = {
encoding: 'base64'
};
const skipPreflight = options && options.skipPreflight;
const preflightCommitment = skipPreflight === true ? 'processed' // FIXME Remove when https://github.com/anza-xyz/agave/pull/483 is deployed.
: options && options.preflightCommitment || this.commitment;
if (options && options.maxRetries != null) {
config.maxRetries = options.maxRetries;
}
if (options && options.minContextSlot != null) {
config.minContextSlot = options.minContextSlot;
}
if (skipPreflight) {
config.skipPreflight = skipPreflight;
}
if (preflightCommitment) {
config.preflightCommitment = preflightCommitment;
}
const args = [encodedTransaction, config];
const unsafeRes = await this._rpcRequest('sendTransaction', args);
const res = superstruct.create(unsafeRes, SendTransactionRpcResult);
if ('error' in res) {
let logs = undefined;
if ('data' in res.error) {
logs = res.error.data.logs;
}
throw new SendTransactionError({
action: skipPreflight ? 'send' : 'simulate',
signature: '',
transactionMessage: res.error.message,
logs: logs
});
}
return res.result;
}
/**
* @internal
*/
_wsOnOpen() {
this._rpcWebSocketConnected = true;
this._rpcWebSocketHeartbeat = setInterval(() => {
// Ping server every 5s to prevent idle timeouts
(async () => {
try {
await this._rpcWebSocket.notify('ping');
// eslint-disable-next-line no-empty
} catch {}
})();
}, 5000);
this._updateSubscriptions();
}
/**
* @internal
*/
_wsOnError(err) {
this._rpcWebSocketConnected = false;
console.error('ws error:', err.message);
}
/**
* @internal
*/
_wsOnClose(code) {
this._rpcWebSocketConnected = false;
this._rpcWebSocketGeneration = (this._rpcWebSocketGeneration + 1) % Number.MAX_SAFE_INTEGER;
if (this._rpcWebSocketIdleTimeout) {
clearTimeout(this._rpcWebSocketIdleTimeout);
this._rpcWebSocketIdleTimeout = null;
}
if (this._rpcWebSocketHeartbeat) {
clearInterval(this._rpcWebSocketHeartbeat);
this._rpcWebSocketHeartbeat = null;
}
if (code === 1000) {
// explicit close, check if any subscriptions have been made since close
this._updateSubscriptions();
return;
}
// implicit close, prepare subscriptions for auto-reconnect
this._subscriptionCallbacksByServerSubscriptionId = {};
Object.entries(this._subscriptionsByHash).forEach(([hash, subscription]) => {
this._setSubscription(hash, {
...subscription,
state: 'pending'
});
});
}
/**
* @internal
*/
_setSubscription(hash, nextSubscription) {
const prevState = this._subscriptionsByHash[hash]?.state;
this._subscriptionsByHash[hash] = nextSubscription;
if (prevState !== nextSubscription.state) {
const stateChangeCallbacks = this._subscriptionStateChangeCallbacksByHash[hash];
if (stateChangeCallbacks) {
stateChangeCallbacks.forEach(cb => {
try {
cb(nextSubscription.state);
// eslint-disable-next-line no-empty
} catch {}
});
}
}
}
/**
* @internal
*/
_onSubscriptionStateChange(clientSubscriptionId, callback) {
const hash = this._subscriptionHashByClientSubscriptionId[clientSubscriptionId];
if (hash == null) {
return () => {};
}
const stateChangeCallbacks = this._subscriptionStateChangeCallbacksByHash[hash] ||= new Set();
stateChangeCallbacks.add(callback);
return () => {
stateChangeCallbacks.delete(callback);
if (stateChangeCallbacks.size === 0) {
delete this._subscriptionStateChangeCallbacksByHash[hash];
}
};
}
/**
* @internal
*/
async _updateSubscriptions() {
if (Object.keys(this._subscriptionsByHash).length === 0) {
if (this._rpcWebSocketConnected) {
this._rpcWebSocketConnected = false;
this._rpcWebSocketIdleTimeout = setTimeout(() => {
this._rpcWebSocketIdleTimeout = null;
try {
this._rpcWebSocket.close();
} catch (err) {
// swallow error if socket has already been closed.
if (err instanceof Error) {
console.log(`Error when closing socket connection: ${err.message}`);
}
}
}, 500);
}
return;
}
if (this._rpcWebSocketIdleTimeout !== null) {
clearTimeout(this._rpcWebSocketIdleTimeout);
this._rpcWebSocketIdleTimeout = null;
this._rpcWebSocketConnected = true;
}
if (!this._rpcWebSocketConnected) {
this._rpcWebSocket.connect();
return;
}
const activeWebSocketGeneration = this._rpcWebSocketGeneration;
const isCurrentConnectionStillActive = () => {
return activeWebSocketGeneration === this._rpcWebSocketGeneration;
};
await Promise.all(
// Don't be tempted to change this to `Object.entries`. We call
// `_updateSubscriptions` recursively when processing the state,
// so it's important that we look up the *current* version of
// each subscription, every time we process a hash.
Object.keys(this._subscriptionsByHash).map(async hash => {
const subscription = this._subscriptionsByHash[hash];
if (subscription === undefined) {
// This entry has since been deleted. Skip.
return;
}
switch (subscription.state) {
case 'pending':
case 'unsubscribed':
if (subscription.callbacks.size === 0) {
/**
* You can end up here when:
*
* - a subscription has recently unsubscribed
* without having new callbacks added to it
* while the unsubscribe was in flight, or
* - when a pending subscription has its
* listeners removed before a request was
* sent to the server.
*
* Being that nobody is interested in this
* subscription any longer, delete it.
*/
delete this._subscriptionsByHash[hash];
if (subscription.state === 'unsubscribed') {
delete this._subscriptionCallbacksByServerSubscriptionId[subscription.serverSubscriptionId];
}
await this._updateSubscriptions();
return;
}
await (async () => {
const {
args,
method
} = subscription;
try {
this._setSubscription(hash, {
...subscription,
state: 'subscribing'
});
const serverSubscriptionId = await this._rpcWebSocket.call(method, args);
this._setSubscription(hash, {
...subscription,
serverSubscriptionId,
state: 'subscribed'
});
this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId] = subscription.callbacks;
await this._updateSubscriptions();
} catch (e) {
console.error(`Received ${e instanceof Error ? '' : 'JSON-RPC '}error calling \`${method}\``, {
args,
error: e
});
if (!isCurrentConnectionStillActive()) {
return;
}
// TODO: Maybe add an 'errored' state or a retry limit?
this._setSubscription(hash, {
...subscription,
state: 'pending'
});
await this._updateSubscriptions();
}
})();
break;
case 'subscribed':
if (subscription.callbacks.size === 0) {
// By the time we successfully set up a subscription
// with the server, the client stopped caring about it.
// Tear it down now.
await (async () => {
const {
serverSubscriptionId,
unsubscribeMethod
} = subscription;
if (this._subscriptionsAutoDisposedByRpc.has(serverSubscriptionId)) {
/**
* Special case.
* If we're dealing with a subscription that has been auto-
* disposed by the RPC, then we can skip the RPC call to
* tear down the subscription here.
*
* NOTE: There is a proposal to eliminate this special case, here:
* https://github.com/solana-labs/solana/issues/18892
*/
this._subscriptionsAutoDisposedByRpc.delete(serverSubscriptionId);
} else {
this._setSubscription(hash, {
...subscription,
state: 'unsubscribing'
});
this._setSubscription(hash, {
...subscription,
state: 'unsubscribing'
});
try {
await this._rpcWebSocket.call(unsubscribeMethod, [serverSubscriptionId]);
} catch (e) {
if (e instanceof Error) {
console.error(`${unsubscribeMethod} error:`, e.message);
}
if (!isCurrentConnectionStillActive()) {
return;
}
// TODO: Maybe add an 'errored' state or a retry limit?
this._setSubscription(hash, {
...subscription,
state: 'subscribed'
});
await this._updateSubscriptions();
return;
}
}
this._setSubscription(hash, {
...subscription,
state: 'unsubscribed'
});
await this._updateSubscriptions();
})();
}
break;
}
}));
}
/**
* @internal
*/
_handleServerNotification(serverSubscriptionId, callbackArgs) {
const callbacks = this._subscriptionCallbacksByServerSubscriptionId[serverSubscriptionId];
if (callbacks === undefined) {
return;
}
callbacks.forEach(cb => {
try {
cb(
// I failed to find a way to convince TypeScript that `cb` is of type
// `TCallback` which is certainly compatible with `Parameters<TCallback>`.
// See https://github.com/microsoft/TypeScript/issues/47615
// @ts-ignore
...callbackArgs);
} catch (e) {
console.error(e);
}
});
}
/**
* @internal
*/
_wsOnAccountNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, AccountNotificationResult);
this._handleServerNotification(subscription, [result.value, result.context]);
}
/**
* @internal
*/
_makeSubscription(subscriptionConfig,
/**
* When preparing `args` for a call to `_makeSubscription`, be sure
* to carefully apply a default `commitment` property, if necessary.
*
* - If the user supplied a `commitment` use that.
* - Otherwise, if the `Connection::commitment` is set, use that.
* - Otherwise, set it to the RPC server default: `finalized`.
*
* This is extremely important to ensure that these two fundamentally
* identical subscriptions produce the same identifying hash:
*
* - A subscription made without specifying a commitment.
* - A subscription made where the commitment specified is the same
* as the default applied to the subscription above.
*
* Example; these two subscriptions must produce the same hash:
*
* - An `accountSubscribe` subscription for `'PUBKEY'`
* - An `accountSubscribe` subscription for `'PUBKEY'` with commitment
* `'finalized'`.
*
* See the 'making a subscription with defaulted params omitted' test
* in `connection-subscriptions.ts` for more.
*/
args) {
const clientSubscriptionId = this._nextClientSubscriptionId++;
const hash = fastStableStringify([subscriptionConfig.method, args]);
const existingSubscription = this._subscriptionsByHash[hash];
if (existingSubscription === undefined) {
this._subscriptionsByHash[hash] = {
...subscriptionConfig,
args,
callbacks: new Set([subscriptionConfig.callback]),
state: 'pending'
};
} else {
existingSubscription.callbacks.add(subscriptionConfig.callback);
}
this._subscriptionHashByClientSubscriptionId[clientSubscriptionId] = hash;
this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId] = async () => {
delete this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId];
delete this._subscriptionHashByClientSubscriptionId[clientSubscriptionId];
const subscription = this._subscriptionsByHash[hash];
assert(subscription !== undefined, `Could not find a \`Subscription\` when tearing down client subscription #${clientSubscriptionId}`);
subscription.callbacks.delete(subscriptionConfig.callback);
await this._updateSubscriptions();
};
this._updateSubscriptions();
return clientSubscriptionId;
}
/**
* Register a callback to be invoked whenever the specified account changes
*
* @param publicKey Public key of the account to monitor
* @param callback Function to invoke whenever the account is changed
* @param config
* @return subscription id
*/
/** @deprecated Instead, pass in an {@link AccountSubscriptionConfig} */
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
onAccountChange(publicKey, callback, commitmentOrConfig) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([publicKey.toBase58()], commitment || this._commitment || 'finalized',
// Apply connection/server default.
'base64', config);
return this._makeSubscription({
callback,
method: 'accountSubscribe',
unsubscribeMethod: 'accountUnsubscribe'
}, args);
}
/**
* Deregister an account notification callback
*
* @param clientSubscriptionId client subscription id to deregister
*/
async removeAccountChangeListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'account change');
}
/**
* @internal
*/
_wsOnProgramAccountNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, ProgramAccountNotificationResult);
this._handleServerNotification(subscription, [{
accountId: result.value.pubkey,
accountInfo: result.value.account
}, result.context]);
}
/**
* Register a callback to be invoked whenever accounts owned by the
* specified program change
*
* @param programId Public key of the program to monitor
* @param callback Function to invoke whenever the account is changed
* @param config
* @return subscription id
*/
/** @deprecated Instead, pass in a {@link ProgramAccountSubscriptionConfig} */
// eslint-disable-next-line no-dupe-class-members
// eslint-disable-next-line no-dupe-class-members
onProgramAccountChange(programId, callback, commitmentOrConfig, maybeFilters) {
const {
commitment,
config
} = extractCommitmentFromConfig(commitmentOrConfig);
const args = this._buildArgs([programId.toBase58()], commitment || this._commitment || 'finalized',
// Apply connection/server default.
'base64' /* encoding */, config ? config : maybeFilters ? {
filters: applyDefaultMemcmpEncodingToFilters(maybeFilters)
} : undefined /* extra */);
return this._makeSubscription({
callback,
method: 'programSubscribe',
unsubscribeMethod: 'programUnsubscribe'
}, args);
}
/**
* Deregister an account notification callback
*
* @param clientSubscriptionId client subscription id to deregister
*/
async removeProgramAccountChangeListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'program account change');
}
/**
* Registers a callback to be invoked whenever logs are emitted.
*/
onLogs(filter, callback, commitment) {
const args = this._buildArgs([typeof filter === 'object' ? {
mentions: [filter.toString()]
} : filter], commitment || this._commitment || 'finalized' // Apply connection/server default.
);
return this._makeSubscription({
callback,
method: 'logsSubscribe',
unsubscribeMethod: 'logsUnsubscribe'
}, args);
}
/**
* Deregister a logs callback.
*
* @param clientSubscriptionId client subscription id to deregister.
*/
async removeOnLogsListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'logs');
}
/**
* @internal
*/
_wsOnLogsNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, LogsNotificationResult);
this._handleServerNotification(subscription, [result.value, result.context]);
}
/**
* @internal
*/
_wsOnSlotNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, SlotNotificationResult);
this._handleServerNotification(subscription, [result]);
}
/**
* Register a callback to be invoked upon slot changes
*
* @param callback Function to invoke whenever the slot changes
* @return subscription id
*/
onSlotChange(callback) {
return this._makeSubscription({
callback,
method: 'slotSubscribe',
unsubscribeMethod: 'slotUnsubscribe'
}, [] /* args */);
}
/**
* Deregister a slot notification callback
*
* @param clientSubscriptionId client subscription id to deregister
*/
async removeSlotChangeListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'slot change');
}
/**
* @internal
*/
_wsOnSlotUpdatesNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, SlotUpdateNotificationResult);
this._handleServerNotification(subscription, [result]);
}
/**
* Register a callback to be invoked upon slot updates. {@link SlotUpdate}'s
* may be useful to track live progress of a cluster.
*
* @param callback Function to invoke whenever the slot updates
* @return subscription id
*/
onSlotUpdate(callback) {
return this._makeSubscription({
callback,
method: 'slotsUpdatesSubscribe',
unsubscribeMethod: 'slotsUpdatesUnsubscribe'
}, [] /* args */);
}
/**
* Deregister a slot update notification callback
*
* @param clientSubscriptionId client subscription id to deregister
*/
async removeSlotUpdateListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'slot update');
}
/**
* @internal
*/
async _unsubscribeClientSubscription(clientSubscriptionId, subscriptionName) {
const dispose = this._subscriptionDisposeFunctionsByClientSubscriptionId[clientSubscriptionId];
if (dispose) {
await dispose();
} else {
console.warn('Ignored unsubscribe request because an active subscription with id ' + `\`${clientSubscriptionId}\` for '${subscriptionName}' events ` + 'could not be found.');
}
}
_buildArgs(args, override, encoding, extra) {
const commitment = override || this._commitment;
if (commitment || encoding || extra) {
let options = {};
if (encoding) {
options.encoding = encoding;
}
if (commitment) {
options.commitment = commitment;
}
if (extra) {
options = Object.assign(options, extra);
}
args.push(options);
}
return args;
}
/**
* @internal
*/
_buildArgsAtLeastConfirmed(args, override, encoding, extra) {
const commitment = override || this._commitment;
if (commitment && !['confirmed', 'finalized'].includes(commitment)) {
throw new Error('Using Connection with default commitment: `' + this._commitment + '`, but method requires at least `confirmed`');
}
return this._buildArgs(args, override, encoding, extra);
}
/**
* @internal
*/
_wsOnSignatureNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, SignatureNotificationResult);
if (result.value !== 'receivedSignature') {
/**
* Special case.
* After a signature is processed, RPCs automatically dispose of the
* subscription on the server side. We need to track which of these
* subscriptions have been disposed in such a way, so that we know
* whether the client is dealing with a not-yet-processed signature
* (in which case we must tear down the server subscription) or an
* already-processed signature (in which case the client can simply
* clear out the subscription locally without telling the server).
*
* NOTE: There is a proposal to eliminate this special case, here:
* https://github.com/solana-labs/solana/issues/18892
*/
this._subscriptionsAutoDisposedByRpc.add(subscription);
}
this._handleServerNotification(subscription, result.value === 'receivedSignature' ? [{
type: 'received'
}, result.context] : [{
type: 'status',
result: result.value
}, result.context]);
}
/**
* Register a callback to be invoked upon signature updates
*
* @param signature Transaction signature string in base 58
* @param callback Function to invoke on signature notifications
* @param commitment Specify the commitment level signature must reach before notification
* @return subscription id
*/
onSignature(signature, callback, commitment) {
const args = this._buildArgs([signature], commitment || this._commitment || 'finalized' // Apply connection/server default.
);
const clientSubscriptionId = this._makeSubscription({
callback: (notification, context) => {
if (notification.type === 'status') {
callback(notification.result, context);
// Signatures subscriptions are auto-removed by the RPC service
// so no need to explicitly send an unsubscribe message.
try {
this.removeSignatureListener(clientSubscriptionId);
// eslint-disable-next-line no-empty
} catch (_err) {
// Already removed.
}
}
},
method: 'signatureSubscribe',
unsubscribeMethod: 'signatureUnsubscribe'
}, args);
return clientSubscriptionId;
}
/**
* Register a callback to be invoked when a transaction is
* received and/or processed.
*
* @param signature Transaction signature string in base 58
* @param callback Function to invoke on signature notifications
* @param options Enable received notifications and set the commitment
* level that signature must reach before notification
* @return subscription id
*/
onSignatureWithOptions(signature, callback, options) {
const {
commitment,
...extra
} = {
...options,
commitment: options && options.commitment || this._commitment || 'finalized' // Apply connection/server default.
};
const args = this._buildArgs([signature], commitment, undefined /* encoding */, extra);
const clientSubscriptionId = this._makeSubscription({
callback: (notification, context) => {
callback(notification, context);
// Signatures subscriptions are auto-removed by the RPC service
// so no need to explicitly send an unsubscribe message.
try {
this.removeSignatureListener(clientSubscriptionId);
// eslint-disable-next-line no-empty
} catch (_err) {
// Already removed.
}
},
method: 'signatureSubscribe',
unsubscribeMethod: 'signatureUnsubscribe'
}, args);
return clientSubscriptionId;
}
/**
* Deregister a signature notification callback
*
* @param clientSubscriptionId client subscription id to deregister
*/
async removeSignatureListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'signature result');
}
/**
* @internal
*/
_wsOnRootNotification(notification) {
const {
result,
subscription
} = superstruct.create(notification, RootNotificationResult);
this._handleServerNotification(subscription, [result]);
}
/**
* Register a callback to be invoked upon root changes
*
* @param callback Function to invoke whenever the root changes
* @return subscription id
*/
onRootChange(callback) {
return this._makeSubscription({
callback,
method: 'rootSubscribe',
unsubscribeMethod: 'rootUnsubscribe'
}, [] /* args */);
}
/**
* Deregister a root notification callback
*
* @param clientSubscriptionId client subscription id to deregister
*/
async removeRootChangeListener(clientSubscriptionId) {
await this._unsubscribeClientSubscription(clientSubscriptionId, 'root change');
}
}
/**
* Keypair signer interface
*/
/**
* An account keypair used for signing transactions.
*/
class Keypair {
/**
* Create a new keypair instance.
* Generate random keypair if no {@link Ed25519Keypair} is provided.
*
* @param {Ed25519Keypair} keypair ed25519 keypair
*/
constructor(keypair) {
this._keypair = void 0;
this._keypair = keypair ?? generateKeypair();
}
/**
* Generate a new random keypair
*
* @returns {Keypair} Keypair
*/
static generate() {
return new Keypair(generateKeypair());
}
/**
* Create a keypair from a raw secret key byte array.
*
* This method should only be used to recreate a keypair from a previously
* generated secret key. Generating keypairs from a random seed should be done
* with the {@link Keypair.fromSeed} method.
*
* @throws error if the provided secret key is invalid and validation is not skipped.
*
* @param secretKey secret key byte array
* @param options skip secret key validation
*
* @returns {Keypair} Keypair
*/
static fromSecretKey(secretKey, options) {
if (secretKey.byteLength !== 64) {
throw new Error('bad secret key size');
}
const publicKey = secretKey.slice(32, 64);
if (!options || !options.skipValidation) {
const privateScalar = secretKey.slice(0, 32);
const computedPublicKey = getPublicKey(privateScalar);
for (let ii = 0; ii < 32; ii++) {
if (publicKey[ii] !== computedPublicKey[ii]) {
throw new Error('provided secretKey is invalid');
}
}
}
return new Keypair({
publicKey,
secretKey
});
}
/**
* Generate a keypair from a 32 byte seed.
*
* @param seed seed byte array
*
* @returns {Keypair} Keypair
*/
static fromSeed(seed) {
const publicKey = getPublicKey(seed);
const secretKey = new Uint8Array(64);
secretKey.set(seed);
secretKey.set(publicKey, 32);
return new Keypair({
publicKey,
secretKey
});
}
/**
* The public key for this keypair
*
* @returns {PublicKey} PublicKey
*/
get publicKey() {
return new PublicKey(this._keypair.publicKey);
}
/**
* The raw secret key for this keypair
* @returns {Uint8Array} Secret key in an array of Uint8 bytes
*/
get secretKey() {
return new Uint8Array(this._keypair.secretKey);
}
}
/**
* An enumeration of valid LookupTableInstructionType's
*/
/**
* An enumeration of valid address lookup table InstructionType's
* @internal
*/
const LOOKUP_TABLE_INSTRUCTION_LAYOUTS = Object.freeze({
CreateLookupTable: {
index: 0,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), u64('recentSlot'), BufferLayout__namespace.u8('bumpSeed')])
},
FreezeLookupTable: {
index: 1,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
ExtendLookupTable: {
index: 2,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), u64(), BufferLayout__namespace.seq(publicKey(), BufferLayout__namespace.offset(BufferLayout__namespace.u32(), -8), 'addresses')])
},
DeactivateLookupTable: {
index: 3,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
CloseLookupTable: {
index: 4,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
}
});
class AddressLookupTableInstruction {
/**
* @internal
*/
constructor() {}
static decodeInstructionType(instruction) {
this.checkProgramId(instruction.programId);
const instructionTypeLayout = BufferLayout__namespace.u32('instruction');
const index = instructionTypeLayout.decode(instruction.data);
let type;
for (const [layoutType, layout] of Object.entries(LOOKUP_TABLE_INSTRUCTION_LAYOUTS)) {
if (layout.index == index) {
type = layoutType;
break;
}
}
if (!type) {
throw new Error('Invalid Instruction. Should be a LookupTable Instruction');
}
return type;
}
static decodeCreateLookupTable(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeysLength(instruction.keys, 4);
const {
recentSlot
} = decodeData$1(LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable, instruction.data);
return {
authority: instruction.keys[1].pubkey,
payer: instruction.keys[2].pubkey,
recentSlot: Number(recentSlot)
};
}
static decodeExtendLookupTable(instruction) {
this.checkProgramId(instruction.programId);
if (instruction.keys.length < 2) {
throw new Error(`invalid instruction; found ${instruction.keys.length} keys, expected at least 2`);
}
const {
addresses
} = decodeData$1(LOOKUP_TABLE_INSTRUCTION_LAYOUTS.ExtendLookupTable, instruction.data);
return {
lookupTable: instruction.keys[0].pubkey,
authority: instruction.keys[1].pubkey,
payer: instruction.keys.length > 2 ? instruction.keys[2].pubkey : undefined,
addresses: addresses.map(buffer => new PublicKey(buffer))
};
}
static decodeCloseLookupTable(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeysLength(instruction.keys, 3);
return {
lookupTable: instruction.keys[0].pubkey,
authority: instruction.keys[1].pubkey,
recipient: instruction.keys[2].pubkey
};
}
static decodeFreezeLookupTable(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeysLength(instruction.keys, 2);
return {
lookupTable: instruction.keys[0].pubkey,
authority: instruction.keys[1].pubkey
};
}
static decodeDeactivateLookupTable(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeysLength(instruction.keys, 2);
return {
lookupTable: instruction.keys[0].pubkey,
authority: instruction.keys[1].pubkey
};
}
/**
* @internal
*/
static checkProgramId(programId) {
if (!programId.equals(AddressLookupTableProgram.programId)) {
throw new Error('invalid instruction; programId is not AddressLookupTable Program');
}
}
/**
* @internal
*/
static checkKeysLength(keys, expectedLength) {
if (keys.length < expectedLength) {
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
}
}
}
class AddressLookupTableProgram {
/**
* @internal
*/
constructor() {}
static createLookupTable(params) {
const [lookupTableAddress, bumpSeed] = PublicKey.findProgramAddressSync([params.authority.toBuffer(), codecsNumbers.getU64Encoder().encode(params.recentSlot)], this.programId);
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable;
const data = encodeData(type, {
recentSlot: BigInt(params.recentSlot),
bumpSeed: bumpSeed
});
const keys = [{
pubkey: lookupTableAddress,
isSigner: false,
isWritable: true
}, {
pubkey: params.authority,
isSigner: true,
isWritable: false
}, {
pubkey: params.payer,
isSigner: true,
isWritable: true
}, {
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false
}];
return [new TransactionInstruction({
programId: this.programId,
keys: keys,
data: data
}), lookupTableAddress];
}
static freezeLookupTable(params) {
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.FreezeLookupTable;
const data = encodeData(type);
const keys = [{
pubkey: params.lookupTable,
isSigner: false,
isWritable: true
}, {
pubkey: params.authority,
isSigner: true,
isWritable: false
}];
return new TransactionInstruction({
programId: this.programId,
keys: keys,
data: data
});
}
static extendLookupTable(params) {
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.ExtendLookupTable;
const data = encodeData(type, {
addresses: params.addresses.map(addr => addr.toBytes())
});
const keys = [{
pubkey: params.lookupTable,
isSigner: false,
isWritable: true
}, {
pubkey: params.authority,
isSigner: true,
isWritable: false
}];
if (params.payer) {
keys.push({
pubkey: params.payer,
isSigner: true,
isWritable: true
}, {
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false
});
}
return new TransactionInstruction({
programId: this.programId,
keys: keys,
data: data
});
}
static deactivateLookupTable(params) {
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.DeactivateLookupTable;
const data = encodeData(type);
const keys = [{
pubkey: params.lookupTable,
isSigner: false,
isWritable: true
}, {
pubkey: params.authority,
isSigner: true,
isWritable: false
}];
return new TransactionInstruction({
programId: this.programId,
keys: keys,
data: data
});
}
static closeLookupTable(params) {
const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CloseLookupTable;
const data = encodeData(type);
const keys = [{
pubkey: params.lookupTable,
isSigner: false,
isWritable: true
}, {
pubkey: params.authority,
isSigner: true,
isWritable: false
}, {
pubkey: params.recipient,
isSigner: false,
isWritable: true
}];
return new TransactionInstruction({
programId: this.programId,
keys: keys,
data: data
});
}
}
AddressLookupTableProgram.programId = new PublicKey('AddressLookupTab1e1111111111111111111111111');
/**
* Compute Budget Instruction class
*/
class ComputeBudgetInstruction {
/**
* @internal
*/
constructor() {}
/**
* Decode a compute budget instruction and retrieve the instruction type.
*/
static decodeInstructionType(instruction) {
this.checkProgramId(instruction.programId);
const instructionTypeLayout = BufferLayout__namespace.u8('instruction');
const typeIndex = instructionTypeLayout.decode(instruction.data);
let type;
for (const [ixType, layout] of Object.entries(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS)) {
if (layout.index == typeIndex) {
type = ixType;
break;
}
}
if (!type) {
throw new Error('Instruction type incorrect; not a ComputeBudgetInstruction');
}
return type;
}
/**
* Decode request units compute budget instruction and retrieve the instruction params.
*/
static decodeRequestUnits(instruction) {
this.checkProgramId(instruction.programId);
const {
units,
additionalFee
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits, instruction.data);
return {
units,
additionalFee
};
}
/**
* Decode request heap frame compute budget instruction and retrieve the instruction params.
*/
static decodeRequestHeapFrame(instruction) {
this.checkProgramId(instruction.programId);
const {
bytes
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame, instruction.data);
return {
bytes
};
}
/**
* Decode set compute unit limit compute budget instruction and retrieve the instruction params.
*/
static decodeSetComputeUnitLimit(instruction) {
this.checkProgramId(instruction.programId);
const {
units
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit, instruction.data);
return {
units
};
}
/**
* Decode set compute unit price compute budget instruction and retrieve the instruction params.
*/
static decodeSetComputeUnitPrice(instruction) {
this.checkProgramId(instruction.programId);
const {
microLamports
} = decodeData$1(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice, instruction.data);
return {
microLamports
};
}
/**
* @internal
*/
static checkProgramId(programId) {
if (!programId.equals(ComputeBudgetProgram.programId)) {
throw new Error('invalid instruction; programId is not ComputeBudgetProgram');
}
}
}
/**
* An enumeration of valid ComputeBudgetInstructionType's
*/
/**
* Request units instruction params
*/
/**
* Request heap frame instruction params
*/
/**
* Set compute unit limit instruction params
*/
/**
* Set compute unit price instruction params
*/
/**
* An enumeration of valid ComputeBudget InstructionType's
* @internal
*/
const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze({
RequestUnits: {
index: 0,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('units'), BufferLayout__namespace.u32('additionalFee')])
},
RequestHeapFrame: {
index: 1,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('bytes')])
},
SetComputeUnitLimit: {
index: 2,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('units')])
},
SetComputeUnitPrice: {
index: 3,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), u64('microLamports')])
}
});
/**
* Factory class for transaction instructions to interact with the Compute Budget program
*/
class ComputeBudgetProgram {
/**
* @internal
*/
constructor() {}
/**
* Public key that identifies the Compute Budget program
*/
/**
* @deprecated Instead, call {@link setComputeUnitLimit} and/or {@link setComputeUnitPrice}
*/
static requestUnits(params) {
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits;
const data = encodeData(type, params);
return new TransactionInstruction({
keys: [],
programId: this.programId,
data
});
}
static requestHeapFrame(params) {
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame;
const data = encodeData(type, params);
return new TransactionInstruction({
keys: [],
programId: this.programId,
data
});
}
static setComputeUnitLimit(params) {
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
const data = encodeData(type, params);
return new TransactionInstruction({
keys: [],
programId: this.programId,
data
});
}
static setComputeUnitPrice(params) {
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice;
const data = encodeData(type, {
microLamports: BigInt(params.microLamports)
});
return new TransactionInstruction({
keys: [],
programId: this.programId,
data
});
}
}
ComputeBudgetProgram.programId = new PublicKey('ComputeBudget111111111111111111111111111111');
const PRIVATE_KEY_BYTES$1 = 64;
const PUBLIC_KEY_BYTES$1 = 32;
const SIGNATURE_BYTES = 64;
/**
* Params for creating an ed25519 instruction using a public key
*/
/**
* Params for creating an ed25519 instruction using a private key
*/
const ED25519_INSTRUCTION_LAYOUT = BufferLayout__namespace.struct([BufferLayout__namespace.u8('numSignatures'), BufferLayout__namespace.u8('padding'), BufferLayout__namespace.u16('signatureOffset'), BufferLayout__namespace.u16('signatureInstructionIndex'), BufferLayout__namespace.u16('publicKeyOffset'), BufferLayout__namespace.u16('publicKeyInstructionIndex'), BufferLayout__namespace.u16('messageDataOffset'), BufferLayout__namespace.u16('messageDataSize'), BufferLayout__namespace.u16('messageInstructionIndex')]);
class Ed25519Program {
/**
* @internal
*/
constructor() {}
/**
* Public key that identifies the ed25519 program
*/
/**
* Create an ed25519 instruction with a public key and signature. The
* public key must be a buffer that is 32 bytes long, and the signature
* must be a buffer of 64 bytes.
*/
static createInstructionWithPublicKey(params) {
const {
publicKey,
message,
signature,
instructionIndex
} = params;
assert(publicKey.length === PUBLIC_KEY_BYTES$1, `Public Key must be ${PUBLIC_KEY_BYTES$1} bytes but received ${publicKey.length} bytes`);
assert(signature.length === SIGNATURE_BYTES, `Signature must be ${SIGNATURE_BYTES} bytes but received ${signature.length} bytes`);
const publicKeyOffset = ED25519_INSTRUCTION_LAYOUT.span;
const signatureOffset = publicKeyOffset + publicKey.length;
const messageDataOffset = signatureOffset + signature.length;
const numSignatures = 1;
const instructionData = buffer.Buffer.alloc(messageDataOffset + message.length);
const index = instructionIndex == null ? 0xffff // An index of `u16::MAX` makes it default to the current instruction.
: instructionIndex;
ED25519_INSTRUCTION_LAYOUT.encode({
numSignatures,
padding: 0,
signatureOffset,
signatureInstructionIndex: index,
publicKeyOffset,
publicKeyInstructionIndex: index,
messageDataOffset,
messageDataSize: message.length,
messageInstructionIndex: index
}, instructionData);
instructionData.fill(publicKey, publicKeyOffset);
instructionData.fill(signature, signatureOffset);
instructionData.fill(message, messageDataOffset);
return new TransactionInstruction({
keys: [],
programId: Ed25519Program.programId,
data: instructionData
});
}
/**
* Create an ed25519 instruction with a private key. The private key
* must be a buffer that is 64 bytes long.
*/
static createInstructionWithPrivateKey(params) {
const {
privateKey,
message,
instructionIndex
} = params;
assert(privateKey.length === PRIVATE_KEY_BYTES$1, `Private key must be ${PRIVATE_KEY_BYTES$1} bytes but received ${privateKey.length} bytes`);
try {
const keypair = Keypair.fromSecretKey(privateKey);
const publicKey = keypair.publicKey.toBytes();
const signature = sign(message, keypair.secretKey);
return this.createInstructionWithPublicKey({
publicKey,
message,
signature,
instructionIndex
});
} catch (error) {
throw new Error(`Error creating instruction; ${error}`);
}
}
}
Ed25519Program.programId = new PublicKey('Ed25519SigVerify111111111111111111111111111');
const ecdsaSign = (msgHash, privKey) => {
const signature = secp256k1.secp256k1.sign(msgHash, privKey);
return [signature.toCompactRawBytes(), signature.recovery];
};
secp256k1.secp256k1.utils.isValidPrivateKey;
const publicKeyCreate = secp256k1.secp256k1.getPublicKey;
const PRIVATE_KEY_BYTES = 32;
const ETHEREUM_ADDRESS_BYTES = 20;
const PUBLIC_KEY_BYTES = 64;
const SIGNATURE_OFFSETS_SERIALIZED_SIZE = 11;
/**
* Params for creating an secp256k1 instruction using a public key
*/
/**
* Params for creating an secp256k1 instruction using an Ethereum address
*/
/**
* Params for creating an secp256k1 instruction using a private key
*/
const SECP256K1_INSTRUCTION_LAYOUT = BufferLayout__namespace.struct([BufferLayout__namespace.u8('numSignatures'), BufferLayout__namespace.u16('signatureOffset'), BufferLayout__namespace.u8('signatureInstructionIndex'), BufferLayout__namespace.u16('ethAddressOffset'), BufferLayout__namespace.u8('ethAddressInstructionIndex'), BufferLayout__namespace.u16('messageDataOffset'), BufferLayout__namespace.u16('messageDataSize'), BufferLayout__namespace.u8('messageInstructionIndex'), BufferLayout__namespace.blob(20, 'ethAddress'), BufferLayout__namespace.blob(64, 'signature'), BufferLayout__namespace.u8('recoveryId')]);
class Secp256k1Program {
/**
* @internal
*/
constructor() {}
/**
* Public key that identifies the secp256k1 program
*/
/**
* Construct an Ethereum address from a secp256k1 public key buffer.
* @param {Buffer} publicKey a 64 byte secp256k1 public key buffer
*/
static publicKeyToEthAddress(publicKey) {
assert(publicKey.length === PUBLIC_KEY_BYTES, `Public key must be ${PUBLIC_KEY_BYTES} bytes but received ${publicKey.length} bytes`);
try {
return buffer.Buffer.from(sha3.keccak_256(toBuffer(publicKey))).slice(-ETHEREUM_ADDRESS_BYTES);
} catch (error) {
throw new Error(`Error constructing Ethereum address: ${error}`);
}
}
/**
* Create an secp256k1 instruction with a public key. The public key
* must be a buffer that is 64 bytes long.
*/
static createInstructionWithPublicKey(params) {
const {
publicKey,
message,
signature,
recoveryId,
instructionIndex
} = params;
return Secp256k1Program.createInstructionWithEthAddress({
ethAddress: Secp256k1Program.publicKeyToEthAddress(publicKey),
message,
signature,
recoveryId,
instructionIndex
});
}
/**
* Create an secp256k1 instruction with an Ethereum address. The address
* must be a hex string or a buffer that is 20 bytes long.
*/
static createInstructionWithEthAddress(params) {
const {
ethAddress: rawAddress,
message,
signature,
recoveryId,
instructionIndex = 0
} = params;
let ethAddress;
if (typeof rawAddress === 'string') {
if (rawAddress.startsWith('0x')) {
ethAddress = buffer.Buffer.from(rawAddress.substr(2), 'hex');
} else {
ethAddress = buffer.Buffer.from(rawAddress, 'hex');
}
} else {
ethAddress = rawAddress;
}
assert(ethAddress.length === ETHEREUM_ADDRESS_BYTES, `Address must be ${ETHEREUM_ADDRESS_BYTES} bytes but received ${ethAddress.length} bytes`);
const dataStart = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE;
const ethAddressOffset = dataStart;
const signatureOffset = dataStart + ethAddress.length;
const messageDataOffset = signatureOffset + signature.length + 1;
const numSignatures = 1;
const instructionData = buffer.Buffer.alloc(SECP256K1_INSTRUCTION_LAYOUT.span + message.length);
SECP256K1_INSTRUCTION_LAYOUT.encode({
numSignatures,
signatureOffset,
signatureInstructionIndex: instructionIndex,
ethAddressOffset,
ethAddressInstructionIndex: instructionIndex,
messageDataOffset,
messageDataSize: message.length,
messageInstructionIndex: instructionIndex,
signature: toBuffer(signature),
ethAddress: toBuffer(ethAddress),
recoveryId
}, instructionData);
instructionData.fill(toBuffer(message), SECP256K1_INSTRUCTION_LAYOUT.span);
return new TransactionInstruction({
keys: [],
programId: Secp256k1Program.programId,
data: instructionData
});
}
/**
* Create an secp256k1 instruction with a private key. The private key
* must be a buffer that is 32 bytes long.
*/
static createInstructionWithPrivateKey(params) {
const {
privateKey: pkey,
message,
instructionIndex
} = params;
assert(pkey.length === PRIVATE_KEY_BYTES, `Private key must be ${PRIVATE_KEY_BYTES} bytes but received ${pkey.length} bytes`);
try {
const privateKey = toBuffer(pkey);
const publicKey = publicKeyCreate(privateKey, false /* isCompressed */).slice(1); // throw away leading byte
const messageHash = buffer.Buffer.from(sha3.keccak_256(toBuffer(message)));
const [signature, recoveryId] = ecdsaSign(messageHash, privateKey);
return this.createInstructionWithPublicKey({
publicKey,
message,
signature,
recoveryId,
instructionIndex
});
} catch (error) {
throw new Error(`Error creating instruction; ${error}`);
}
}
}
Secp256k1Program.programId = new PublicKey('KeccakSecp256k11111111111111111111111111111');
var _Lockup;
/**
* Address of the stake config account which configures the rate
* of stake warmup and cooldown as well as the slashing penalty.
*/
const STAKE_CONFIG_ID = new PublicKey('StakeConfig11111111111111111111111111111111');
/**
* Stake account authority info
*/
class Authorized {
/**
* Create a new Authorized object
* @param staker the stake authority
* @param withdrawer the withdraw authority
*/
constructor(staker, withdrawer) {
/** stake authority */
this.staker = void 0;
/** withdraw authority */
this.withdrawer = void 0;
this.staker = staker;
this.withdrawer = withdrawer;
}
}
/**
* Stake account lockup info
*/
class Lockup {
/**
* Create a new Lockup object
*/
constructor(unixTimestamp, epoch, custodian) {
/** Unix timestamp of lockup expiration */
this.unixTimestamp = void 0;
/** Epoch of lockup expiration */
this.epoch = void 0;
/** Lockup custodian authority */
this.custodian = void 0;
this.unixTimestamp = unixTimestamp;
this.epoch = epoch;
this.custodian = custodian;
}
/**
* Default, inactive Lockup value
*/
}
_Lockup = Lockup;
Lockup.default = new _Lockup(0, 0, PublicKey.default);
/**
* Create stake account transaction params
*/
/**
* Create stake account with seed transaction params
*/
/**
* Initialize stake instruction params
*/
/**
* Delegate stake instruction params
*/
/**
* Authorize stake instruction params
*/
/**
* Authorize stake instruction params using a derived key
*/
/**
* Split stake instruction params
*/
/**
* Split with seed transaction params
*/
/**
* Withdraw stake instruction params
*/
/**
* Deactivate stake instruction params
*/
/**
* Merge stake instruction params
*/
/**
* Stake Instruction class
*/
class StakeInstruction {
/**
* @internal
*/
constructor() {}
/**
* Decode a stake instruction and retrieve the instruction type.
*/
static decodeInstructionType(instruction) {
this.checkProgramId(instruction.programId);
const instructionTypeLayout = BufferLayout__namespace.u32('instruction');
const typeIndex = instructionTypeLayout.decode(instruction.data);
let type;
for (const [ixType, layout] of Object.entries(STAKE_INSTRUCTION_LAYOUTS)) {
if (layout.index == typeIndex) {
type = ixType;
break;
}
}
if (!type) {
throw new Error('Instruction type incorrect; not a StakeInstruction');
}
return type;
}
/**
* Decode a initialize stake instruction and retrieve the instruction params.
*/
static decodeInitialize(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {
authorized,
lockup
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Initialize, instruction.data);
return {
stakePubkey: instruction.keys[0].pubkey,
authorized: new Authorized(new PublicKey(authorized.staker), new PublicKey(authorized.withdrawer)),
lockup: new Lockup(lockup.unixTimestamp, lockup.epoch, new PublicKey(lockup.custodian))
};
}
/**
* Decode a delegate stake instruction and retrieve the instruction params.
*/
static decodeDelegate(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 6);
decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Delegate, instruction.data);
return {
stakePubkey: instruction.keys[0].pubkey,
votePubkey: instruction.keys[1].pubkey,
authorizedPubkey: instruction.keys[5].pubkey
};
}
/**
* Decode an authorize stake instruction and retrieve the instruction params.
*/
static decodeAuthorize(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
newAuthorized,
stakeAuthorizationType
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Authorize, instruction.data);
const o = {
stakePubkey: instruction.keys[0].pubkey,
authorizedPubkey: instruction.keys[2].pubkey,
newAuthorizedPubkey: new PublicKey(newAuthorized),
stakeAuthorizationType: {
index: stakeAuthorizationType
}
};
if (instruction.keys.length > 3) {
o.custodianPubkey = instruction.keys[3].pubkey;
}
return o;
}
/**
* Decode an authorize-with-seed stake instruction and retrieve the instruction params.
*/
static decodeAuthorizeWithSeed(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 2);
const {
newAuthorized,
stakeAuthorizationType,
authoritySeed,
authorityOwner
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, instruction.data);
const o = {
stakePubkey: instruction.keys[0].pubkey,
authorityBase: instruction.keys[1].pubkey,
authoritySeed: authoritySeed,
authorityOwner: new PublicKey(authorityOwner),
newAuthorizedPubkey: new PublicKey(newAuthorized),
stakeAuthorizationType: {
index: stakeAuthorizationType
}
};
if (instruction.keys.length > 3) {
o.custodianPubkey = instruction.keys[3].pubkey;
}
return o;
}
/**
* Decode a split stake instruction and retrieve the instruction params.
*/
static decodeSplit(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
lamports
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Split, instruction.data);
return {
stakePubkey: instruction.keys[0].pubkey,
splitStakePubkey: instruction.keys[1].pubkey,
authorizedPubkey: instruction.keys[2].pubkey,
lamports
};
}
/**
* Decode a merge stake instruction and retrieve the instruction params.
*/
static decodeMerge(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Merge, instruction.data);
return {
stakePubkey: instruction.keys[0].pubkey,
sourceStakePubKey: instruction.keys[1].pubkey,
authorizedPubkey: instruction.keys[4].pubkey
};
}
/**
* Decode a withdraw stake instruction and retrieve the instruction params.
*/
static decodeWithdraw(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 5);
const {
lamports
} = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Withdraw, instruction.data);
const o = {
stakePubkey: instruction.keys[0].pubkey,
toPubkey: instruction.keys[1].pubkey,
authorizedPubkey: instruction.keys[4].pubkey,
lamports
};
if (instruction.keys.length > 5) {
o.custodianPubkey = instruction.keys[5].pubkey;
}
return o;
}
/**
* Decode a deactivate stake instruction and retrieve the instruction params.
*/
static decodeDeactivate(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Deactivate, instruction.data);
return {
stakePubkey: instruction.keys[0].pubkey,
authorizedPubkey: instruction.keys[2].pubkey
};
}
/**
* @internal
*/
static checkProgramId(programId) {
if (!programId.equals(StakeProgram.programId)) {
throw new Error('invalid instruction; programId is not StakeProgram');
}
}
/**
* @internal
*/
static checkKeyLength(keys, expectedLength) {
if (keys.length < expectedLength) {
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
}
}
}
/**
* An enumeration of valid StakeInstructionType's
*/
/**
* An enumeration of valid stake InstructionType's
* @internal
*/
const STAKE_INSTRUCTION_LAYOUTS = Object.freeze({
Initialize: {
index: 0,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), authorized(), lockup()])
},
Authorize: {
index: 1,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('newAuthorized'), BufferLayout__namespace.u32('stakeAuthorizationType')])
},
Delegate: {
index: 2,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
Split: {
index: 3,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.ns64('lamports')])
},
Withdraw: {
index: 4,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.ns64('lamports')])
},
Deactivate: {
index: 5,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
Merge: {
index: 7,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
AuthorizeWithSeed: {
index: 8,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('newAuthorized'), BufferLayout__namespace.u32('stakeAuthorizationType'), rustString('authoritySeed'), publicKey('authorityOwner')])
}
});
/**
* Stake authorization type
*/
/**
* An enumeration of valid StakeAuthorizationLayout's
*/
const StakeAuthorizationLayout = Object.freeze({
Staker: {
index: 0
},
Withdrawer: {
index: 1
}
});
/**
* Factory class for transactions to interact with the Stake program
*/
class StakeProgram {
/**
* @internal
*/
constructor() {}
/**
* Public key that identifies the Stake program
*/
/**
* Generate an Initialize instruction to add to a Stake Create transaction
*/
static initialize(params) {
const {
stakePubkey,
authorized,
lockup: maybeLockup
} = params;
const lockup = maybeLockup || Lockup.default;
const type = STAKE_INSTRUCTION_LAYOUTS.Initialize;
const data = encodeData(type, {
authorized: {
staker: toBuffer(authorized.staker.toBuffer()),
withdrawer: toBuffer(authorized.withdrawer.toBuffer())
},
lockup: {
unixTimestamp: lockup.unixTimestamp,
epoch: lockup.epoch,
custodian: toBuffer(lockup.custodian.toBuffer())
}
});
const instructionData = {
keys: [{
pubkey: stakePubkey,
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(params) {
const transaction = new Transaction();
transaction.add(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
}));
}
/**
* Generate a Transaction that creates a new Stake account
*/
static createAccount(params) {
const transaction = new Transaction();
transaction.add(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
}));
}
/**
* 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(params) {
const {
stakePubkey,
authorizedPubkey,
votePubkey
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.Delegate;
const data = encodeData(type);
return new Transaction().add({
keys: [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: votePubkey,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: STAKE_CONFIG_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(params) {
const {
stakePubkey,
authorizedPubkey,
newAuthorizedPubkey,
stakeAuthorizationType,
custodianPubkey
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.Authorize;
const data = encodeData(type, {
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
stakeAuthorizationType: stakeAuthorizationType.index
});
const keys = [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: true
}, {
pubkey: authorizedPubkey,
isSigner: true,
isWritable: false
}];
if (custodianPubkey) {
keys.push({
pubkey: custodianPubkey,
isSigner: true,
isWritable: false
});
}
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
/**
* Generate a Transaction that authorizes a new PublicKey as Staker
* or Withdrawer on the Stake account.
*/
static authorizeWithSeed(params) {
const {
stakePubkey,
authorityBase,
authoritySeed,
authorityOwner,
newAuthorizedPubkey,
stakeAuthorizationType,
custodianPubkey
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed;
const data = encodeData(type, {
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
stakeAuthorizationType: stakeAuthorizationType.index,
authoritySeed: authoritySeed,
authorityOwner: toBuffer(authorityOwner.toBuffer())
});
const keys = [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: authorityBase,
isSigner: true,
isWritable: false
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}];
if (custodianPubkey) {
keys.push({
pubkey: custodianPubkey,
isSigner: true,
isWritable: false
});
}
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
/**
* @internal
*/
static splitInstruction(params) {
const {
stakePubkey,
authorizedPubkey,
splitStakePubkey,
lamports
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.Split;
const data = encodeData(type, {
lamports
});
return new TransactionInstruction({
keys: [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: splitStakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: authorizedPubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
});
}
/**
* Generate a Transaction that splits Stake tokens into another stake account
*/
static split(params,
// Compute the cost of allocating the new stake account in lamports
rentExemptReserve) {
const transaction = new Transaction();
transaction.add(SystemProgram.createAccount({
fromPubkey: params.authorizedPubkey,
newAccountPubkey: params.splitStakePubkey,
lamports: rentExemptReserve,
space: this.space,
programId: this.programId
}));
return transaction.add(this.splitInstruction(params));
}
/**
* Generate a Transaction that splits Stake tokens into another account
* derived from a base public key and seed
*/
static splitWithSeed(params,
// If this stake account is new, compute the cost of allocating it in lamports
rentExemptReserve) {
const {
stakePubkey,
authorizedPubkey,
splitStakePubkey,
basePubkey,
seed,
lamports
} = params;
const transaction = new Transaction();
transaction.add(SystemProgram.allocate({
accountPubkey: splitStakePubkey,
basePubkey,
seed,
space: this.space,
programId: this.programId
}));
if (rentExemptReserve && rentExemptReserve > 0) {
transaction.add(SystemProgram.transfer({
fromPubkey: params.authorizedPubkey,
toPubkey: splitStakePubkey,
lamports: rentExemptReserve
}));
}
return transaction.add(this.splitInstruction({
stakePubkey,
authorizedPubkey,
splitStakePubkey,
lamports
}));
}
/**
* Generate a Transaction that merges Stake accounts.
*/
static merge(params) {
const {
stakePubkey,
sourceStakePubKey,
authorizedPubkey
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.Merge;
const data = encodeData(type);
return new Transaction().add({
keys: [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: sourceStakePubKey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: authorizedPubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
});
}
/**
* Generate a Transaction that withdraws deactivated Stake tokens.
*/
static withdraw(params) {
const {
stakePubkey,
authorizedPubkey,
toPubkey,
lamports,
custodianPubkey
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.Withdraw;
const data = encodeData(type, {
lamports
});
const keys = [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: toPubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_STAKE_HISTORY_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: authorizedPubkey,
isSigner: true,
isWritable: false
}];
if (custodianPubkey) {
keys.push({
pubkey: custodianPubkey,
isSigner: true,
isWritable: false
});
}
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
/**
* Generate a Transaction that deactivates Stake tokens.
*/
static deactivate(params) {
const {
stakePubkey,
authorizedPubkey
} = params;
const type = STAKE_INSTRUCTION_LAYOUTS.Deactivate;
const data = encodeData(type);
return new Transaction().add({
keys: [{
pubkey: stakePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: authorizedPubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
});
}
}
StakeProgram.programId = new PublicKey('Stake11111111111111111111111111111111111111');
/**
* Max space of a Stake account
*
* This is generated from the solana-stake-program StakeState struct as
* `StakeStateV2::size_of()`:
* https://docs.rs/solana-stake-program/latest/solana_stake_program/stake_state/enum.StakeStateV2.html
*/
StakeProgram.space = 200;
/**
* Vote account info
*/
class VoteInit {
/** [0, 100] */
constructor(nodePubkey, authorizedVoter, authorizedWithdrawer, commission) {
this.nodePubkey = void 0;
this.authorizedVoter = void 0;
this.authorizedWithdrawer = void 0;
this.commission = void 0;
this.nodePubkey = nodePubkey;
this.authorizedVoter = authorizedVoter;
this.authorizedWithdrawer = authorizedWithdrawer;
this.commission = commission;
}
}
/**
* Create vote account transaction params
*/
/**
* InitializeAccount instruction params
*/
/**
* Authorize instruction params
*/
/**
* AuthorizeWithSeed instruction params
*/
/**
* Withdraw from vote account transaction params
*/
/**
* Update validator identity (node pubkey) vote account instruction params.
*/
/**
* Vote Instruction class
*/
class VoteInstruction {
/**
* @internal
*/
constructor() {}
/**
* Decode a vote instruction and retrieve the instruction type.
*/
static decodeInstructionType(instruction) {
this.checkProgramId(instruction.programId);
const instructionTypeLayout = BufferLayout__namespace.u32('instruction');
const typeIndex = instructionTypeLayout.decode(instruction.data);
let type;
for (const [ixType, layout] of Object.entries(VOTE_INSTRUCTION_LAYOUTS)) {
if (layout.index == typeIndex) {
type = ixType;
break;
}
}
if (!type) {
throw new Error('Instruction type incorrect; not a VoteInstruction');
}
return type;
}
/**
* Decode an initialize vote instruction and retrieve the instruction params.
*/
static decodeInitializeAccount(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 4);
const {
voteInit
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.InitializeAccount, instruction.data);
return {
votePubkey: instruction.keys[0].pubkey,
nodePubkey: instruction.keys[3].pubkey,
voteInit: new VoteInit(new PublicKey(voteInit.nodePubkey), new PublicKey(voteInit.authorizedVoter), new PublicKey(voteInit.authorizedWithdrawer), voteInit.commission)
};
}
/**
* Decode an authorize instruction and retrieve the instruction params.
*/
static decodeAuthorize(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
newAuthorized,
voteAuthorizationType
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.Authorize, instruction.data);
return {
votePubkey: instruction.keys[0].pubkey,
authorizedPubkey: instruction.keys[2].pubkey,
newAuthorizedPubkey: new PublicKey(newAuthorized),
voteAuthorizationType: {
index: voteAuthorizationType
}
};
}
/**
* Decode an authorize instruction and retrieve the instruction params.
*/
static decodeAuthorizeWithSeed(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
voteAuthorizeWithSeedArgs: {
currentAuthorityDerivedKeyOwnerPubkey,
currentAuthorityDerivedKeySeed,
newAuthorized,
voteAuthorizationType
}
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, instruction.data);
return {
currentAuthorityDerivedKeyBasePubkey: instruction.keys[2].pubkey,
currentAuthorityDerivedKeyOwnerPubkey: new PublicKey(currentAuthorityDerivedKeyOwnerPubkey),
currentAuthorityDerivedKeySeed: currentAuthorityDerivedKeySeed,
newAuthorizedPubkey: new PublicKey(newAuthorized),
voteAuthorizationType: {
index: voteAuthorizationType
},
votePubkey: instruction.keys[0].pubkey
};
}
/**
* Decode a withdraw instruction and retrieve the instruction params.
*/
static decodeWithdraw(instruction) {
this.checkProgramId(instruction.programId);
this.checkKeyLength(instruction.keys, 3);
const {
lamports
} = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.Withdraw, instruction.data);
return {
votePubkey: instruction.keys[0].pubkey,
authorizedWithdrawerPubkey: instruction.keys[2].pubkey,
lamports,
toPubkey: instruction.keys[1].pubkey
};
}
/**
* @internal
*/
static checkProgramId(programId) {
if (!programId.equals(VoteProgram.programId)) {
throw new Error('invalid instruction; programId is not VoteProgram');
}
}
/**
* @internal
*/
static checkKeyLength(keys, expectedLength) {
if (keys.length < expectedLength) {
throw new Error(`invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
}
}
}
/**
* An enumeration of valid VoteInstructionType's
*/
/** @internal */
const VOTE_INSTRUCTION_LAYOUTS = Object.freeze({
InitializeAccount: {
index: 0,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), voteInit()])
},
Authorize: {
index: 1,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), publicKey('newAuthorized'), BufferLayout__namespace.u32('voteAuthorizationType')])
},
Withdraw: {
index: 3,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), BufferLayout__namespace.ns64('lamports')])
},
UpdateValidatorIdentity: {
index: 4,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction')])
},
AuthorizeWithSeed: {
index: 10,
layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32('instruction'), voteAuthorizeWithSeedArgs()])
}
});
/**
* VoteAuthorize type
*/
/**
* An enumeration of valid VoteAuthorization layouts.
*/
const VoteAuthorizationLayout = Object.freeze({
Voter: {
index: 0
},
Withdrawer: {
index: 1
}
});
/**
* Factory class for transactions to interact with the Vote program
*/
class VoteProgram {
/**
* @internal
*/
constructor() {}
/**
* Public key that identifies the Vote program
*/
/**
* Generate an Initialize instruction.
*/
static initializeAccount(params) {
const {
votePubkey,
nodePubkey,
voteInit
} = params;
const type = VOTE_INSTRUCTION_LAYOUTS.InitializeAccount;
const data = encodeData(type, {
voteInit: {
nodePubkey: toBuffer(voteInit.nodePubkey.toBuffer()),
authorizedVoter: toBuffer(voteInit.authorizedVoter.toBuffer()),
authorizedWithdrawer: toBuffer(voteInit.authorizedWithdrawer.toBuffer()),
commission: voteInit.commission
}
});
const instructionData = {
keys: [{
pubkey: votePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: nodePubkey,
isSigner: true,
isWritable: false
}],
programId: this.programId,
data
};
return new TransactionInstruction(instructionData);
}
/**
* Generate a transaction that creates a new Vote account.
*/
static createAccount(params) {
const transaction = new Transaction();
transaction.add(SystemProgram.createAccount({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.votePubkey,
lamports: params.lamports,
space: this.space,
programId: this.programId
}));
return transaction.add(this.initializeAccount({
votePubkey: params.votePubkey,
nodePubkey: params.voteInit.nodePubkey,
voteInit: params.voteInit
}));
}
/**
* Generate a transaction that authorizes a new Voter or Withdrawer on the Vote account.
*/
static authorize(params) {
const {
votePubkey,
authorizedPubkey,
newAuthorizedPubkey,
voteAuthorizationType
} = params;
const type = VOTE_INSTRUCTION_LAYOUTS.Authorize;
const data = encodeData(type, {
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
voteAuthorizationType: voteAuthorizationType.index
});
const keys = [{
pubkey: votePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: authorizedPubkey,
isSigner: true,
isWritable: false
}];
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
/**
* Generate a transaction that authorizes a new Voter or Withdrawer on the Vote account
* where the current Voter or Withdrawer authority is a derived key.
*/
static authorizeWithSeed(params) {
const {
currentAuthorityDerivedKeyBasePubkey,
currentAuthorityDerivedKeyOwnerPubkey,
currentAuthorityDerivedKeySeed,
newAuthorizedPubkey,
voteAuthorizationType,
votePubkey
} = params;
const type = VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed;
const data = encodeData(type, {
voteAuthorizeWithSeedArgs: {
currentAuthorityDerivedKeyOwnerPubkey: toBuffer(currentAuthorityDerivedKeyOwnerPubkey.toBuffer()),
currentAuthorityDerivedKeySeed: currentAuthorityDerivedKeySeed,
newAuthorized: toBuffer(newAuthorizedPubkey.toBuffer()),
voteAuthorizationType: voteAuthorizationType.index
}
});
const keys = [{
pubkey: votePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: SYSVAR_CLOCK_PUBKEY,
isSigner: false,
isWritable: false
}, {
pubkey: currentAuthorityDerivedKeyBasePubkey,
isSigner: true,
isWritable: false
}];
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
/**
* Generate a transaction to withdraw from a Vote account.
*/
static withdraw(params) {
const {
votePubkey,
authorizedWithdrawerPubkey,
lamports,
toPubkey
} = params;
const type = VOTE_INSTRUCTION_LAYOUTS.Withdraw;
const data = encodeData(type, {
lamports
});
const keys = [{
pubkey: votePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: toPubkey,
isSigner: false,
isWritable: true
}, {
pubkey: authorizedWithdrawerPubkey,
isSigner: true,
isWritable: false
}];
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
/**
* Generate a transaction to withdraw safely from a Vote account.
*
* This function was created as a safeguard for vote accounts running validators, `safeWithdraw`
* checks that the withdraw amount will not exceed the specified balance while leaving enough left
* to cover rent. If you wish to close the vote account by withdrawing the full amount, call the
* `withdraw` method directly.
*/
static safeWithdraw(params, currentVoteAccountBalance, rentExemptMinimum) {
if (params.lamports > currentVoteAccountBalance - rentExemptMinimum) {
throw new Error('Withdraw will leave vote account with insufficient funds.');
}
return VoteProgram.withdraw(params);
}
/**
* Generate a transaction to update the validator identity (node pubkey) of a Vote account.
*/
static updateValidatorIdentity(params) {
const {
votePubkey,
authorizedWithdrawerPubkey,
nodePubkey
} = params;
const type = VOTE_INSTRUCTION_LAYOUTS.UpdateValidatorIdentity;
const data = encodeData(type);
const keys = [{
pubkey: votePubkey,
isSigner: false,
isWritable: true
}, {
pubkey: nodePubkey,
isSigner: true,
isWritable: false
}, {
pubkey: authorizedWithdrawerPubkey,
isSigner: true,
isWritable: false
}];
return new Transaction().add({
keys,
programId: this.programId,
data
});
}
}
VoteProgram.programId = new PublicKey('Vote111111111111111111111111111111111111111');
/**
* Max space of a Vote account
*
* This is generated from the solana-vote-program VoteState struct as
* `VoteState::size_of()`:
* https://docs.rs/solana-vote-program/1.9.5/solana_vote_program/vote_state/struct.VoteState.html#method.size_of
*
* KEEP IN SYNC WITH `VoteState::size_of()` in https://github.com/solana-labs/solana/blob/a474cb24b9238f5edcc982f65c0b37d4a1046f7e/sdk/program/src/vote/state/mod.rs#L340-L342
*/
VoteProgram.space = 3762;
const VALIDATOR_INFO_KEY = new PublicKey('Va1idator1nfo111111111111111111111111111111');
/**
* @internal
*/
/**
* Info used to identity validators.
*/
const InfoString = superstruct.type({
name: superstruct.string(),
website: superstruct.optional(superstruct.string()),
details: superstruct.optional(superstruct.string()),
iconUrl: superstruct.optional(superstruct.string()),
keybaseUsername: superstruct.optional(superstruct.string())
});
/**
* ValidatorInfo class
*/
class ValidatorInfo {
/**
* Construct a valid ValidatorInfo
*
* @param key validator public key
* @param info validator information
*/
constructor(key, info) {
/**
* validator public key
*/
this.key = void 0;
/**
* validator information
*/
this.info = void 0;
this.key = key;
this.info = info;
}
/**
* Deserialize ValidatorInfo from the config account data. Exactly two config
* keys are required in the data.
*
* @param buffer config account data
* @return null if info was not found
*/
static fromConfigData(buffer$1) {
let byteArray = [...buffer$1];
const configKeyCount = decodeLength(byteArray);
if (configKeyCount !== 2) return null;
const configKeys = [];
for (let i = 0; i < 2; i++) {
const publicKey = new PublicKey(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
const isSigner = guardedShift(byteArray) === 1;
configKeys.push({
publicKey,
isSigner
});
}
if (configKeys[0].publicKey.equals(VALIDATOR_INFO_KEY)) {
if (configKeys[1].isSigner) {
const rawInfo = rustString().decode(buffer.Buffer.from(byteArray));
const info = JSON.parse(rawInfo);
superstruct.assert(info, InfoString);
return new ValidatorInfo(configKeys[1].publicKey, info);
}
}
return null;
}
}
const VOTE_PROGRAM_ID = new PublicKey('Vote111111111111111111111111111111111111111');
/**
* History of how many credits earned by the end of each epoch
*/
/**
* See https://github.com/solana-labs/solana/blob/8a12ed029cfa38d4a45400916c2463fb82bbec8c/programs/vote_api/src/vote_state.rs#L68-L88
*
* @internal
*/
const VoteAccountLayout = BufferLayout__namespace.struct([publicKey('nodePubkey'), publicKey('authorizedWithdrawer'), BufferLayout__namespace.u8('commission'), BufferLayout__namespace.nu64(),
// votes.length
BufferLayout__namespace.seq(BufferLayout__namespace.struct([BufferLayout__namespace.nu64('slot'), BufferLayout__namespace.u32('confirmationCount')]), BufferLayout__namespace.offset(BufferLayout__namespace.u32(), -8), 'votes'), BufferLayout__namespace.u8('rootSlotValid'), BufferLayout__namespace.nu64('rootSlot'), BufferLayout__namespace.nu64(),
// authorizedVoters.length
BufferLayout__namespace.seq(BufferLayout__namespace.struct([BufferLayout__namespace.nu64('epoch'), publicKey('authorizedVoter')]), BufferLayout__namespace.offset(BufferLayout__namespace.u32(), -8), 'authorizedVoters'), BufferLayout__namespace.struct([BufferLayout__namespace.seq(BufferLayout__namespace.struct([publicKey('authorizedPubkey'), BufferLayout__namespace.nu64('epochOfLastAuthorizedSwitch'), BufferLayout__namespace.nu64('targetEpoch')]), 32, 'buf'), BufferLayout__namespace.nu64('idx'), BufferLayout__namespace.u8('isEmpty')], 'priorVoters'), BufferLayout__namespace.nu64(),
// epochCredits.length
BufferLayout__namespace.seq(BufferLayout__namespace.struct([BufferLayout__namespace.nu64('epoch'), BufferLayout__namespace.nu64('credits'), BufferLayout__namespace.nu64('prevCredits')]), BufferLayout__namespace.offset(BufferLayout__namespace.u32(), -8), 'epochCredits'), BufferLayout__namespace.struct([BufferLayout__namespace.nu64('slot'), BufferLayout__namespace.nu64('timestamp')], 'lastTimestamp')]);
/**
* VoteAccount class
*/
class VoteAccount {
/**
* @internal
*/
constructor(args) {
this.nodePubkey = void 0;
this.authorizedWithdrawer = void 0;
this.commission = void 0;
this.rootSlot = void 0;
this.votes = void 0;
this.authorizedVoters = void 0;
this.priorVoters = void 0;
this.epochCredits = void 0;
this.lastTimestamp = void 0;
this.nodePubkey = args.nodePubkey;
this.authorizedWithdrawer = args.authorizedWithdrawer;
this.commission = args.commission;
this.rootSlot = args.rootSlot;
this.votes = args.votes;
this.authorizedVoters = args.authorizedVoters;
this.priorVoters = args.priorVoters;
this.epochCredits = args.epochCredits;
this.lastTimestamp = args.lastTimestamp;
}
/**
* Deserialize VoteAccount from the account data.
*
* @param buffer account data
* @return VoteAccount
*/
static fromAccountData(buffer) {
const versionOffset = 4;
const va = VoteAccountLayout.decode(toBuffer(buffer), versionOffset);
let rootSlot = va.rootSlot;
if (!va.rootSlotValid) {
rootSlot = null;
}
return new VoteAccount({
nodePubkey: new PublicKey(va.nodePubkey),
authorizedWithdrawer: new PublicKey(va.authorizedWithdrawer),
commission: va.commission,
votes: va.votes,
rootSlot,
authorizedVoters: va.authorizedVoters.map(parseAuthorizedVoter),
priorVoters: getPriorVoters(va.priorVoters),
epochCredits: va.epochCredits,
lastTimestamp: va.lastTimestamp
});
}
}
function parseAuthorizedVoter({
authorizedVoter,
epoch
}) {
return {
epoch,
authorizedVoter: new PublicKey(authorizedVoter)
};
}
function parsePriorVoters({
authorizedPubkey,
epochOfLastAuthorizedSwitch,
targetEpoch
}) {
return {
authorizedPubkey: new PublicKey(authorizedPubkey),
epochOfLastAuthorizedSwitch,
targetEpoch
};
}
function getPriorVoters({
buf,
idx,
isEmpty
}) {
if (isEmpty) {
return [];
}
return [...buf.slice(idx + 1).map(parsePriorVoters), ...buf.slice(0, idx).map(parsePriorVoters)];
}
const endpoint = {
http: {
devnet: 'http://api.devnet.solana.com',
testnet: 'http://api.testnet.solana.com',
'mainnet-beta': 'http://api.mainnet-beta.solana.com/'
},
https: {
devnet: 'https://api.devnet.solana.com',
testnet: 'https://api.testnet.solana.com',
'mainnet-beta': 'https://api.mainnet-beta.solana.com/'
}
};
/**
* Retrieves the RPC API URL for the specified cluster
* @param {Cluster} [cluster="devnet"] - The cluster name of the RPC API URL to use. Possible options: 'devnet' | 'testnet' | 'mainnet-beta'
* @param {boolean} [tls="http"] - Use TLS when connecting to cluster.
*
* @returns {string} URL string of the RPC endpoint
*/
function clusterApiUrl(cluster, tls) {
const key = tls === false ? 'http' : 'https';
if (!cluster) {
return endpoint[key]['devnet'];
}
const url = endpoint[key][cluster];
if (!url) {
throw new Error(`Unknown ${key} cluster: ${cluster}`);
}
return url;
}
/**
* Send and confirm a raw transaction
*
* If `commitment` option is not specified, defaults to 'max' commitment.
*
* @param {Connection} connection
* @param {Buffer} rawTransaction
* @param {TransactionConfirmationStrategy} confirmationStrategy
* @param {ConfirmOptions} [options]
* @returns {Promise<TransactionSignature>}
*/
/**
* @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
* is no longer supported and will be removed in a future version.
*/
// eslint-disable-next-line no-redeclare
// eslint-disable-next-line no-redeclare
async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
let confirmationStrategy;
let options;
if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
confirmationStrategy = confirmationStrategyOrConfirmOptions;
options = maybeConfirmOptions;
} else if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'nonceValue')) {
confirmationStrategy = confirmationStrategyOrConfirmOptions;
options = maybeConfirmOptions;
} else {
options = confirmationStrategyOrConfirmOptions;
}
const sendOptions = options && {
skipPreflight: options.skipPreflight,
preflightCommitment: options.preflightCommitment || options.commitment,
minContextSlot: options.minContextSlot
};
const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
const commitment = options && options.commitment;
const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
const status = (await confirmationPromise).value;
if (status.err) {
if (signature != null) {
throw new SendTransactionError({
action: sendOptions?.skipPreflight ? 'send' : 'simulate',
signature: signature,
transactionMessage: `Status: (${JSON.stringify(status)})`
});
}
throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);
}
return signature;
}
/**
* There are 1-billion lamports in one SOL
*/
const LAMPORTS_PER_SOL = 1000000000;
exports.Account = Account;
exports.AddressLookupTableAccount = AddressLookupTableAccount;
exports.AddressLookupTableInstruction = AddressLookupTableInstruction;
exports.AddressLookupTableProgram = AddressLookupTableProgram;
exports.Authorized = Authorized;
exports.BLOCKHASH_CACHE_TIMEOUT_MS = BLOCKHASH_CACHE_TIMEOUT_MS;
exports.BPF_LOADER_DEPRECATED_PROGRAM_ID = BPF_LOADER_DEPRECATED_PROGRAM_ID;
exports.BPF_LOADER_PROGRAM_ID = BPF_LOADER_PROGRAM_ID;
exports.BpfLoader = BpfLoader;
exports.COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS;
exports.ComputeBudgetInstruction = ComputeBudgetInstruction;
exports.ComputeBudgetProgram = ComputeBudgetProgram;
exports.Connection = Connection;
exports.Ed25519Program = Ed25519Program;
exports.Enum = Enum;
exports.EpochSchedule = EpochSchedule;
exports.FeeCalculatorLayout = FeeCalculatorLayout;
exports.Keypair = Keypair;
exports.LAMPORTS_PER_SOL = LAMPORTS_PER_SOL;
exports.LOOKUP_TABLE_INSTRUCTION_LAYOUTS = LOOKUP_TABLE_INSTRUCTION_LAYOUTS;
exports.Loader = Loader;
exports.Lockup = Lockup;
exports.MAX_SEED_LENGTH = MAX_SEED_LENGTH;
exports.Message = Message;
exports.MessageAccountKeys = MessageAccountKeys;
exports.MessageV0 = MessageV0;
exports.NONCE_ACCOUNT_LENGTH = NONCE_ACCOUNT_LENGTH;
exports.NonceAccount = NonceAccount;
exports.PACKET_DATA_SIZE = PACKET_DATA_SIZE;
exports.PUBLIC_KEY_LENGTH = PUBLIC_KEY_LENGTH;
exports.PublicKey = PublicKey;
exports.SIGNATURE_LENGTH_IN_BYTES = SIGNATURE_LENGTH_IN_BYTES;
exports.SOLANA_SCHEMA = SOLANA_SCHEMA;
exports.STAKE_CONFIG_ID = STAKE_CONFIG_ID;
exports.STAKE_INSTRUCTION_LAYOUTS = STAKE_INSTRUCTION_LAYOUTS;
exports.SYSTEM_INSTRUCTION_LAYOUTS = SYSTEM_INSTRUCTION_LAYOUTS;
exports.SYSVAR_CLOCK_PUBKEY = SYSVAR_CLOCK_PUBKEY;
exports.SYSVAR_EPOCH_SCHEDULE_PUBKEY = SYSVAR_EPOCH_SCHEDULE_PUBKEY;
exports.SYSVAR_INSTRUCTIONS_PUBKEY = SYSVAR_INSTRUCTIONS_PUBKEY;
exports.SYSVAR_RECENT_BLOCKHASHES_PUBKEY = SYSVAR_RECENT_BLOCKHASHES_PUBKEY;
exports.SYSVAR_RENT_PUBKEY = SYSVAR_RENT_PUBKEY;
exports.SYSVAR_REWARDS_PUBKEY = SYSVAR_REWARDS_PUBKEY;
exports.SYSVAR_SLOT_HASHES_PUBKEY = SYSVAR_SLOT_HASHES_PUBKEY;
exports.SYSVAR_SLOT_HISTORY_PUBKEY = SYSVAR_SLOT_HISTORY_PUBKEY;
exports.SYSVAR_STAKE_HISTORY_PUBKEY = SYSVAR_STAKE_HISTORY_PUBKEY;
exports.Secp256k1Program = Secp256k1Program;
exports.SendTransactionError = SendTransactionError;
exports.SolanaJSONRPCError = SolanaJSONRPCError;
exports.SolanaJSONRPCErrorCode = SolanaJSONRPCErrorCode;
exports.StakeAuthorizationLayout = StakeAuthorizationLayout;
exports.StakeInstruction = StakeInstruction;
exports.StakeProgram = StakeProgram;
exports.Struct = Struct;
exports.SystemInstruction = SystemInstruction;
exports.SystemProgram = SystemProgram;
exports.Transaction = Transaction;
exports.TransactionExpiredBlockheightExceededError = TransactionExpiredBlockheightExceededError;
exports.TransactionExpiredNonceInvalidError = TransactionExpiredNonceInvalidError;
exports.TransactionExpiredTimeoutError = TransactionExpiredTimeoutError;
exports.TransactionInstruction = TransactionInstruction;
exports.TransactionMessage = TransactionMessage;
exports.TransactionStatus = TransactionStatus;
exports.VALIDATOR_INFO_KEY = VALIDATOR_INFO_KEY;
exports.VERSION_PREFIX_MASK = VERSION_PREFIX_MASK;
exports.VOTE_PROGRAM_ID = VOTE_PROGRAM_ID;
exports.ValidatorInfo = ValidatorInfo;
exports.VersionedMessage = VersionedMessage;
exports.VersionedTransaction = VersionedTransaction;
exports.VoteAccount = VoteAccount;
exports.VoteAuthorizationLayout = VoteAuthorizationLayout;
exports.VoteInit = VoteInit;
exports.VoteInstruction = VoteInstruction;
exports.VoteProgram = VoteProgram;
exports.clusterApiUrl = clusterApiUrl;
exports.sendAndConfirmRawTransaction = sendAndConfirmRawTransaction;
exports.sendAndConfirmTransaction = sendAndConfirmTransaction;
//# sourceMappingURL=index.cjs.js.map
Back to Directory
File Manager