2020-01-15 13:04:26 -08:00
import bs58 from 'bs58' ;
2021-02-01 18:53:24 -08:00
import { Buffer } from 'buffer' ;
2022-04-28 16:21:39 -07:00
// @ts-ignore
import fastStableStringify from 'fast-stable-stringify' ;
2021-02-25 23:06:12 -08:00
import {
type as pick ,
number ,
string ,
array ,
boolean ,
literal ,
record ,
union ,
optional ,
nullable ,
coerce ,
instance ,
create ,
tuple ,
unknown ,
2021-03-14 20:01:35 -07:00
any ,
2021-02-25 23:06:12 -08:00
} from 'superstruct' ;
import type { Struct } from 'superstruct' ;
2018-10-26 21:37:39 -07:00
import { Client as RpcWebSocketClient } from 'rpc-websockets' ;
2021-03-14 20:01:35 -07:00
import RpcClient from 'jayson/lib/client/browser' ;
2018-08-23 10:52:48 -07:00
2021-02-01 18:53:24 -08:00
import { AgentManager } from './agent-manager' ;
2021-06-09 22:47:54 -07:00
import { EpochSchedule } from './epoch-schedule' ;
2022-06-30 13:08:10 -07:00
import { SendTransactionError , SolanaJSONRPCError } from './errors' ;
2022-05-26 14:36:57 -07:00
import fetchImpl , { Response } from './fetch-impl' ;
2020-01-02 17:54:43 -08:00
import { NonceAccount } from './nonce-account' ;
2018-09-30 18:42:45 -07:00
import { PublicKey } from './publickey' ;
2021-05-07 01:59:51 -07:00
import { Signer } from './keypair' ;
2020-06-15 03:32:57 -07:00
import { MS_PER_SLOT } from './timing' ;
2022-08-31 05:46:24 -07:00
import {
Transaction ,
TransactionStatus ,
TransactionVersion ,
2022-09-06 20:53:42 -07:00
VersionedTransaction ,
2022-08-31 05:46:24 -07:00
} from './transaction' ;
import { Message , MessageHeader , MessageV0 , VersionedMessage } from './message' ;
2022-08-14 03:11:49 -07:00
import { AddressLookupTableAccount } from './programs/address-lookup-table/state' ;
2022-08-11 02:10:11 -07:00
import assert from './utils/assert' ;
import { sleep } from './utils/sleep' ;
import { toBuffer } from './utils/to-buffer' ;
2022-05-13 18:42:40 -07:00
import {
TransactionExpiredBlockheightExceededError ,
TransactionExpiredTimeoutError ,
2022-08-11 02:10:11 -07:00
} from './transaction/expiry-custom-errors' ;
import { makeWebsocketUrl } from './utils/makeWebsocketUrl' ;
2019-03-04 08:06:33 -08:00
import type { Blockhash } from './blockhash' ;
2019-06-12 14:36:05 -07:00
import type { FeeCalculator } from './fee-calculator' ;
2019-03-04 08:06:33 -08:00
import type { TransactionSignature } from './transaction' ;
2020-10-28 07:38:39 -07:00
import type { CompiledInstruction } from './message' ;
2018-08-23 10:52:48 -07:00
2021-02-25 23:06:12 -08:00
const PublicKeyFromString = coerce (
instance ( PublicKey ) ,
string ( ) ,
value = > new PublicKey ( value ) ,
) ;
const RawAccountDataResult = tuple ( [ string ( ) , literal ( 'base64' ) ] ) ;
const BufferFromRawAccountData = coerce (
instance ( Buffer ) ,
RawAccountDataResult ,
value = > Buffer . from ( value [ 0 ] , 'base64' ) ,
) ;
2021-03-14 22:08:10 -07:00
/ * *
* Attempt to use a recent blockhash for up to 30 seconds
* @internal
* /
export const BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1000 ;
2022-04-28 16:21:39 -07:00
/ * *
* HACK .
* Copied from rpc - websockets / dist / lib / client .
* Otherwise , ` yarn build ` fails with :
* https : //gist.github.com/steveluscher/c057eca81d479ef705cdb53162f9971d
* /
interface IWSRequestParams {
[ x : string ] : any ;
[ x : number ] : any ;
}
type ClientSubscriptionId = number ;
/** @internal */ type ServerSubscriptionId = number ;
/** @internal */ type SubscriptionConfigHash = string ;
/** @internal */ type SubscriptionDisposeFn = ( ) = > Promise < void > ;
/ * *
* @internal
* Every subscription contains the args used to open the subscription with
* the server , and a list of callers interested in notifications .
* /
type BaseSubscription < TMethod = SubscriptionConfig [ ' method ' ] > = Readonly < {
args : IWSRequestParams ;
callbacks : Set < Extract < SubscriptionConfig , { method : TMethod } > [ 'callback' ] > ;
} > ;
/ * *
* @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 .
* /
type StatefulSubscription = Readonly <
// New subscriptions that have not yet been
// sent to the server start in this state.
| {
state : 'pending' ;
}
// These subscriptions have been sent to the server
// and are waiting for the server to acknowledge them.
| {
state : 'subscribing' ;
}
// These subscriptions have been acknowledged by the
// server and have been assigned server subscription ids.
| {
serverSubscriptionId : ServerSubscriptionId ;
state : 'subscribed' ;
}
// These subscriptions are intended to be torn down and
// are waiting on an acknowledgement from the server.
| {
serverSubscriptionId : ServerSubscriptionId ;
state : 'unsubscribing' ;
}
// The request to tear down these subscriptions has been
// acknowledged by the server. The `serverSubscriptionId`
// is the id of the now-dead subscription.
| {
serverSubscriptionId : ServerSubscriptionId ;
state : 'unsubscribed' ;
}
> ;
/ * *
* A type that encapsulates a subscription ' s RPC method
* names and notification ( callback ) signature .
* /
type SubscriptionConfig = Readonly <
| {
callback : AccountChangeCallback ;
method : 'accountSubscribe' ;
unsubscribeMethod : 'accountUnsubscribe' ;
}
| {
callback : LogsCallback ;
method : 'logsSubscribe' ;
unsubscribeMethod : 'logsUnsubscribe' ;
}
| {
callback : ProgramAccountChangeCallback ;
method : 'programSubscribe' ;
unsubscribeMethod : 'programUnsubscribe' ;
}
| {
callback : RootChangeCallback ;
method : 'rootSubscribe' ;
unsubscribeMethod : 'rootUnsubscribe' ;
}
| {
callback : SignatureSubscriptionCallback ;
method : 'signatureSubscribe' ;
unsubscribeMethod : 'signatureUnsubscribe' ;
}
| {
callback : SlotChangeCallback ;
method : 'slotSubscribe' ;
unsubscribeMethod : 'slotUnsubscribe' ;
}
| {
callback : SlotUpdateCallback ;
method : 'slotsUpdatesSubscribe' ;
unsubscribeMethod : 'slotsUpdatesUnsubscribe' ;
}
> ;
/ * *
* @internal
* Utility type that keeps tagged unions intact while omitting properties .
* /
type DistributiveOmit < T , K extends PropertyKey > = T extends unknown
? Omit < T , K >
: never ;
/ * *
* @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 .
* /
type Subscription = BaseSubscription &
StatefulSubscription &
DistributiveOmit < SubscriptionConfig , ' callback ' > ;
2022-06-21 14:48:44 -07:00
type RpcRequest = ( methodName : string , args : Array < any > ) = > Promise < any > ;
2018-08-23 10:52:48 -07:00
2022-06-21 14:48:44 -07:00
type RpcBatchRequest = ( requests : RpcParams [ ] ) = > Promise < any [ ] > ;
2021-03-22 10:22:59 -07:00
/ * *
* @internal
* /
export type RpcParams = {
methodName : string ;
args : Array < any > ;
} ;
2021-03-14 20:01:35 -07:00
export type TokenAccountsFilter =
| {
mint : PublicKey ;
}
| {
programId : PublicKey ;
} ;
2020-07-30 21:33:54 -07:00
2020-03-23 07:19:32 -07:00
/ * *
* Extra contextual information for RPC responses
* /
2021-03-14 20:01:35 -07:00
export type Context = {
slot : number ;
2020-03-23 07:19:32 -07:00
} ;
2020-06-03 04:55:42 -07:00
/ * *
* Options for sending transactions
* /
export type SendOptions = {
2021-03-14 20:01:35 -07:00
/** disable transaction verification step */
skipPreflight? : boolean ;
/** preflight commitment level */
preflightCommitment? : Commitment ;
2022-02-03 10:54:43 -08:00
/** Maximum number of times for the RPC node to retry sending the transaction to the leader. */
maxRetries? : number ;
2022-06-29 09:22:34 -07:00
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2020-06-03 04:55:42 -07:00
} ;
/ * *
* Options for confirming transactions
* /
export type ConfirmOptions = {
2021-03-14 20:01:35 -07:00
/** disable transaction verification step */
skipPreflight? : boolean ;
/** desired commitment level */
commitment? : Commitment ;
/** preflight commitment level */
preflightCommitment? : Commitment ;
2022-02-03 10:54:43 -08:00
/** Maximum number of times for the RPC node to retry sending the transaction to the leader. */
maxRetries? : number ;
2022-06-29 09:22:34 -07:00
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2020-06-03 04:55:42 -07:00
} ;
2020-07-29 22:40:46 -07:00
/ * *
* Options for getConfirmedSignaturesForAddress2
* /
export type ConfirmedSignaturesForAddress2Options = {
2021-03-14 20:01:35 -07:00
/ * *
* Start searching backwards from this transaction signature .
* @remark If not provided the search starts from the highest max confirmed block .
* /
before? : TransactionSignature ;
2021-04-11 11:20:22 -07:00
/** Search until this transaction signature is reached, if found before `limit`. */
until? : TransactionSignature ;
2021-03-14 20:01:35 -07:00
/** Maximum transaction signatures to return (between 1 and 1,000, default: 1,000). */
limit? : number ;
2020-07-29 22:40:46 -07:00
} ;
2021-06-21 23:07:36 -07:00
/ * *
* Options for getSignaturesForAddress
* /
export type SignaturesForAddressOptions = {
/ * *
* Start searching backwards from this transaction signature .
* @remark If not provided the search starts from the highest max confirmed block .
* /
before? : TransactionSignature ;
/** Search until this transaction signature is reached, if found before `limit`. */
until? : TransactionSignature ;
/** Maximum transaction signatures to return (between 1 and 1,000, default: 1,000). */
limit? : number ;
2022-06-29 09:22:34 -07:00
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2021-06-21 23:07:36 -07:00
} ;
2020-02-14 07:01:01 -08:00
/ * *
* RPC Response with extra contextual information
* /
2021-03-14 20:01:35 -07:00
export type RpcResponseAndContext < T > = {
/** response context */
context : Context ;
/** response value */
value : T ;
2019-11-13 14:31:31 -08:00
} ;
2022-05-14 21:54:12 -07:00
export type BlockhashWithExpiryBlockHeight = Readonly < {
blockhash : Blockhash ;
lastValidBlockHeight : number ;
} > ;
2022-05-13 18:42:40 -07:00
/ * *
* A strategy for confirming transactions that uses the last valid
* block height for a given blockhash to check for transaction expiration .
* /
2022-05-17 16:59:04 -07:00
export type BlockheightBasedTransactionConfirmationStrategy = {
2022-05-13 18:42:40 -07:00
signature : TransactionSignature ;
2022-05-14 21:54:12 -07:00
} & BlockhashWithExpiryBlockHeight ;
2022-05-13 18:42:40 -07:00
2022-08-24 11:02:40 -07:00
/* @internal */
function assertEndpointUrl ( putativeUrl : string ) {
if ( /^https?:/ . test ( putativeUrl ) === false ) {
throw new TypeError ( 'Endpoint URL must start with `http:` or `https:`.' ) ;
}
return putativeUrl ;
}
2022-06-29 09:22:34 -07:00
/** @internal */
function extractCommitmentFromConfig < TConfig > (
commitmentOrConfig? : Commitment | ( { commitment? : Commitment } & TConfig ) ,
) {
let commitment : Commitment | undefined ;
let config : Omit < TConfig , ' commitment ' > | undefined ;
if ( typeof commitmentOrConfig === 'string' ) {
commitment = commitmentOrConfig ;
} else if ( commitmentOrConfig ) {
const { commitment : specifiedCommitment , . . . specifiedConfig } =
commitmentOrConfig ;
commitment = specifiedCommitment ;
config = specifiedConfig ;
}
return { commitment , config } ;
}
2019-11-13 14:31:31 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-11-13 14:31:31 -08:00
* /
2021-02-25 23:06:12 -08:00
function createRpcResult < T , U > ( result : Struct < T , U > ) {
return union ( [
pick ( {
jsonrpc : literal ( '2.0' ) ,
id : string ( ) ,
result ,
2019-11-13 14:31:31 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
pick ( {
jsonrpc : literal ( '2.0' ) ,
id : string ( ) ,
error : pick ( {
code : unknown ( ) ,
message : string ( ) ,
2021-03-14 20:01:35 -07:00
data : optional ( any ( ) ) ,
2021-02-25 23:06:12 -08:00
} ) ,
} ) ,
] ) ;
}
const UnknownRpcResult = createRpcResult ( unknown ( ) ) ;
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2021-02-25 23:06:12 -08:00
* /
function jsonRpcResult < T , U > ( schema : Struct < T , U > ) {
return coerce ( createRpcResult ( schema ) , UnknownRpcResult , value = > {
if ( 'error' in value ) {
return value ;
} else {
return {
. . . value ,
result : create ( value . result , schema ) ,
} ;
}
2020-01-08 12:59:58 -08:00
} ) ;
2019-11-13 14:31:31 -08:00
}
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-11-13 14:31:31 -08:00
* /
2021-02-25 23:06:12 -08:00
function jsonRpcResultAndContext < T , U > ( value : Struct < T , U > ) {
return jsonRpcResult (
pick ( {
context : pick ( {
slot : number ( ) ,
} ) ,
value ,
2019-11-13 14:31:31 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
) ;
2019-11-13 14:31:31 -08:00
}
2020-03-23 07:19:32 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-03-23 07:19:32 -07:00
* /
2021-02-25 23:06:12 -08:00
function notificationResultAndContext < T , U > ( value : Struct < T , U > ) {
return pick ( {
context : pick ( {
slot : number ( ) ,
2020-03-23 07:19:32 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
value ,
2020-03-23 07:19:32 -07:00
} ) ;
}
2022-08-31 05:46:24 -07:00
/ * *
* @internal
* /
function versionedMessageFromResponse (
version : TransactionVersion | undefined ,
response : MessageResponse ,
) : VersionedMessage {
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.decode ( ix . data ) ,
} ) ) ,
addressTableLookups : response.addressTableLookups ! ,
} ) ;
} else {
return new Message ( response ) ;
}
}
2019-11-11 10:01:10 -08:00
/ * *
* The level of commitment desired when querying state
2020-05-20 02:12:09 -07:00
* < pre >
2021-02-17 16:15:09 -08:00
* '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
2020-05-20 02:12:09 -07:00
* < / pre >
2019-11-11 10:01:10 -08:00
* /
2021-02-17 16:15:09 -08:00
export type Commitment =
| 'processed'
| 'confirmed'
| 'finalized'
| 'recent' // Deprecated as of v1.5.5
| 'single' // Deprecated as of v1.5.5
| 'singleGossip' // Deprecated as of v1.5.5
| 'root' // Deprecated as of v1.5.5
| 'max' ; // Deprecated as of v1.5.5
2019-11-11 10:01:10 -08:00
2021-04-19 19:03:19 -07:00
/ * *
* 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 >
* /
export type Finality = 'confirmed' | 'finalized' ;
2020-05-22 10:23:29 -07:00
/ * *
* 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 >
* /
export type LargestAccountsFilter = 'circulating' | 'nonCirculating' ;
2022-06-29 09:22:34 -07:00
/ * *
* Configuration object for changing ` getAccountInfo ` query behavior
* /
export type GetAccountInfoConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2022-10-13 20:28:00 -07:00
/** Optional data slice to limit the returned account data */
dataSlice? : DataSlice ;
2022-06-29 09:22:34 -07:00
} ;
/ * *
* Configuration object for changing ` getBalance ` query behavior
* /
export type GetBalanceConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
2022-07-21 21:02:05 -07:00
/ * *
* Configuration object for changing ` getBlock ` query behavior
* /
export type GetBlockConfig = {
/** The level of finality desired */
commitment? : Finality ;
2022-08-31 05:46:24 -07:00
} ;
/ * *
* Configuration object for changing ` getBlock ` query behavior
* /
export type GetVersionedBlockConfig = {
/** The level of finality desired */
commitment? : Finality ;
2022-07-21 21:02:05 -07:00
/** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */
maxSupportedTransactionVersion? : number ;
} ;
2022-07-22 01:02:49 -07:00
/ * *
* Configuration object for changing ` getStakeMinimumDelegation ` query behavior
* /
export type GetStakeMinimumDelegationConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
} ;
2022-06-29 09:22:34 -07:00
/ * *
* Configuration object for changing ` getBlockHeight ` query behavior
* /
export type GetBlockHeightConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for changing ` getEpochInfo ` query behavior
* /
export type GetEpochInfoConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for changing ` getInflationReward ` query behavior
* /
export type GetInflationRewardConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** An epoch for which the reward occurs. If omitted, the previous epoch will be used */
epoch? : number ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for changing ` getLatestBlockhash ` query behavior
* /
export type GetLatestBlockhashConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for changing ` getSlot ` query behavior
* /
export type GetSlotConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for changing ` getSlotLeader ` query behavior
* /
export type GetSlotLeaderConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
2022-07-21 21:02:05 -07:00
/ * *
* Configuration object for changing ` getTransaction ` query behavior
* /
export type GetTransactionConfig = {
/** The level of finality desired */
commitment? : Finality ;
2022-08-31 05:46:24 -07:00
} ;
/ * *
* Configuration object for changing ` getTransaction ` query behavior
* /
export type GetVersionedTransactionConfig = {
/** The level of finality desired */
commitment? : Finality ;
2022-07-21 21:02:05 -07:00
/** The max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned */
maxSupportedTransactionVersion? : number ;
} ;
2020-05-22 10:23:29 -07:00
/ * *
* Configuration object for changing ` getLargestAccounts ` query behavior
* /
2021-03-14 20:01:35 -07:00
export type GetLargestAccountsConfig = {
2021-03-31 03:48:41 -07:00
/** The level of commitment desired */
2021-03-14 20:01:35 -07:00
commitment? : Commitment ;
2021-03-31 03:48:41 -07:00
/** Filter largest accounts by whether they are part of the circulating supply */
2021-03-14 20:01:35 -07:00
filter? : LargestAccountsFilter ;
2020-05-22 10:23:29 -07:00
} ;
2021-10-22 13:12:49 -07:00
/ * *
* Configuration object for changing ` getSupply ` request behavior
* /
export type GetSupplyConfig = {
/** The level of commitment desired */
commitment? : Commitment ;
/** Exclude non circulating accounts list from response */
excludeNonCirculatingAccountsList? : boolean ;
} ;
2020-04-06 02:56:26 -07:00
/ * *
* Configuration object for changing query behavior
* /
export type SignatureStatusConfig = {
2021-03-31 03:48:41 -07:00
/** enable searching status history, not needed for recent transactions */
2021-03-14 20:01:35 -07:00
searchTransactionHistory : boolean ;
2020-04-06 02:56:26 -07:00
} ;
2019-04-23 09:53:26 -07:00
/ * *
* Information describing a cluster node
* /
2021-03-14 20:01:35 -07:00
export type ContactInfo = {
2021-03-31 03:48:41 -07:00
/** Identity public key of the node */
2021-03-14 20:01:35 -07:00
pubkey : string ;
2021-03-31 03:48:41 -07:00
/** Gossip network address for the node */
2021-03-14 20:01:35 -07:00
gossip : string | null ;
2021-03-31 03:48:41 -07:00
/** TPU network address for the node (null if not available) */
2021-03-14 20:01:35 -07:00
tpu : string | null ;
2021-03-31 03:48:41 -07:00
/** JSON RPC network address for the node (null if not available) */
2021-03-14 20:01:35 -07:00
rpc : string | null ;
2021-03-31 03:48:41 -07:00
/** Software version of the node (null if not available) */
2021-03-14 20:01:35 -07:00
version : string | null ;
2019-04-23 09:53:26 -07:00
} ;
2019-06-12 10:26:55 -07:00
/ * *
* Information describing a vote account
* /
2021-03-14 20:01:35 -07:00
export type VoteAccountInfo = {
2021-03-31 03:48:41 -07:00
/** Public key of the vote account */
2021-03-14 20:01:35 -07:00
votePubkey : string ;
2021-03-31 03:48:41 -07:00
/** Identity public key of the node voting with this account */
2021-03-14 20:01:35 -07:00
nodePubkey : string ;
2021-03-31 03:48:41 -07:00
/** The stake, in lamports, delegated to this vote account and activated */
2021-03-14 20:01:35 -07:00
activatedStake : number ;
2021-03-31 03:48:41 -07:00
/** Whether the vote account is staked for this epoch */
2021-03-14 20:01:35 -07:00
epochVoteAccount : boolean ;
2021-03-31 03:48:41 -07:00
/** Recent epoch voting credit history for this voter */
2021-03-14 20:01:35 -07:00
epochCredits : Array < [ number , number , number ] > ;
2021-03-31 03:48:41 -07:00
/** A percentage (0-100) of rewards payout owed to the voter */
2021-03-14 20:01:35 -07:00
commission : number ;
2021-03-31 03:48:41 -07:00
/** Most recent slot voted on by this vote account */
2021-03-14 20:01:35 -07:00
lastVote : number ;
2019-08-19 10:39:08 -07:00
} ;
/ * *
* A collection of cluster vote accounts
* /
2021-03-14 20:01:35 -07:00
export type VoteAccountStatus = {
2021-03-31 03:48:41 -07:00
/** Active vote accounts */
2021-03-14 20:01:35 -07:00
current : Array < VoteAccountInfo > ;
2021-03-31 03:48:41 -07:00
/** Inactive vote accounts */
2021-03-14 20:01:35 -07:00
delinquent : Array < VoteAccountInfo > ;
2019-06-12 10:26:55 -07:00
} ;
2019-08-28 07:21:39 -07:00
/ * *
2020-05-21 02:11:32 -07:00
* Network Inflation
2020-03-29 07:01:01 -07:00
* ( see https : //docs.solana.com/implemented-proposals/ed_overview)
2019-08-28 07:21:39 -07:00
* /
2021-03-14 20:01:35 -07:00
export type InflationGovernor = {
foundation : number ;
foundationTerm : number ;
initial : number ;
taper : number ;
terminal : number ;
2020-05-21 02:11:32 -07:00
} ;
2021-02-25 23:06:12 -08:00
const GetInflationGovernorResult = pick ( {
foundation : number ( ) ,
foundationTerm : number ( ) ,
initial : number ( ) ,
taper : number ( ) ,
terminal : number ( ) ,
2019-08-28 07:21:39 -07:00
} ) ;
2021-04-26 11:09:40 -07:00
/ * *
* The inflation reward for an epoch
* /
export type InflationReward = {
/** epoch for which the reward occurs */
epoch : number ;
/** the slot in which the rewards are effective */
effectiveSlot : number ;
/** reward amount in lamports */
amount : number ;
/** post balance of the account in lamports */
postBalance : number ;
} ;
/ * *
* Expected JSON RPC response for the "getInflationReward" message
* /
const GetInflationRewardResult = jsonRpcResult (
array (
nullable (
pick ( {
epoch : number ( ) ,
effectiveSlot : number ( ) ,
amount : number ( ) ,
postBalance : number ( ) ,
} ) ,
) ,
) ,
) ;
2019-10-29 09:50:05 -07:00
/ * *
2020-05-21 02:11:32 -07:00
* Information about the current epoch
2019-10-29 09:50:05 -07:00
* /
2021-03-14 20:01:35 -07:00
export type EpochInfo = {
epoch : number ;
slotIndex : number ;
slotsInEpoch : number ;
absoluteSlot : number ;
blockHeight? : number ;
transactionCount? : number ;
2020-05-21 02:11:32 -07:00
} ;
2021-02-25 23:06:12 -08:00
const GetEpochInfoResult = pick ( {
epoch : number ( ) ,
slotIndex : number ( ) ,
slotsInEpoch : number ( ) ,
absoluteSlot : number ( ) ,
blockHeight : optional ( number ( ) ) ,
transactionCount : optional ( number ( ) ) ,
2019-10-29 09:50:05 -07:00
} ) ;
2021-02-25 23:06:12 -08:00
const GetEpochScheduleResult = pick ( {
slotsPerEpoch : number ( ) ,
leaderScheduleSlotOffset : number ( ) ,
warmup : boolean ( ) ,
firstNormalEpoch : number ( ) ,
firstNormalSlot : number ( ) ,
2019-10-23 06:48:24 -07:00
} ) ;
2020-07-17 08:16:44 -07:00
/ * *
* Leader schedule
* ( see https : //docs.solana.com/terminology#leader-schedule)
* /
2021-03-14 20:01:35 -07:00
export type LeaderSchedule = {
[ address : string ] : number [ ] ;
2020-07-17 08:16:44 -07:00
} ;
2021-03-14 20:01:35 -07:00
const GetLeaderScheduleResult = record ( string ( ) , array ( number ( ) ) ) ;
2020-07-17 08:16:44 -07:00
2020-04-04 06:35:08 -07:00
/ * *
* Transaction error or null
* /
2021-04-04 03:02:36 -07:00
const TransactionErrorResult = nullable ( union ( [ pick ( { } ) , string ( ) ] ) ) ;
2020-04-04 06:35:08 -07:00
2020-02-03 07:22:11 -08:00
/ * *
* Signature status for a transaction
* /
2021-02-25 23:06:12 -08:00
const SignatureStatusResult = pick ( {
err : TransactionErrorResult ,
} ) ;
2020-02-03 07:22:11 -08:00
2021-03-18 18:30:36 -07:00
/ * *
* Transaction signature received notification
* /
const SignatureReceivedResult = literal ( 'receivedSignature' ) ;
2021-03-31 03:48:41 -07:00
/ * *
* Version info for a node
* /
2021-03-14 20:01:35 -07:00
export type Version = {
2021-03-31 03:48:41 -07:00
/** Version of solana-core */
2021-03-14 20:01:35 -07:00
'solana-core' : string ;
'feature-set' ? : number ;
2021-03-14 19:52:04 -07:00
} ;
const VersionResult = pick ( {
2021-02-25 23:06:12 -08:00
'solana-core' : string ( ) ,
2021-03-14 19:52:04 -07:00
'feature-set' : optional ( number ( ) ) ,
2019-11-11 17:09:00 -08:00
} ) ;
2021-09-16 14:10:28 -07:00
export type SimulatedTransactionAccountInfo = {
/** `true` if this account's data contains a loaded program */
executable : boolean ;
/** Identifier of the program that owns the account */
owner : string ;
/** Number of lamports assigned to the account */
lamports : number ;
/** Optional data assigned to the account */
data : string [ ] ;
/** Optional rent epoch info for account */
rentEpoch? : number ;
} ;
2022-07-12 05:07:17 -07:00
export type TransactionReturnDataEncoding = 'base64' ;
export type TransactionReturnData = {
programId : string ;
data : [ string , TransactionReturnDataEncoding ] ;
} ;
2022-09-06 20:53:42 -07:00
export type SimulateTransactionConfig = {
/** Optional parameter used to enable signature verification before simulation */
sigVerify? : boolean ;
/** Optional parameter used to replace the simulated transaction's recent blockhash with the latest blockhash */
replaceRecentBlockhash? : boolean ;
/** Optional parameter used to set the commitment level when selecting the latest block */
commitment? : Commitment ;
/** Optional parameter used to specify a list of account addresses to return post simulation state for */
accounts ? : {
encoding : 'base64' ;
addresses : string [ ] ;
} ;
/** Optional parameter used to specify the minimum block slot that can be used for simulation */
minContextSlot? : number ;
} ;
2021-03-14 20:01:35 -07:00
export type SimulatedTransactionResponse = {
err : TransactionError | string | null ;
logs : Array < string > | null ;
2022-02-20 22:20:11 -08:00
accounts ? : ( SimulatedTransactionAccountInfo | null ) [ ] | null ;
2021-09-16 14:10:28 -07:00
unitsConsumed? : number ;
2022-07-12 05:07:17 -07:00
returnData? : TransactionReturnData | null ;
2020-08-10 23:35:56 -07:00
} ;
2021-02-25 23:06:12 -08:00
const SimulatedTransactionResponseStruct = jsonRpcResultAndContext (
pick ( {
err : nullable ( union ( [ pick ( { } ) , string ( ) ] ) ) ,
logs : nullable ( array ( string ( ) ) ) ,
2021-09-16 14:10:28 -07:00
accounts : optional (
nullable (
array (
2022-02-20 22:20:11 -08:00
nullable (
pick ( {
executable : boolean ( ) ,
owner : string ( ) ,
lamports : number ( ) ,
data : array ( string ( ) ) ,
rentEpoch : optional ( number ( ) ) ,
} ) ,
) ,
2021-09-16 14:10:28 -07:00
) ,
) ,
) ,
unitsConsumed : optional ( number ( ) ) ,
2022-07-12 05:07:17 -07:00
returnData : optional (
nullable (
pick ( {
programId : string ( ) ,
data : tuple ( [ string ( ) , literal ( 'base64' ) ] ) ,
} ) ,
) ,
) ,
2020-08-10 23:35:56 -07:00
} ) ,
) ;
2021-03-14 20:01:35 -07:00
export type ParsedInnerInstruction = {
index : number ;
instructions : ( ParsedInstruction | PartiallyDecodedInstruction ) [ ] ;
2020-10-28 02:13:51 -07:00
} ;
2021-03-14 20:01:35 -07:00
export type TokenBalance = {
accountIndex : number ;
mint : string ;
2021-12-28 08:08:38 -08:00
owner? : string ;
2021-03-14 20:01:35 -07:00
uiTokenAmount : TokenAmount ;
2020-12-16 23:15:25 -08:00
} ;
2020-10-28 02:13:51 -07:00
/ * *
* Metadata for a parsed confirmed transaction on the ledger
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link ParsedTransactionMeta } instead .
2020-10-28 02:13:51 -07:00
* /
2022-01-27 15:43:01 -08:00
export type ParsedConfirmedTransactionMeta = ParsedTransactionMeta ;
2022-08-10 13:08:24 -07:00
/ * *
* Collection of addresses loaded by a transaction using address table lookups
* /
export type LoadedAddresses = {
writable : Array < PublicKey > ;
readonly : Array < PublicKey > ;
} ;
2022-01-27 15:43:01 -08:00
/ * *
* Metadata for a parsed transaction on the ledger
* /
export type ParsedTransactionMeta = {
2021-03-31 03:48:41 -07:00
/** The fee charged for processing the transaction */
2021-03-14 20:01:35 -07:00
fee : number ;
2021-03-31 03:48:41 -07:00
/** An array of cross program invoked parsed instructions */
2021-03-14 20:01:35 -07:00
innerInstructions? : ParsedInnerInstruction [ ] | null ;
2021-03-31 03:48:41 -07:00
/** The balances of the transaction accounts before processing */
2021-03-14 20:01:35 -07:00
preBalances : Array < number > ;
2021-03-31 03:48:41 -07:00
/** The balances of the transaction accounts after processing */
2021-03-14 20:01:35 -07:00
postBalances : Array < number > ;
2021-03-31 03:48:41 -07:00
/** An array of program log messages emitted during a transaction */
2021-03-14 20:01:35 -07:00
logMessages? : Array < string > | null ;
2021-03-31 03:48:41 -07:00
/** The token balances of the transaction accounts before processing */
2021-03-14 20:01:35 -07:00
preTokenBalances? : Array < TokenBalance > | null ;
2021-03-31 03:48:41 -07:00
/** The token balances of the transaction accounts after processing */
2021-03-14 20:01:35 -07:00
postTokenBalances? : Array < TokenBalance > | null ;
2021-03-31 03:48:41 -07:00
/** The error result of transaction processing */
2021-03-14 20:01:35 -07:00
err : TransactionError | null ;
2022-08-10 13:08:24 -07:00
/** The collection of addresses loaded using address lookup tables */
loadedAddresses? : LoadedAddresses ;
2022-09-01 11:18:43 -07:00
/** The compute units consumed after processing the transaction */
computeUnitsConsumed? : number ;
2020-10-28 02:13:51 -07:00
} ;
2021-03-14 20:01:35 -07:00
export type CompiledInnerInstruction = {
index : number ;
instructions : CompiledInstruction [ ] ;
2020-10-28 02:13:51 -07:00
} ;
2020-04-21 20:12:59 -07:00
/ * *
* Metadata for a confirmed transaction on the ledger
* /
2021-03-14 20:01:35 -07:00
export type ConfirmedTransactionMeta = {
2021-03-31 03:48:41 -07:00
/** The fee charged for processing the transaction */
2021-03-14 20:01:35 -07:00
fee : number ;
2021-03-31 03:48:41 -07:00
/** An array of cross program invoked instructions */
2021-03-14 20:01:35 -07:00
innerInstructions? : CompiledInnerInstruction [ ] | null ;
2021-03-31 03:48:41 -07:00
/** The balances of the transaction accounts before processing */
2021-03-14 20:01:35 -07:00
preBalances : Array < number > ;
2021-03-31 03:48:41 -07:00
/** The balances of the transaction accounts after processing */
2021-03-14 20:01:35 -07:00
postBalances : Array < number > ;
2021-03-31 03:48:41 -07:00
/** An array of program log messages emitted during a transaction */
2021-03-14 20:01:35 -07:00
logMessages? : Array < string > | null ;
2021-03-31 03:48:41 -07:00
/** The token balances of the transaction accounts before processing */
2021-03-14 20:01:35 -07:00
preTokenBalances? : Array < TokenBalance > | null ;
2021-03-31 03:48:41 -07:00
/** The token balances of the transaction accounts after processing */
2021-03-14 20:01:35 -07:00
postTokenBalances? : Array < TokenBalance > | null ;
2021-03-31 03:48:41 -07:00
/** The error result of transaction processing */
2021-03-14 20:01:35 -07:00
err : TransactionError | null ;
2022-08-31 05:46:24 -07:00
/** The collection of addresses loaded using address lookup tables */
loadedAddresses? : LoadedAddresses ;
2022-09-01 11:18:43 -07:00
/** The compute units consumed after processing the transaction */
computeUnitsConsumed? : number ;
2020-04-21 20:12:59 -07:00
} ;
2021-05-25 10:12:47 -07:00
/ * *
* A processed transaction from the RPC API
* /
export type TransactionResponse = {
/** The slot during which the transaction was processed */
slot : number ;
/** The transaction */
transaction : {
/** The transaction message */
message : Message ;
/** The transaction signatures */
signatures : string [ ] ;
} ;
/** Metadata produced from the transaction */
meta : ConfirmedTransactionMeta | null ;
/** The unix timestamp of when the transaction was processed */
blockTime? : number | null ;
} ;
2022-08-31 05:46:24 -07:00
/ * *
* A processed transaction from the RPC API
* /
export type VersionedTransactionResponse = {
/** The slot during which the transaction was processed */
slot : number ;
/** The transaction */
transaction : {
/** The transaction message */
message : VersionedMessage ;
/** The transaction signatures */
signatures : string [ ] ;
} ;
/** Metadata produced from the transaction */
meta : ConfirmedTransactionMeta | null ;
/** The unix timestamp of when the transaction was processed */
blockTime? : number | null ;
/** The transaction version */
version? : TransactionVersion ;
} ;
/ * *
* A processed transaction message from the RPC API
* /
type MessageResponse = {
accountKeys : string [ ] ;
header : MessageHeader ;
instructions : CompiledInstruction [ ] ;
recentBlockhash : string ;
addressTableLookups? : ParsedAddressTableLookup [ ] ;
} ;
2020-04-21 00:40:44 -07:00
/ * *
* A confirmed transaction on the ledger
2022-08-10 13:35:30 -07:00
*
* @deprecated Deprecated since Solana v1 . 8.0 .
2020-04-21 00:40:44 -07:00
* /
2021-03-14 20:01:35 -07:00
export type ConfirmedTransaction = {
2021-03-31 03:48:41 -07:00
/** The slot during which the transaction was processed */
2021-03-14 20:01:35 -07:00
slot : number ;
2021-03-31 03:48:41 -07:00
/** The details of the transaction */
2021-03-14 20:01:35 -07:00
transaction : Transaction ;
2021-03-31 03:48:41 -07:00
/** Metadata produced from the transaction */
2021-03-14 20:01:35 -07:00
meta : ConfirmedTransactionMeta | null ;
2021-03-31 03:48:41 -07:00
/** The unix timestamp of when the transaction was processed */
2021-03-14 20:01:35 -07:00
blockTime? : number | null ;
2020-04-21 00:40:44 -07:00
} ;
2020-08-06 04:16:01 -07:00
/ * *
* A partially decoded transaction instruction
* /
2021-03-14 20:01:35 -07:00
export type PartiallyDecodedInstruction = {
/** Program id called by this instruction */
programId : PublicKey ;
/** Public keys of accounts passed to this instruction */
accounts : Array < PublicKey > ;
/** Raw base-58 instruction data */
data : string ;
} ;
2020-08-06 04:16:01 -07:00
/ * *
* A parsed transaction message account
* /
2021-03-14 20:01:35 -07:00
export type ParsedMessageAccount = {
2021-03-31 03:48:41 -07:00
/** Public key of the account */
2021-03-14 20:01:35 -07:00
pubkey : PublicKey ;
2021-03-31 03:48:41 -07:00
/** Indicates if the account signed the transaction */
2021-03-14 20:01:35 -07:00
signer : boolean ;
2021-03-31 03:48:41 -07:00
/** Indicates if the account is writable for this transaction */
2021-03-14 20:01:35 -07:00
writable : boolean ;
2022-09-09 14:06:54 -07:00
/** Indicates if the account key came from the transaction or a lookup table */
source ? : 'transaction' | 'lookupTable' ;
2020-08-06 04:16:01 -07:00
} ;
/ * *
* A parsed transaction instruction
* /
2021-03-14 20:01:35 -07:00
export type ParsedInstruction = {
2021-03-31 03:48:41 -07:00
/** Name of the program for this instruction */
2021-03-14 20:01:35 -07:00
program : string ;
2021-03-31 03:48:41 -07:00
/** ID of the program for this instruction */
2021-03-14 20:01:35 -07:00
programId : PublicKey ;
2021-03-31 03:48:41 -07:00
/** Parsed instruction info */
2021-03-14 20:01:35 -07:00
parsed : any ;
} ;
2020-08-06 04:16:01 -07:00
2022-08-31 05:46:24 -07:00
/ * *
* A parsed address table lookup
* /
export type ParsedAddressTableLookup = {
/** Address lookup table account key */
accountKey : PublicKey ;
/** Parsed instruction info */
writableIndexes : number [ ] ;
/** Parsed instruction info */
readonlyIndexes : number [ ] ;
} ;
2020-08-06 04:16:01 -07:00
/ * *
* A parsed transaction message
* /
2021-03-14 20:01:35 -07:00
export type ParsedMessage = {
2021-03-31 03:48:41 -07:00
/** Accounts used in the instructions */
2021-03-14 20:01:35 -07:00
accountKeys : ParsedMessageAccount [ ] ;
2021-03-31 03:48:41 -07:00
/** The atomically executed instructions for the transaction */
2021-03-14 20:01:35 -07:00
instructions : ( ParsedInstruction | PartiallyDecodedInstruction ) [ ] ;
2021-03-31 03:48:41 -07:00
/** Recent blockhash */
2021-03-14 20:01:35 -07:00
recentBlockhash : string ;
2022-08-31 05:46:24 -07:00
/** Address table lookups used to load additional accounts */
addressTableLookups? : ParsedAddressTableLookup [ ] | null ;
2020-08-06 04:16:01 -07:00
} ;
/ * *
* A parsed transaction
* /
2021-03-14 20:01:35 -07:00
export type ParsedTransaction = {
2021-03-31 03:48:41 -07:00
/** Signatures for the transaction */
2021-03-14 20:01:35 -07:00
signatures : Array < string > ;
2021-03-31 03:48:41 -07:00
/** Message of the transaction */
2021-03-14 20:01:35 -07:00
message : ParsedMessage ;
2020-08-06 04:16:01 -07:00
} ;
/ * *
* A parsed and confirmed transaction on the ledger
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link ParsedTransactionWithMeta } instead .
* /
export type ParsedConfirmedTransaction = ParsedTransactionWithMeta ;
/ * *
* A parsed transaction on the ledger with meta
2020-08-06 04:16:01 -07:00
* /
2022-01-27 15:43:01 -08:00
export type ParsedTransactionWithMeta = {
2021-03-31 03:48:41 -07:00
/** The slot during which the transaction was processed */
2021-03-14 20:01:35 -07:00
slot : number ;
2021-03-31 03:48:41 -07:00
/** The details of the transaction */
2021-03-14 20:01:35 -07:00
transaction : ParsedTransaction ;
2021-03-31 03:48:41 -07:00
/** Metadata produced from the transaction */
2022-01-27 15:43:01 -08:00
meta : ParsedTransactionMeta | null ;
2021-03-31 03:48:41 -07:00
/** The unix timestamp of when the transaction was processed */
2021-03-14 20:01:35 -07:00
blockTime? : number | null ;
2022-08-31 05:46:24 -07:00
/** The version of the transaction message */
version? : TransactionVersion ;
2020-08-06 04:16:01 -07:00
} ;
2021-05-25 10:12:47 -07:00
/ * *
* A processed block fetched from the RPC API
* /
export type BlockResponse = {
/** Blockhash of this block */
blockhash : Blockhash ;
/** Blockhash of this block's parent */
previousBlockhash : Blockhash ;
/** Slot index of this block's parent */
parentSlot : number ;
/** Vector of transactions with status meta and original message */
transactions : Array < {
/** The transaction */
transaction : {
/** The transaction message */
message : Message ;
/** The transaction signatures */
signatures : string [ ] ;
} ;
/** Metadata produced from the transaction */
meta : ConfirmedTransactionMeta | null ;
2022-08-31 05:46:24 -07:00
/** The transaction version */
version? : TransactionVersion ;
} > ;
/** Vector of block rewards */
rewards? : Array < {
/** Public key of reward recipient */
pubkey : string ;
/** Reward value in lamports */
lamports : number ;
/** Account balance after reward is applied */
postBalance : number | null ;
/** Type of reward received */
rewardType : string | null ;
} > ;
/** The unix timestamp of when the block was processed */
blockTime : number | null ;
} ;
2022-10-11 01:13:10 -07:00
/ * *
* A block with parsed transactions
* /
export type ParsedBlockResponse = {
/** Blockhash of this block */
blockhash : Blockhash ;
/** Blockhash of this block's parent */
previousBlockhash : Blockhash ;
/** Slot index of this block's parent */
parentSlot : number ;
/** Vector of transactions with status meta and original message */
transactions : Array < {
/** The details of the transaction */
transaction : ParsedTransaction ;
/** Metadata produced from the transaction */
meta : ParsedTransactionMeta | null ;
/** The transaction version */
version? : TransactionVersion ;
} > ;
/** Vector of block rewards */
rewards? : Array < {
/** Public key of reward recipient */
pubkey : string ;
/** Reward value in lamports */
lamports : number ;
/** Account balance after reward is applied */
postBalance : number | null ;
/** Type of reward received */
rewardType : string | null ;
} > ;
/** The unix timestamp of when the block was processed */
blockTime : number | null ;
/** The number of blocks beneath this block */
blockHeight : number | null ;
} ;
2022-08-31 05:46:24 -07:00
/ * *
* A processed block fetched from the RPC API
* /
export type VersionedBlockResponse = {
/** Blockhash of this block */
blockhash : Blockhash ;
/** Blockhash of this block's parent */
previousBlockhash : Blockhash ;
/** Slot index of this block's parent */
parentSlot : number ;
/** Vector of transactions with status meta and original message */
transactions : Array < {
/** The transaction */
transaction : {
/** The transaction message */
message : VersionedMessage ;
/** The transaction signatures */
signatures : string [ ] ;
} ;
/** Metadata produced from the transaction */
meta : ConfirmedTransactionMeta | null ;
/** The transaction version */
version? : TransactionVersion ;
2021-05-25 10:12:47 -07:00
} > ;
/** Vector of block rewards */
rewards? : Array < {
/** Public key of reward recipient */
pubkey : string ;
/** Reward value in lamports */
lamports : number ;
/** Account balance after reward is applied */
postBalance : number | null ;
/** Type of reward received */
rewardType : string | null ;
} > ;
/** The unix timestamp of when the block was processed */
blockTime : number | null ;
} ;
2019-11-19 14:38:06 -08:00
/ * *
2022-08-10 13:35:30 -07:00
* A confirmed block on the ledger
*
* @deprecated Deprecated since Solana v1 . 8.0 .
2019-11-19 14:38:06 -08:00
* /
2021-03-14 20:01:35 -07:00
export type ConfirmedBlock = {
2021-03-31 03:48:41 -07:00
/** Blockhash of this block */
2021-03-14 20:01:35 -07:00
blockhash : Blockhash ;
2021-03-31 03:48:41 -07:00
/** Blockhash of this block's parent */
2021-03-14 20:01:35 -07:00
previousBlockhash : Blockhash ;
2021-03-31 03:48:41 -07:00
/** Slot index of this block's parent */
2021-03-14 20:01:35 -07:00
parentSlot : number ;
2021-03-31 03:48:41 -07:00
/** Vector of transactions and status metas */
2020-01-15 13:04:26 -08:00
transactions : Array < {
2021-03-14 20:01:35 -07:00
transaction : Transaction ;
meta : ConfirmedTransactionMeta | null ;
} > ;
2021-03-31 03:48:41 -07:00
/** Vector of block rewards */
2021-03-14 20:01:35 -07:00
rewards? : Array < {
pubkey : string ;
lamports : number ;
postBalance : number | null ;
rewardType : string | null ;
} > ;
2021-03-31 03:48:41 -07:00
/** The unix timestamp of when the block was processed */
2021-03-18 07:10:48 -07:00
blockTime : number | null ;
2019-11-19 14:38:06 -08:00
} ;
2021-04-13 23:56:08 -07:00
/ * *
2022-01-27 15:43:01 -08:00
* A Block on the ledger with signatures only
2021-04-13 23:56:08 -07:00
* /
2022-01-27 15:43:01 -08:00
export type BlockSignatures = {
2021-04-13 23:56:08 -07:00
/** Blockhash of this block */
blockhash : Blockhash ;
/** Blockhash of this block's parent */
previousBlockhash : Blockhash ;
/** Slot index of this block's parent */
parentSlot : number ;
/** Vector of signatures */
signatures : Array < string > ;
/** The unix timestamp of when the block was processed */
blockTime : number | null ;
} ;
2022-02-22 18:49:27 -08:00
/ * *
* recent block production information
* /
export type BlockProduction = Readonly < {
/** a dictionary of validator identities, as base-58 encoded strings. Value is a two element array containing the number of leader slots and the number of blocks produced */
byIdentity : Readonly < Record < string , ReadonlyArray < number > >> ;
/** Block production slot range */
range : Readonly < {
/** first slot of the block production information (inclusive) */
firstSlot : number ;
/** last slot of block production information (inclusive) */
lastSlot : number ;
} > ;
} > ;
export type GetBlockProductionConfig = {
/** Optional commitment level */
commitment? : Commitment ;
/** Slot range to return block production for. If parameter not provided, defaults to current epoch. */
range ? : {
/** first slot to return block production information for (inclusive) */
firstSlot : number ;
/** last slot to return block production information for (inclusive). If parameter not provided, defaults to the highest slot */
lastSlot? : number ;
} ;
/** Only return results for this validator identity (base-58 encoded) */
identity? : string ;
} ;
/ * *
* Expected JSON RPC response for the "getBlockProduction" message
* /
const BlockProductionResponseStruct = jsonRpcResultAndContext (
pick ( {
byIdentity : record ( string ( ) , array ( number ( ) ) ) ,
range : pick ( {
firstSlot : number ( ) ,
lastSlot : number ( ) ,
} ) ,
} ) ,
) ;
2020-10-08 20:26:58 -07:00
/ * *
* A performance sample
* /
2021-03-14 20:01:35 -07:00
export type PerfSample = {
2021-03-31 03:48:41 -07:00
/** Slot number of sample */
2021-03-14 20:01:35 -07:00
slot : number ;
2021-03-31 03:48:41 -07:00
/** Number of transactions in a sample window */
2021-03-14 20:01:35 -07:00
numTransactions : number ;
2021-03-31 03:48:41 -07:00
/** Number of slots in a sample window */
2021-03-14 20:01:35 -07:00
numSlots : number ;
2021-03-31 03:48:41 -07:00
/** Sample window in seconds */
2021-03-14 20:01:35 -07:00
samplePeriodSecs : number ;
2020-10-08 20:26:58 -07:00
} ;
2021-04-26 08:35:07 -07:00
function createRpcClient (
url : string ,
httpHeaders? : HttpHeaders ,
2022-05-26 13:17:14 -07:00
customFetch? : FetchFn ,
2021-04-26 08:35:07 -07:00
fetchMiddleware? : FetchMiddleware ,
2021-06-03 21:17:19 -07:00
disableRetryOnRateLimit? : boolean ,
2021-04-26 08:35:07 -07:00
) : RpcClient {
2022-05-26 14:36:57 -07:00
const fetch = customFetch ? customFetch : fetchImpl ;
2021-03-14 20:01:35 -07:00
let agentManager : AgentManager | undefined ;
2021-02-01 18:53:24 -08:00
if ( ! process . env . BROWSER ) {
2022-08-24 11:02:40 -07:00
agentManager = new AgentManager ( url . startsWith ( 'https:' ) /* useHttps */ ) ;
2021-02-01 18:53:24 -08:00
}
2020-10-08 20:26:58 -07:00
2022-05-26 13:17:14 -07:00
let fetchWithMiddleware : FetchFn | undefined ;
2021-04-26 08:35:07 -07:00
if ( fetchMiddleware ) {
2022-05-26 13:17:14 -07:00
fetchWithMiddleware = async ( info , init ) = > {
const modifiedFetchArgs = await new Promise < Parameters < FetchFn > > (
2021-11-28 21:43:33 -08:00
( resolve , reject ) = > {
2021-04-26 08:35:07 -07:00
try {
2022-05-26 13:17:14 -07:00
fetchMiddleware ( info , init , ( modifiedInfo , modifiedInit ) = >
resolve ( [ modifiedInfo , modifiedInit ] ) ,
2021-11-28 21:43:33 -08:00
) ;
2021-04-26 08:35:07 -07:00
} catch ( error ) {
reject ( error ) ;
}
2021-11-28 21:43:33 -08:00
} ,
) ;
return await fetch ( . . . modifiedFetchArgs ) ;
2021-04-26 08:35:07 -07:00
} ;
}
2021-03-14 20:01:35 -07:00
const clientBrowser = new RpcClient ( async ( request , callback ) = > {
2021-02-01 18:53:24 -08:00
const agent = agentManager ? agentManager . requestStart ( ) : undefined ;
2018-11-04 11:41:21 -08:00
const options = {
method : 'POST' ,
body : request ,
2020-09-25 08:52:01 -07:00
agent ,
2021-04-26 08:35:07 -07:00
headers : Object.assign (
{
'Content-Type' : 'application/json' ,
} ,
httpHeaders || { } ,
2022-06-28 22:11:17 -07:00
COMMON_HTTP_HEADERS ,
2021-04-26 08:35:07 -07:00
) ,
2018-11-04 11:41:21 -08:00
} ;
try {
2020-08-17 15:33:58 -07:00
let too_many_requests_retries = 5 ;
2021-03-14 20:01:35 -07:00
let res : Response ;
2020-08-24 11:20:45 -07:00
let waitTime = 500 ;
2020-08-17 15:33:58 -07:00
for ( ; ; ) {
2021-04-26 08:35:07 -07:00
if ( fetchWithMiddleware ) {
res = await fetchWithMiddleware ( url , options ) ;
} else {
res = await fetch ( url , options ) ;
}
2020-09-01 10:58:40 -07:00
if ( res . status !== 429 /* Too many requests */ ) {
2020-08-17 15:33:58 -07:00
break ;
}
2021-06-03 21:17:19 -07:00
if ( disableRetryOnRateLimit === true ) {
break ;
}
2020-08-24 11:20:45 -07:00
too_many_requests_retries -= 1 ;
if ( too_many_requests_retries === 0 ) {
break ;
}
2020-08-17 15:33:58 -07:00
console . log (
2020-09-01 10:58:40 -07:00
` Server responded with ${ res . status } ${ res . statusText } . Retrying after ${ waitTime } ms delay... ` ,
2020-08-17 15:33:58 -07:00
) ;
2020-08-24 11:20:45 -07:00
await sleep ( waitTime ) ;
waitTime *= 2 ;
2020-08-17 15:33:58 -07:00
}
2018-11-04 11:41:21 -08:00
const text = await res . text ( ) ;
2020-08-17 12:42:39 -07:00
if ( res . ok ) {
callback ( null , text ) ;
} else {
callback ( new Error ( ` ${ res . status } ${ res . statusText } : ${ text } ` ) ) ;
}
2018-11-04 11:41:21 -08:00
} catch ( err ) {
2021-09-25 12:25:14 -07:00
if ( err instanceof Error ) callback ( err ) ;
2020-09-25 08:52:01 -07:00
} finally {
2021-02-01 18:53:24 -08:00
agentManager && agentManager . requestEnd ( ) ;
2018-08-23 10:52:48 -07:00
}
2021-03-14 20:01:35 -07:00
} , { } ) ;
2018-08-23 10:52:48 -07:00
2021-03-22 10:22:59 -07:00
return clientBrowser ;
}
function createRpcRequest ( client : RpcClient ) : RpcRequest {
2018-08-23 10:52:48 -07:00
return ( method , args ) = > {
return new Promise ( ( resolve , reject ) = > {
2021-03-22 10:22:59 -07:00
client . request ( method , args , ( err : any , response : any ) = > {
if ( err ) {
reject ( err ) ;
return ;
}
resolve ( response ) ;
} ) ;
} ) ;
} ;
}
function createRpcBatchRequest ( client : RpcClient ) : RpcBatchRequest {
return ( requests : RpcParams [ ] ) = > {
return new Promise ( ( resolve , reject ) = > {
2021-03-31 00:15:04 -07:00
// Do nothing if requests is empty
if ( requests . length === 0 ) resolve ( [ ] ) ;
2021-03-22 10:22:59 -07:00
const batch = requests . map ( ( params : RpcParams ) = > {
return client . request ( params . methodName , params . args ) ;
} ) ;
client . request ( batch , ( err : any , response : any ) = > {
2018-08-23 10:52:48 -07:00
if ( err ) {
reject ( err ) ;
return ;
}
resolve ( response ) ;
} ) ;
} ) ;
} ;
}
2019-08-28 07:21:39 -07:00
/ * *
2020-06-03 08:38:48 -07:00
* Expected JSON RPC response for the "getInflationGovernor" message
2019-08-28 07:21:39 -07:00
* /
2021-02-25 23:06:12 -08:00
const GetInflationGovernorRpcResult = jsonRpcResult ( GetInflationGovernorResult ) ;
2019-08-28 07:21:39 -07:00
2019-10-29 09:50:05 -07:00
/ * *
* Expected JSON RPC response for the "getEpochInfo" message
* /
2021-02-25 23:06:12 -08:00
const GetEpochInfoRpcResult = jsonRpcResult ( GetEpochInfoResult ) ;
2019-10-29 09:50:05 -07:00
2019-10-23 06:48:24 -07:00
/ * *
* Expected JSON RPC response for the "getEpochSchedule" message
* /
2021-02-25 23:06:12 -08:00
const GetEpochScheduleRpcResult = jsonRpcResult ( GetEpochScheduleResult ) ;
2019-10-23 06:48:24 -07:00
2020-07-17 08:16:44 -07:00
/ * *
* Expected JSON RPC response for the "getLeaderSchedule" message
* /
2020-07-21 14:43:40 -07:00
const GetLeaderScheduleRpcResult = jsonRpcResult ( GetLeaderScheduleResult ) ;
2020-07-17 08:16:44 -07:00
2020-05-21 01:58:17 -07:00
/ * *
2020-05-23 02:33:04 -07:00
* Expected JSON RPC response for the "minimumLedgerSlot" and "getFirstAvailableBlock" messages
2020-05-21 01:58:17 -07:00
* /
2021-02-25 23:06:12 -08:00
const SlotRpcResult = jsonRpcResult ( number ( ) ) ;
2020-05-21 01:58:17 -07:00
2020-05-22 04:30:22 -07:00
/ * *
* Supply
* /
2021-03-14 20:01:35 -07:00
export type Supply = {
2021-03-31 03:48:41 -07:00
/** Total supply in lamports */
2021-03-14 20:01:35 -07:00
total : number ;
2021-03-31 03:48:41 -07:00
/** Circulating supply in lamports */
2021-03-14 20:01:35 -07:00
circulating : number ;
2021-03-31 03:48:41 -07:00
/** Non-circulating supply in lamports */
2021-03-14 20:01:35 -07:00
nonCirculating : number ;
2021-03-31 03:48:41 -07:00
/** List of non-circulating account addresses */
2021-03-14 20:01:35 -07:00
nonCirculatingAccounts : Array < PublicKey > ;
2020-05-22 04:30:22 -07:00
} ;
/ * *
* Expected JSON RPC response for the "getSupply" message
* /
const GetSupplyRpcResult = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
pick ( {
total : number ( ) ,
circulating : number ( ) ,
nonCirculating : number ( ) ,
nonCirculatingAccounts : array ( PublicKeyFromString ) ,
2020-05-22 04:30:22 -07:00
} ) ,
) ;
2020-08-11 02:28:07 -07:00
/ * *
* Token amount object which returns a token amount in different formats
* for various client use cases .
* /
2021-03-14 20:01:35 -07:00
export type TokenAmount = {
2021-03-31 03:48:41 -07:00
/** Raw amount of tokens as string ignoring decimals */
2021-03-14 20:01:35 -07:00
amount : string ;
2021-03-31 03:48:41 -07:00
/** Number of decimals configured for token's mint */
2021-03-14 20:01:35 -07:00
decimals : number ;
2021-03-31 03:48:41 -07:00
/** Token amount as float, accounts for decimals */
2021-03-14 20:01:35 -07:00
uiAmount : number | null ;
2021-03-31 03:48:41 -07:00
/** Token amount as string, accounts for decimals */
2021-03-14 20:01:35 -07:00
uiAmountString? : string ;
2020-08-05 21:17:29 -07:00
} ;
2020-07-30 21:33:54 -07:00
/ * *
2020-08-05 21:17:29 -07:00
* Expected JSON RPC structure for token amounts
2020-07-30 21:33:54 -07:00
* /
2021-02-25 23:06:12 -08:00
const TokenAmountResult = pick ( {
amount : string ( ) ,
2021-03-05 10:01:37 -08:00
uiAmount : nullable ( number ( ) ) ,
2021-02-25 23:06:12 -08:00
decimals : number ( ) ,
2021-03-14 19:52:04 -07:00
uiAmountString : optional ( string ( ) ) ,
2020-07-30 21:33:54 -07:00
} ) ;
2020-08-11 02:28:07 -07:00
/ * *
* Token address and balance .
* /
2021-03-14 20:01:35 -07:00
export type TokenAccountBalancePair = {
2021-03-31 03:48:41 -07:00
/** Address of the token account */
2021-03-14 20:01:35 -07:00
address : PublicKey ;
2021-03-31 03:48:41 -07:00
/** Raw amount of tokens as string ignoring decimals */
2021-03-14 20:01:35 -07:00
amount : string ;
2021-03-31 03:48:41 -07:00
/** Number of decimals configured for token's mint */
2021-03-14 20:01:35 -07:00
decimals : number ;
2021-03-31 03:48:41 -07:00
/** Token amount as float, accounts for decimals */
2021-03-14 20:01:35 -07:00
uiAmount : number | null ;
2021-03-31 03:48:41 -07:00
/** Token amount as string, accounts for decimals */
2021-03-14 20:01:35 -07:00
uiAmountString? : string ;
2020-08-11 02:28:07 -07:00
} ;
/ * *
* Expected JSON RPC response for the "getTokenLargestAccounts" message
* /
const GetTokenLargestAccountsResult = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
array (
pick ( {
address : PublicKeyFromString ,
amount : string ( ) ,
2021-03-05 10:53:45 -08:00
uiAmount : nullable ( number ( ) ) ,
2021-02-25 23:06:12 -08:00
decimals : number ( ) ,
2021-03-14 19:52:04 -07:00
uiAmountString : optional ( string ( ) ) ,
2020-08-11 02:28:07 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-08-11 02:28:07 -07:00
) ;
2020-07-30 21:33:54 -07:00
/ * *
* Expected JSON RPC response for the "getTokenAccountsByOwner" message
* /
const GetTokenAccountsByOwner = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
array (
pick ( {
pubkey : PublicKeyFromString ,
account : pick ( {
executable : boolean ( ) ,
owner : PublicKeyFromString ,
lamports : number ( ) ,
data : BufferFromRawAccountData ,
rentEpoch : number ( ) ,
2020-08-06 08:47:22 -07:00
} ) ,
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-08-06 08:47:22 -07:00
) ;
2021-02-25 23:06:12 -08:00
const ParsedAccountDataResult = pick ( {
program : string ( ) ,
parsed : unknown ( ) ,
space : number ( ) ,
} ) ;
2020-08-06 08:47:22 -07:00
/ * *
* Expected JSON RPC response for the "getTokenAccountsByOwner" message with parsed data
* /
const GetParsedTokenAccountsByOwner = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
array (
pick ( {
pubkey : PublicKeyFromString ,
account : pick ( {
executable : boolean ( ) ,
owner : PublicKeyFromString ,
lamports : number ( ) ,
data : ParsedAccountDataResult ,
rentEpoch : number ( ) ,
2020-07-30 21:33:54 -07:00
} ) ,
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-07-30 21:33:54 -07:00
) ;
2020-05-22 10:23:29 -07:00
/ * *
* Pair of an account address and its balance
* /
2021-03-14 20:01:35 -07:00
export type AccountBalancePair = {
address : PublicKey ;
lamports : number ;
2020-05-22 10:23:29 -07:00
} ;
/ * *
* Expected JSON RPC response for the "getLargestAccounts" message
* /
const GetLargestAccountsRpcResult = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
array (
pick ( {
lamports : number ( ) ,
address : PublicKeyFromString ,
2020-05-22 10:23:29 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-05-22 10:23:29 -07:00
) ;
2019-11-11 17:09:00 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-11-11 17:09:00 -08:00
* /
2021-02-25 23:06:12 -08:00
const AccountInfoResult = pick ( {
executable : boolean ( ) ,
owner : PublicKeyFromString ,
lamports : number ( ) ,
data : BufferFromRawAccountData ,
rentEpoch : number ( ) ,
2019-11-11 17:09:00 -08:00
} ) ;
2018-09-20 15:08:52 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2018-09-20 15:08:52 -07:00
* /
2021-02-25 23:06:12 -08:00
const KeyedAccountInfoResult = pick ( {
pubkey : PublicKeyFromString ,
account : AccountInfoResult ,
2018-09-20 15:08:52 -07:00
} ) ;
2021-02-25 23:06:12 -08:00
const ParsedOrRawAccountData = coerce (
union ( [ instance ( Buffer ) , ParsedAccountDataResult ] ) ,
union ( [ RawAccountDataResult , ParsedAccountDataResult ] ) ,
value = > {
if ( Array . isArray ( value ) ) {
return create ( value , BufferFromRawAccountData ) ;
} else {
return value ;
}
} ,
) ;
2020-08-06 08:47:22 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-08-06 08:47:22 -07:00
* /
2021-02-25 23:06:12 -08:00
const ParsedAccountInfoResult = pick ( {
executable : boolean ( ) ,
owner : PublicKeyFromString ,
lamports : number ( ) ,
data : ParsedOrRawAccountData ,
rentEpoch : number ( ) ,
} ) ;
const KeyedParsedAccountInfoResult = pick ( {
pubkey : PublicKeyFromString ,
account : ParsedAccountInfoResult ,
2020-08-06 08:47:22 -07:00
} ) ;
2020-09-16 23:50:13 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-09-16 23:50:13 -07:00
* /
2021-02-25 23:06:12 -08:00
const StakeActivationResult = pick ( {
state : union ( [
literal ( 'active' ) ,
literal ( 'inactive' ) ,
literal ( 'activating' ) ,
literal ( 'deactivating' ) ,
2020-09-16 23:50:13 -07:00
] ) ,
2021-02-25 23:06:12 -08:00
active : number ( ) ,
inactive : number ( ) ,
2020-09-16 23:50:13 -07:00
} ) ;
2020-07-29 22:40:46 -07:00
/ * *
* Expected JSON RPC response for the "getConfirmedSignaturesForAddress2" message
* /
const GetConfirmedSignaturesForAddress2RpcResult = jsonRpcResult (
2021-02-25 23:06:12 -08:00
array (
pick ( {
signature : string ( ) ,
slot : number ( ) ,
2020-07-29 22:40:46 -07:00
err : TransactionErrorResult ,
2021-02-25 23:06:12 -08:00
memo : nullable ( string ( ) ) ,
blockTime : optional ( nullable ( number ( ) ) ) ,
2020-07-29 22:40:46 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-07-29 22:40:46 -07:00
) ;
2021-06-21 23:07:36 -07:00
/ * *
* Expected JSON RPC response for the "getSignaturesForAddress" message
* /
const GetSignaturesForAddressRpcResult = jsonRpcResult (
array (
pick ( {
signature : string ( ) ,
slot : number ( ) ,
err : TransactionErrorResult ,
memo : nullable ( string ( ) ) ,
blockTime : optional ( nullable ( number ( ) ) ) ,
} ) ,
) ,
) ;
2018-10-26 21:37:39 -07:00
/ * * *
* Expected JSON RPC response for the "accountNotification" message
* /
2021-02-25 23:06:12 -08:00
const AccountNotificationResult = pick ( {
subscription : number ( ) ,
2020-03-23 07:19:32 -07:00
result : notificationResultAndContext ( AccountInfoResult ) ,
2018-10-26 21:37:39 -07:00
} ) ;
2018-09-20 15:08:52 -07:00
2019-03-08 16:02:39 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-03-08 16:02:39 -08:00
* /
2021-02-25 23:06:12 -08:00
const ProgramAccountInfoResult = pick ( {
pubkey : PublicKeyFromString ,
2020-01-15 13:04:26 -08:00
account : AccountInfoResult ,
} ) ;
2019-03-08 16:02:39 -08:00
/ * * *
* Expected JSON RPC response for the "programNotification" message
* /
2021-02-25 23:06:12 -08:00
const ProgramAccountNotificationResult = pick ( {
subscription : number ( ) ,
2020-03-23 07:19:32 -07:00
result : notificationResultAndContext ( ProgramAccountInfoResult ) ,
2019-03-08 16:02:39 -08:00
} ) ;
2019-11-25 08:04:35 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-11-25 08:04:35 -08:00
* /
2021-02-25 23:06:12 -08:00
const SlotInfoResult = pick ( {
parent : number ( ) ,
slot : number ( ) ,
root : number ( ) ,
2019-11-25 08:04:35 -08:00
} ) ;
2020-02-03 07:22:11 -08:00
/ * *
2019-11-25 08:04:35 -08:00
* Expected JSON RPC response for the "slotNotification" message
* /
2021-02-25 23:06:12 -08:00
const SlotNotificationResult = pick ( {
subscription : number ( ) ,
2020-03-27 07:22:53 -07:00
result : SlotInfoResult ,
2019-11-25 08:04:35 -08:00
} ) ;
2021-05-02 05:14:30 -07:00
/ * *
* 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 .
* /
export type SlotUpdate =
| {
type : 'firstShredReceived' ;
slot : number ;
timestamp : number ;
}
| {
type : 'completed' ;
slot : number ;
timestamp : number ;
}
| {
type : 'createdBank' ;
slot : number ;
timestamp : number ;
parent : number ;
}
| {
type : 'frozen' ;
slot : number ;
timestamp : number ;
stats : {
numTransactionEntries : number ;
numSuccessfulTransactions : number ;
numFailedTransactions : number ;
maxTransactionsPerEntry : number ;
} ;
}
| {
type : 'dead' ;
slot : number ;
timestamp : number ;
err : string ;
}
| {
type : 'optimisticConfirmation' ;
slot : number ;
timestamp : number ;
}
| {
type : 'root' ;
slot : number ;
timestamp : number ;
} ;
/ * *
* @internal
* /
const SlotUpdateResult = union ( [
pick ( {
type : union ( [
literal ( 'firstShredReceived' ) ,
literal ( 'completed' ) ,
literal ( 'optimisticConfirmation' ) ,
literal ( 'root' ) ,
] ) ,
slot : number ( ) ,
timestamp : number ( ) ,
} ) ,
pick ( {
type : literal ( 'createdBank' ) ,
parent : number ( ) ,
slot : number ( ) ,
timestamp : number ( ) ,
} ) ,
pick ( {
type : literal ( 'frozen' ) ,
slot : number ( ) ,
timestamp : number ( ) ,
stats : pick ( {
numTransactionEntries : number ( ) ,
numSuccessfulTransactions : number ( ) ,
numFailedTransactions : number ( ) ,
maxTransactionsPerEntry : number ( ) ,
} ) ,
} ) ,
pick ( {
type : literal ( 'dead' ) ,
slot : number ( ) ,
timestamp : number ( ) ,
err : string ( ) ,
} ) ,
] ) ;
/ * *
* Expected JSON RPC response for the "slotsUpdatesNotification" message
* /
const SlotUpdateNotificationResult = pick ( {
subscription : number ( ) ,
result : SlotUpdateResult ,
} ) ;
2020-02-03 07:22:11 -08:00
/ * *
* Expected JSON RPC response for the "signatureNotification" message
* /
2021-02-25 23:06:12 -08:00
const SignatureNotificationResult = pick ( {
subscription : number ( ) ,
2021-03-18 18:30:36 -07:00
result : notificationResultAndContext (
union ( [ SignatureStatusResult , SignatureReceivedResult ] ) ,
) ,
2020-02-03 07:22:11 -08:00
} ) ;
2020-03-27 07:22:53 -07:00
/ * *
* Expected JSON RPC response for the "rootNotification" message
* /
2021-02-25 23:06:12 -08:00
const RootNotificationResult = pick ( {
subscription : number ( ) ,
result : number ( ) ,
2020-03-27 07:22:53 -07:00
} ) ;
2021-02-25 23:06:12 -08:00
const ContactInfoResult = pick ( {
pubkey : string ( ) ,
gossip : nullable ( string ( ) ) ,
tpu : nullable ( string ( ) ) ,
rpc : nullable ( string ( ) ) ,
version : nullable ( string ( ) ) ,
} ) ;
2019-04-23 09:53:26 -07:00
2021-02-25 23:06:12 -08:00
const VoteAccountInfoResult = pick ( {
votePubkey : string ( ) ,
nodePubkey : string ( ) ,
activatedStake : number ( ) ,
epochVoteAccount : boolean ( ) ,
epochCredits : array ( tuple ( [ number ( ) , number ( ) , number ( ) ] ) ) ,
commission : number ( ) ,
lastVote : number ( ) ,
rootSlot : nullable ( number ( ) ) ,
} ) ;
2019-04-23 09:53:26 -07:00
2019-06-12 10:26:55 -07:00
/ * *
2019-08-19 10:39:08 -07:00
* Expected JSON RPC response for the "getVoteAccounts" message
2019-06-12 10:26:55 -07:00
* /
2019-08-19 10:39:08 -07:00
const GetVoteAccounts = jsonRpcResult (
2021-02-25 23:06:12 -08:00
pick ( {
current : array ( VoteAccountInfoResult ) ,
delinquent : array ( VoteAccountInfoResult ) ,
2019-08-19 10:39:08 -07:00
} ) ,
2019-06-12 10:26:55 -07:00
) ;
2021-03-14 18:52:52 -07:00
const ConfirmationStatus = union ( [
literal ( 'processed' ) ,
literal ( 'confirmed' ) ,
literal ( 'finalized' ) ,
] ) ;
2021-02-25 23:06:12 -08:00
const SignatureStatusResponse = pick ( {
slot : number ( ) ,
confirmations : nullable ( number ( ) ) ,
err : TransactionErrorResult ,
2021-03-14 18:52:52 -07:00
confirmationStatus : optional ( ConfirmationStatus ) ,
2021-02-25 23:06:12 -08:00
} ) ;
2018-09-26 19:16:17 -07:00
/ * *
2020-04-01 10:51:30 -07:00
* Expected JSON RPC response for the "getSignatureStatuses" message
2018-09-26 19:16:17 -07:00
* /
2020-04-01 10:51:30 -07:00
const GetSignatureStatusesRpcResult = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
array ( nullable ( SignatureStatusResponse ) ) ,
2020-02-03 07:22:11 -08:00
) ;
2018-09-26 19:16:17 -07:00
2019-09-26 13:13:57 -07:00
/ * *
* Expected JSON RPC response for the "getMinimumBalanceForRentExemption" message
* /
2021-02-25 23:06:12 -08:00
const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult ( number ( ) ) ;
2019-09-26 13:13:57 -07:00
2022-08-31 05:46:24 -07:00
const AddressTableLookupStruct = pick ( {
accountKey : PublicKeyFromString ,
writableIndexes : array ( number ( ) ) ,
readonlyIndexes : array ( number ( ) ) ,
} ) ;
2021-02-25 23:06:12 -08:00
const ConfirmedTransactionResult = pick ( {
signatures : array ( string ( ) ) ,
message : pick ( {
accountKeys : array ( string ( ) ) ,
header : pick ( {
numRequiredSignatures : number ( ) ,
numReadonlySignedAccounts : number ( ) ,
numReadonlyUnsignedAccounts : number ( ) ,
2020-04-21 00:40:44 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
instructions : array (
pick ( {
accounts : array ( number ( ) ) ,
data : string ( ) ,
programIdIndex : number ( ) ,
2020-08-06 04:16:01 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
recentBlockhash : string ( ) ,
2022-08-31 05:46:24 -07:00
addressTableLookups : optional ( array ( AddressTableLookupStruct ) ) ,
2020-08-06 04:16:01 -07:00
} ) ,
} ) ;
2021-02-25 23:06:12 -08:00
const ParsedInstructionResult = pick ( {
parsed : unknown ( ) ,
program : string ( ) ,
programId : PublicKeyFromString ,
} ) ;
const RawInstructionResult = pick ( {
accounts : array ( PublicKeyFromString ) ,
data : string ( ) ,
programId : PublicKeyFromString ,
} ) ;
const InstructionResult = union ( [
RawInstructionResult ,
ParsedInstructionResult ,
] ) ;
const UnknownInstructionResult = union ( [
pick ( {
parsed : unknown ( ) ,
program : string ( ) ,
programId : string ( ) ,
} ) ,
pick ( {
accounts : array ( string ( ) ) ,
data : string ( ) ,
programId : string ( ) ,
} ) ,
] ) ;
const ParsedOrRawInstruction = coerce (
InstructionResult ,
UnknownInstructionResult ,
value = > {
if ( 'accounts' in value ) {
return create ( value , RawInstructionResult ) ;
} else {
return create ( value , ParsedInstructionResult ) ;
}
} ,
) ;
2020-08-06 04:16:01 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-08-06 04:16:01 -07:00
* /
2021-02-25 23:06:12 -08:00
const ParsedConfirmedTransactionResult = pick ( {
signatures : array ( string ( ) ) ,
message : pick ( {
accountKeys : array (
pick ( {
pubkey : PublicKeyFromString ,
signer : boolean ( ) ,
writable : boolean ( ) ,
2022-09-09 14:06:54 -07:00
source : optional (
union ( [ literal ( 'transaction' ) , literal ( 'lookupTable' ) ] ) ,
) ,
2020-08-06 04:16:01 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
instructions : array ( ParsedOrRawInstruction ) ,
recentBlockhash : string ( ) ,
2022-08-31 05:46:24 -07:00
addressTableLookups : optional ( nullable ( array ( AddressTableLookupStruct ) ) ) ,
2020-04-21 00:40:44 -07:00
} ) ,
} ) ;
2021-02-25 23:06:12 -08:00
const TokenBalanceResult = pick ( {
accountIndex : number ( ) ,
mint : string ( ) ,
2021-12-28 08:08:38 -08:00
owner : optional ( string ( ) ) ,
2021-02-25 23:06:12 -08:00
uiTokenAmount : TokenAmountResult ,
} ) ;
2022-08-10 13:08:24 -07:00
const LoadedAddressesResult = pick ( {
writable : array ( PublicKeyFromString ) ,
readonly : array ( PublicKeyFromString ) ,
} ) ;
2020-04-21 00:40:44 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-04-21 00:40:44 -07:00
* /
2021-02-25 23:06:12 -08:00
const ConfirmedTransactionMetaResult = pick ( {
err : TransactionErrorResult ,
fee : number ( ) ,
innerInstructions : optional (
nullable (
array (
pick ( {
index : number ( ) ,
instructions : array (
pick ( {
accounts : array ( number ( ) ) ,
data : string ( ) ,
programIdIndex : number ( ) ,
2020-10-28 02:13:51 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-12-16 23:15:25 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
) ,
) ,
preBalances : array ( number ( ) ) ,
postBalances : array ( number ( ) ) ,
logMessages : optional ( nullable ( array ( string ( ) ) ) ) ,
preTokenBalances : optional ( nullable ( array ( TokenBalanceResult ) ) ) ,
postTokenBalances : optional ( nullable ( array ( TokenBalanceResult ) ) ) ,
2022-08-10 13:08:24 -07:00
loadedAddresses : optional ( LoadedAddressesResult ) ,
2022-09-01 11:18:43 -07:00
computeUnitsConsumed : optional ( number ( ) ) ,
2021-02-25 23:06:12 -08:00
} ) ;
2020-10-28 02:13:51 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-10-28 02:13:51 -07:00
* /
2021-02-25 23:06:12 -08:00
const ParsedConfirmedTransactionMetaResult = pick ( {
err : TransactionErrorResult ,
fee : number ( ) ,
innerInstructions : optional (
nullable (
array (
pick ( {
index : number ( ) ,
instructions : array ( ParsedOrRawInstruction ) ,
2020-12-16 23:15:25 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
) ,
) ,
preBalances : array ( number ( ) ) ,
postBalances : array ( number ( ) ) ,
logMessages : optional ( nullable ( array ( string ( ) ) ) ) ,
preTokenBalances : optional ( nullable ( array ( TokenBalanceResult ) ) ) ,
postTokenBalances : optional ( nullable ( array ( TokenBalanceResult ) ) ) ,
2022-08-10 13:08:24 -07:00
loadedAddresses : optional ( LoadedAddressesResult ) ,
2022-09-01 11:18:43 -07:00
computeUnitsConsumed : optional ( number ( ) ) ,
2021-02-25 23:06:12 -08:00
} ) ;
2020-04-21 00:40:44 -07:00
2022-08-31 05:46:24 -07:00
const TransactionVersionStruct = union ( [ literal ( 0 ) , literal ( 'legacy' ) ] ) ;
2022-01-27 15:43:01 -08:00
/ * *
* Expected JSON RPC response for the "getBlock" message
* /
const GetBlockRpcResult = jsonRpcResult (
nullable (
pick ( {
blockhash : string ( ) ,
previousBlockhash : string ( ) ,
parentSlot : number ( ) ,
transactions : array (
pick ( {
transaction : ConfirmedTransactionResult ,
meta : nullable ( ConfirmedTransactionMetaResult ) ,
2022-08-31 05:46:24 -07:00
version : optional ( TransactionVersionStruct ) ,
2022-01-27 15:43:01 -08:00
} ) ,
) ,
rewards : optional (
array (
pick ( {
pubkey : string ( ) ,
lamports : number ( ) ,
postBalance : nullable ( number ( ) ) ,
rewardType : nullable ( string ( ) ) ,
} ) ,
) ,
) ,
blockTime : nullable ( number ( ) ) ,
blockHeight : nullable ( number ( ) ) ,
} ) ,
) ,
) ;
2022-10-11 01:13:10 -07:00
/ * *
* Expected parsed JSON RPC response for the "getBlock" message
* /
const GetParsedBlockRpcResult = jsonRpcResult (
nullable (
pick ( {
blockhash : string ( ) ,
previousBlockhash : string ( ) ,
parentSlot : number ( ) ,
transactions : array (
pick ( {
transaction : ParsedConfirmedTransactionResult ,
meta : nullable ( ParsedConfirmedTransactionMetaResult ) ,
version : optional ( TransactionVersionStruct ) ,
} ) ,
) ,
rewards : optional (
array (
pick ( {
pubkey : string ( ) ,
lamports : number ( ) ,
postBalance : nullable ( number ( ) ) ,
rewardType : nullable ( string ( ) ) ,
} ) ,
) ,
) ,
blockTime : nullable ( number ( ) ) ,
blockHeight : nullable ( number ( ) ) ,
} ) ,
) ,
) ;
2019-11-11 11:08:00 -08:00
/ * *
2019-11-16 08:28:14 -08:00
* Expected JSON RPC response for the "getConfirmedBlock" message
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link GetBlockRpcResult } instead .
2019-11-11 11:08:00 -08:00
* /
2021-03-29 01:12:47 -07:00
const GetConfirmedBlockRpcResult = jsonRpcResult (
2021-02-25 23:06:12 -08:00
nullable (
pick ( {
blockhash : string ( ) ,
previousBlockhash : string ( ) ,
parentSlot : number ( ) ,
transactions : array (
pick ( {
2021-05-25 10:12:47 -07:00
transaction : ConfirmedTransactionResult ,
2021-02-25 23:06:12 -08:00
meta : nullable ( ConfirmedTransactionMetaResult ) ,
2019-11-16 08:28:14 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
rewards : optional (
array (
pick ( {
pubkey : string ( ) ,
lamports : number ( ) ,
postBalance : nullable ( number ( ) ) ,
rewardType : nullable ( string ( ) ) ,
2020-02-11 23:06:40 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
) ,
2021-03-18 07:10:48 -07:00
blockTime : nullable ( number ( ) ) ,
2020-01-22 12:05:19 -08:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2019-11-12 08:21:19 -08:00
) ;
2021-04-13 23:56:08 -07:00
/ * *
2022-01-27 15:43:01 -08:00
* Expected JSON RPC response for the "getBlock" message
2021-04-13 23:56:08 -07:00
* /
2022-01-27 15:43:01 -08:00
const GetBlockSignaturesRpcResult = jsonRpcResult (
2021-04-13 23:56:08 -07:00
nullable (
pick ( {
blockhash : string ( ) ,
previousBlockhash : string ( ) ,
parentSlot : number ( ) ,
signatures : array ( string ( ) ) ,
blockTime : nullable ( number ( ) ) ,
} ) ,
) ,
) ;
2020-04-21 00:40:44 -07:00
/ * *
2022-01-27 15:43:01 -08:00
* Expected JSON RPC response for the "getTransaction" message
2020-04-21 00:40:44 -07:00
* /
2022-01-27 15:43:01 -08:00
const GetTransactionRpcResult = jsonRpcResult (
2021-02-25 23:06:12 -08:00
nullable (
pick ( {
slot : number ( ) ,
2020-04-21 00:40:44 -07:00
meta : ConfirmedTransactionMetaResult ,
2021-02-25 23:06:12 -08:00
blockTime : optional ( nullable ( number ( ) ) ) ,
2021-05-25 10:12:47 -07:00
transaction : ConfirmedTransactionResult ,
2022-08-31 05:46:24 -07:00
version : optional ( TransactionVersionStruct ) ,
2020-04-21 00:40:44 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-04-21 00:40:44 -07:00
) ;
2020-08-06 04:16:01 -07:00
/ * *
2022-01-27 15:43:01 -08:00
* Expected parsed JSON RPC response for the "getTransaction" message
2020-08-06 04:16:01 -07:00
* /
2022-01-27 15:43:01 -08:00
const GetParsedTransactionRpcResult = jsonRpcResult (
2021-02-25 23:06:12 -08:00
nullable (
pick ( {
slot : number ( ) ,
2020-08-06 04:16:01 -07:00
transaction : ParsedConfirmedTransactionResult ,
2021-02-25 23:06:12 -08:00
meta : nullable ( ParsedConfirmedTransactionMetaResult ) ,
blockTime : optional ( nullable ( number ( ) ) ) ,
2022-08-31 05:46:24 -07:00
version : optional ( TransactionVersionStruct ) ,
2020-08-06 04:16:01 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-08-06 04:16:01 -07:00
) ;
2018-08-24 09:05:23 -07:00
/ * *
2019-03-04 08:06:33 -08:00
* Expected JSON RPC response for the "getRecentBlockhash" message
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link GetLatestBlockhashRpcResult } instead .
2018-08-24 09:05:23 -07:00
* /
2020-01-15 13:04:26 -08:00
const GetRecentBlockhashAndContextRpcResult = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
pick ( {
blockhash : string ( ) ,
feeCalculator : pick ( {
lamportsPerSignature : number ( ) ,
2020-01-15 13:04:26 -08:00
} ) ,
2019-06-12 14:36:05 -07:00
} ) ,
2020-01-15 13:04:26 -08:00
) ;
2019-11-13 14:31:31 -08:00
2022-01-27 15:43:01 -08:00
/ * *
* Expected JSON RPC response for the "getLatestBlockhash" message
* /
const GetLatestBlockhashRpcResult = jsonRpcResultAndContext (
pick ( {
blockhash : string ( ) ,
lastValidBlockHeight : number ( ) ,
} ) ,
) ;
2021-02-25 23:06:12 -08:00
const PerfSampleResult = pick ( {
slot : number ( ) ,
numTransactions : number ( ) ,
numSlots : number ( ) ,
samplePeriodSecs : number ( ) ,
} ) ;
2020-10-08 20:26:58 -07:00
/ *
* Expected JSON RPC response for "getRecentPerformanceSamples" message
* /
const GetRecentPerformanceSamplesRpcResult = jsonRpcResult (
2021-02-25 23:06:12 -08:00
array ( PerfSampleResult ) ,
2020-10-08 20:26:58 -07:00
) ;
2020-06-04 03:12:59 -07:00
/ * *
* Expected JSON RPC response for the "getFeeCalculatorForBlockhash" message
* /
const GetFeeCalculatorRpcResult = jsonRpcResultAndContext (
2021-02-25 23:06:12 -08:00
nullable (
pick ( {
feeCalculator : pick ( {
lamportsPerSignature : number ( ) ,
2020-06-04 03:12:59 -07:00
} ) ,
} ) ,
2021-02-25 23:06:12 -08:00
) ,
2020-06-04 03:12:59 -07:00
) ;
2018-08-24 09:05:23 -07:00
/ * *
* Expected JSON RPC response for the "requestAirdrop" message
* /
2021-02-25 23:06:12 -08:00
const RequestAirdropRpcResult = jsonRpcResult ( string ( ) ) ;
2018-08-24 09:05:23 -07:00
/ * *
* Expected JSON RPC response for the "sendTransaction" message
* /
2021-02-25 23:06:12 -08:00
const SendTransactionRpcResult = jsonRpcResult ( string ( ) ) ;
2018-08-23 10:52:48 -07:00
2020-03-27 07:22:53 -07:00
/ * *
* Information about the latest slot being processed by a node
* /
2021-02-07 08:57:12 -08:00
export type SlotInfo = {
2021-03-31 03:48:41 -07:00
/** Currently processing slot */
2021-03-14 20:01:35 -07:00
slot : number ;
2021-03-31 03:48:41 -07:00
/** Parent of the current slot */
2021-03-14 20:01:35 -07:00
parent : number ;
2021-03-31 03:48:41 -07:00
/** The root block of the current slot's fork */
2021-03-14 20:01:35 -07:00
root : number ;
2020-03-27 07:22:53 -07:00
} ;
2020-08-06 08:47:22 -07:00
/ * *
* Parsed account data
* /
2021-03-14 20:01:35 -07:00
export type ParsedAccountData = {
2021-03-31 03:48:41 -07:00
/** Name of the program that owns this account */
2021-03-14 20:01:35 -07:00
program : string ;
2021-03-31 03:48:41 -07:00
/** Parsed account data */
2021-03-14 20:01:35 -07:00
parsed : any ;
2021-03-31 03:48:41 -07:00
/** Space used by account data */
2021-03-14 20:01:35 -07:00
space : number ;
2020-08-06 08:47:22 -07:00
} ;
2020-09-16 23:50:13 -07:00
/ * *
* Stake Activation data
* /
2021-03-14 20:01:35 -07:00
export type StakeActivationData = {
2021-03-31 03:48:41 -07:00
/** the stake account's activation state */
2021-03-14 20:01:35 -07:00
state : 'active' | 'inactive' | 'activating' | 'deactivating' ;
2021-03-31 03:48:41 -07:00
/** stake active during the epoch */
2021-03-14 20:01:35 -07:00
active : number ;
2021-03-31 03:48:41 -07:00
/** stake inactive during the epoch */
2021-03-14 20:01:35 -07:00
inactive : number ;
2020-09-16 23:50:13 -07:00
} ;
2021-04-16 10:18:19 -07:00
/ * *
* Data slice argument for getProgramAccounts
* /
export type DataSlice = {
/** offset of data slice */
offset : number ;
/** length of data slice */
length : number ;
} ;
/ * *
* Memory comparison filter for getProgramAccounts
* /
export type MemcmpFilter = {
memcmp : {
/** offset into program account data to start comparison */
offset : number ;
/** data to match, as base-58 encoded string and limited to less than 129 bytes */
bytes : string ;
} ;
} ;
/ * *
* Data size comparison filter for getProgramAccounts
* /
export type DataSizeFilter = {
/** Size of data for program account data length comparison */
dataSize : number ;
} ;
/ * *
* A filter object for getProgramAccounts
* /
export type GetProgramAccountsFilter = MemcmpFilter | DataSizeFilter ;
/ * *
* Configuration object for getProgramAccounts requests
* /
export type GetProgramAccountsConfig = {
/** Optional commitment level */
commitment? : Commitment ;
2021-07-21 15:14:25 -07:00
/ * * O p t i o n a l e n c o d i n g f o r a c c o u n t d a t a ( d e f a u l t b a s e 6 4 )
* To use "jsonParsed" encoding , please refer to ` getParsedProgramAccounts ` in connection . ts
* * /
encoding ? : 'base64' ;
2021-04-16 10:18:19 -07:00
/** Optional data slice to limit the returned account data */
dataSlice? : DataSlice ;
/** Optional array of filters to apply to accounts */
filters? : GetProgramAccountsFilter [ ] ;
2022-06-29 09:22:34 -07:00
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2021-04-16 10:18:19 -07:00
} ;
/ * *
* Configuration object for getParsedProgramAccounts
* /
2021-05-05 02:50:55 -07:00
export type GetParsedProgramAccountsConfig = {
/** Optional commitment level */
commitment? : Commitment ;
/** Optional array of filters to apply to accounts */
filters? : GetProgramAccountsFilter [ ] ;
2022-06-29 09:22:34 -07:00
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2021-05-05 02:50:55 -07:00
} ;
2021-04-16 10:18:19 -07:00
2021-12-25 19:21:10 -08:00
/ * *
* Configuration object for getMultipleAccounts
* /
export type GetMultipleAccountsConfig = {
/** Optional commitment level */
commitment? : Commitment ;
2022-06-29 09:22:34 -07:00
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2022-10-13 20:28:00 -07:00
/** Optional data slice to limit the returned account data */
dataSlice? : DataSlice ;
2022-06-29 09:22:34 -07:00
} ;
/ * *
* Configuration object for ` getStakeActivation `
* /
export type GetStakeActivationConfig = {
/** Optional commitment level */
commitment? : Commitment ;
/** Epoch for which to calculate activation details. If parameter not provided, defaults to current epoch */
epoch? : number ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for ` getStakeActivation `
* /
export type GetTokenAccountsByOwnerConfig = {
/** Optional commitment level */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
} ;
/ * *
* Configuration object for ` getStakeActivation `
* /
export type GetTransactionCountConfig = {
/** Optional commitment level */
commitment? : Commitment ;
/** The minimum slot that the request can be evaluated at */
minContextSlot? : number ;
2021-12-25 19:21:10 -08:00
} ;
2018-09-20 15:08:52 -07:00
/ * *
* Information describing an account
* /
2021-03-14 20:01:35 -07:00
export type AccountInfo < T > = {
2021-03-31 03:48:41 -07:00
/** `true` if this account's data contains a loaded program */
2021-03-14 20:01:35 -07:00
executable : boolean ;
2021-03-31 03:48:41 -07:00
/** Identifier of the program that owns the account */
2021-03-14 20:01:35 -07:00
owner : PublicKey ;
2021-03-31 03:48:41 -07:00
/** Number of lamports assigned to the account */
2021-03-14 20:01:35 -07:00
lamports : number ;
2021-03-31 03:48:41 -07:00
/** Optional data assigned to the account */
2021-03-14 20:01:35 -07:00
data : T ;
2021-12-30 14:03:42 -08:00
/** Optional rent epoch info for account */
2021-09-16 14:10:28 -07:00
rentEpoch? : number ;
2018-11-04 11:41:21 -08:00
} ;
2018-09-20 15:08:52 -07:00
2019-03-08 16:02:39 -08:00
/ * *
* Account information identified by pubkey
* /
2021-02-07 08:57:12 -08:00
export type KeyedAccountInfo = {
2021-03-14 20:01:35 -07:00
accountId : PublicKey ;
accountInfo : AccountInfo < Buffer > ;
2019-03-08 16:02:39 -08:00
} ;
2018-10-26 21:37:39 -07:00
/ * *
* Callback function for account change notifications
* /
2020-03-23 07:19:32 -07:00
export type AccountChangeCallback = (
2020-08-06 08:47:22 -07:00
accountInfo : AccountInfo < Buffer > ,
2020-03-23 07:19:32 -07:00
context : Context ,
) = > void ;
2018-10-26 21:37:39 -07:00
2019-03-08 16:02:39 -08:00
/ * *
* Callback function for program account change notifications
* /
export type ProgramAccountChangeCallback = (
keyedAccountInfo : KeyedAccountInfo ,
2020-03-23 07:19:32 -07:00
context : Context ,
2019-03-08 16:02:39 -08:00
) = > void ;
2020-02-03 07:22:11 -08:00
/ * *
* Callback function for slot change notifications
* /
export type SlotChangeCallback = ( slotInfo : SlotInfo ) = > void ;
2021-05-02 05:14:30 -07:00
/ * *
* Callback function for slot update notifications
* /
export type SlotUpdateCallback = ( slotUpdate : SlotUpdate ) = > void ;
2019-11-25 08:04:35 -08:00
/ * *
2021-03-18 18:30:36 -07:00
* Callback function for signature status notifications
2019-11-25 08:04:35 -08:00
* /
2020-02-03 07:22:11 -08:00
export type SignatureResultCallback = (
2020-04-04 06:35:08 -07:00
signatureResult : SignatureResult ,
2020-03-23 07:19:32 -07:00
context : Context ,
2020-02-03 07:22:11 -08:00
) = > void ;
2021-03-18 18:30:36 -07:00
/ * *
* Signature status notification with transaction result
* /
export type SignatureStatusNotification = {
type : 'status' ;
result : SignatureResult ;
} ;
/ * *
* Signature received notification
* /
export type SignatureReceivedNotification = {
type : 'received' ;
} ;
/ * *
* Callback function for signature notifications
* /
export type SignatureSubscriptionCallback = (
notification : SignatureStatusNotification | SignatureReceivedNotification ,
context : Context ,
) = > void ;
/ * *
* Signature subscription options
* /
export type SignatureSubscriptionOptions = {
commitment? : Commitment ;
enableReceivedNotification? : boolean ;
} ;
2020-03-27 07:22:53 -07:00
/ * *
* Callback function for root change notifications
* /
export type RootChangeCallback = ( root : number ) = > void ;
2021-03-23 20:05:17 -07:00
/ * *
* @internal
* /
const LogsResult = pick ( {
err : TransactionErrorResult ,
logs : array ( string ( ) ) ,
signature : string ( ) ,
} ) ;
/ * *
* Logs result .
* /
export type Logs = {
err : TransactionError | null ;
logs : string [ ] ;
signature : string ;
} ;
/ * *
* Expected JSON RPC response for the "logsNotification" message .
* /
const LogsNotificationResult = pick ( {
result : notificationResultAndContext ( LogsResult ) ,
subscription : number ( ) ,
} ) ;
/ * *
* Filter for log subscriptions .
* /
export type LogsFilter = PublicKey | 'all' | 'allWithVotes' ;
/ * *
* Callback function for log notifications .
* /
export type LogsCallback = ( logs : Logs , ctx : Context ) = > void ;
2018-09-26 19:16:17 -07:00
/ * *
2020-04-04 06:35:08 -07:00
* Signature result
2018-09-26 19:16:17 -07:00
* /
2021-03-14 20:01:35 -07:00
export type SignatureResult = {
err : TransactionError | null ;
} ;
2019-04-10 14:40:49 -07:00
/ * *
2020-04-04 06:35:08 -07:00
* Transaction error
2019-04-10 14:40:49 -07:00
* /
2021-04-04 03:02:36 -07:00
export type TransactionError = { } | string ;
2018-09-26 19:16:17 -07:00
2021-03-14 18:52:52 -07:00
/ * *
* 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 >
* /
export type TransactionConfirmationStatus =
| 'processed'
| 'confirmed'
| 'finalized' ;
2020-03-23 08:01:12 -07:00
/ * *
* Signature status
* /
export type SignatureStatus = {
2021-03-14 20:01:35 -07:00
/** when the transaction was processed */
slot : number ;
/** the number of blocks that have been confirmed and voted on in the fork containing `slot` */
confirmations : number | null ;
/** transaction error, if any */
err : TransactionError | null ;
/** cluster confirmation status, if data available. Possible responses: `processed`, `confirmed`, `finalized` */
confirmationStatus? : TransactionConfirmationStatus ;
2020-03-23 08:01:12 -07:00
} ;
2020-07-29 22:40:46 -07:00
/ * *
* A confirmed signature with its status
* /
export type ConfirmedSignatureInfo = {
2021-03-31 03:48:41 -07:00
/** the transaction signature */
2021-03-14 20:01:35 -07:00
signature : string ;
2021-03-31 03:48:41 -07:00
/** when the transaction was processed */
2021-03-14 20:01:35 -07:00
slot : number ;
2021-03-31 03:48:41 -07:00
/** error, if any */
2021-03-14 20:01:35 -07:00
err : TransactionError | null ;
2021-03-31 03:48:41 -07:00
/** memo associated with the transaction, if any */
2021-03-14 20:01:35 -07:00
memo : string | null ;
2021-03-31 03:48:41 -07:00
/** The unix timestamp of when the transaction was processed */
2021-03-14 20:01:35 -07:00
blockTime? : number | null ;
2020-07-29 22:40:46 -07:00
} ;
2021-04-26 08:35:07 -07:00
/ * *
* An object defining headers to be passed to the RPC server
* /
2022-06-28 22:11:17 -07:00
export type HttpHeaders = {
[ header : string ] : string ;
} & {
// Prohibited headers; for internal use only.
'solana-client' ? : never ;
} ;
2021-04-26 08:35:07 -07:00
2022-05-26 14:36:57 -07:00
/ * *
* The type of the JavaScript ` fetch() ` API
* /
export type FetchFn = typeof fetchImpl ;
2022-05-26 13:17:14 -07:00
2021-04-26 08:35:07 -07:00
/ * *
* A callback used to augment the outgoing HTTP request
* /
export type FetchMiddleware = (
2022-05-26 13:17:14 -07:00
info : Parameters < FetchFn > [ 0 ] ,
init : Parameters < FetchFn > [ 1 ] ,
fetch : ( . . . a : Parameters < FetchFn > ) = > void ,
2021-04-26 08:35:07 -07:00
) = > void ;
/ * *
* Configuration for instantiating a Connection
* /
export type ConnectionConfig = {
/** Optional commitment level */
commitment? : Commitment ;
2021-05-27 14:57:32 -07:00
/** Optional endpoint URL to the fullnode JSON RPC PubSub WebSocket Endpoint */
wsEndpoint? : string ;
2021-04-26 08:35:07 -07:00
/** Optional HTTP headers object */
httpHeaders? : HttpHeaders ;
2022-04-15 23:49:31 -07:00
/** Optional custom fetch function */
2022-05-26 13:17:14 -07:00
fetch? : FetchFn ;
2021-04-26 08:35:07 -07:00
/** Optional fetch middleware callback */
fetchMiddleware? : FetchMiddleware ;
2022-03-13 22:25:27 -07:00
/** Optional Disable retrying calls when server responds with HTTP 429 (Too Many Requests) */
2021-06-03 21:17:19 -07:00
disableRetryOnRateLimit? : boolean ;
2021-09-17 09:54:25 -07:00
/** time to allow for the server to initially process a transaction (in milliseconds) */
confirmTransactionInitialTimeout? : number ;
2021-04-26 08:35:07 -07:00
} ;
2022-06-28 22:11:17 -07:00
/** @internal */
const COMMON_HTTP_HEADERS = {
'solana-client' : ` js/ ${ process . env . npm_package_version ? ? 'UNKNOWN' } ` ,
} ;
2018-08-24 09:05:23 -07:00
/ * *
* A connection to a fullnode JSON RPC endpoint
* /
2018-08-23 10:52:48 -07:00
export class Connection {
2021-03-14 20:01:35 -07:00
/** @internal */ _commitment? : Commitment ;
2021-09-17 09:54:25 -07:00
/** @internal */ _confirmTransactionInitialTimeout? : number ;
2021-03-14 20:01:35 -07:00
/** @internal */ _rpcEndpoint : string ;
2021-05-27 14:57:32 -07:00
/** @internal */ _rpcWsEndpoint : string ;
2021-03-22 10:22:59 -07:00
/** @internal */ _rpcClient : RpcClient ;
2021-03-14 20:01:35 -07:00
/** @internal */ _rpcRequest : RpcRequest ;
2021-03-22 10:22:59 -07:00
/** @internal */ _rpcBatchRequest : RpcBatchRequest ;
2021-03-14 20:01:35 -07:00
/** @internal */ _rpcWebSocket : RpcWebSocketClient ;
/** @internal */ _rpcWebSocketConnected : boolean = false ;
/** @internal */ _rpcWebSocketHeartbeat : ReturnType <
typeof setInterval
> | null = null ;
/** @internal */ _rpcWebSocketIdleTimeout : ReturnType <
typeof setTimeout
> | null = null ;
2022-04-28 16:21:39 -07:00
/ * * @ i n t e r n a l
* 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 .
*
* / p r i v a t e _ r p c W e b S o c k e t G e n e r a t i o n : n u m b e r = 0 ;
2021-03-14 20:01:35 -07:00
/** @internal */ _disableBlockhashCaching : boolean = false ;
/** @internal */ _pollingBlockhash : boolean = false ;
/** @internal */ _blockhashInfo : {
2022-05-14 21:54:12 -07:00
latestBlockhash : BlockhashWithExpiryBlockHeight | null ;
2021-03-14 20:01:35 -07:00
lastFetch : number ;
simulatedSignatures : Array < string > ;
transactionSignatures : Array < string > ;
2021-05-27 14:57:32 -07:00
} = {
2022-05-14 21:54:12 -07:00
latestBlockhash : null ,
2021-05-27 14:57:32 -07:00
lastFetch : 0 ,
transactionSignatures : [ ] ,
simulatedSignatures : [ ] ,
2018-10-22 20:03:44 -07:00
} ;
2021-03-14 20:01:35 -07:00
2022-04-28 16:21:39 -07:00
/** @internal */ private _nextClientSubscriptionId : ClientSubscriptionId = 0 ;
/** @internal */ private _subscriptionDisposeFunctionsByClientSubscriptionId : {
[ clientSubscriptionId : ClientSubscriptionId ] :
| SubscriptionDisposeFn
| undefined ;
2020-02-03 07:22:11 -08:00
} = { } ;
2022-04-28 16:21:39 -07:00
/** @internal */ private _subscriptionCallbacksByServerSubscriptionId : {
[ serverSubscriptionId : ServerSubscriptionId ] :
| Set < SubscriptionConfig [ ' callback ' ] >
| undefined ;
2021-03-23 20:05:17 -07:00
} = { } ;
2022-04-28 16:21:39 -07:00
/** @internal */ private _subscriptionsByHash : {
[ hash : SubscriptionConfigHash ] : Subscription | undefined ;
2021-05-02 05:14:30 -07:00
} = { } ;
2022-04-28 16:21:39 -07:00
/ * *
* 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 */ private _subscriptionsAutoDisposedByRpc : Set < ServerSubscriptionId > =
new Set ( ) ;
2021-05-02 05:14:30 -07:00
2018-08-24 09:05:23 -07:00
/ * *
* Establish a JSON RPC connection
*
* @param endpoint URL to the fullnode JSON RPC endpoint
2021-04-26 08:35:07 -07:00
* @param commitmentOrConfig optional default commitment level or optional ConnectionConfig configuration object
2018-08-24 09:05:23 -07:00
* /
2021-04-26 08:35:07 -07:00
constructor (
endpoint : string ,
commitmentOrConfig? : Commitment | ConnectionConfig ,
) {
2021-05-27 14:57:32 -07:00
let wsEndpoint ;
2021-04-26 08:35:07 -07:00
let httpHeaders ;
2022-04-15 23:49:31 -07:00
let fetch ;
2021-04-26 08:35:07 -07:00
let fetchMiddleware ;
2021-06-03 21:17:19 -07:00
let disableRetryOnRateLimit ;
2021-04-26 08:35:07 -07:00
if ( commitmentOrConfig && typeof commitmentOrConfig === 'string' ) {
this . _commitment = commitmentOrConfig ;
} else if ( commitmentOrConfig ) {
this . _commitment = commitmentOrConfig . commitment ;
2021-09-17 09:54:25 -07:00
this . _confirmTransactionInitialTimeout =
commitmentOrConfig . confirmTransactionInitialTimeout ;
2021-05-27 14:57:32 -07:00
wsEndpoint = commitmentOrConfig . wsEndpoint ;
2021-04-26 08:35:07 -07:00
httpHeaders = commitmentOrConfig . httpHeaders ;
2022-04-15 23:49:31 -07:00
fetch = commitmentOrConfig . fetch ;
2021-04-26 08:35:07 -07:00
fetchMiddleware = commitmentOrConfig . fetchMiddleware ;
2021-06-03 21:17:19 -07:00
disableRetryOnRateLimit = commitmentOrConfig . disableRetryOnRateLimit ;
2021-04-26 08:35:07 -07:00
}
2022-08-24 11:02:40 -07:00
this . _rpcEndpoint = assertEndpointUrl ( endpoint ) ;
2021-05-27 14:57:32 -07:00
this . _rpcWsEndpoint = wsEndpoint || makeWebsocketUrl ( endpoint ) ;
2021-04-26 08:35:07 -07:00
this . _rpcClient = createRpcClient (
2022-08-24 11:02:40 -07:00
endpoint ,
2021-04-26 08:35:07 -07:00
httpHeaders ,
2022-04-15 23:49:31 -07:00
fetch ,
2021-04-26 08:35:07 -07:00
fetchMiddleware ,
2021-06-03 21:17:19 -07:00
disableRetryOnRateLimit ,
2021-04-26 08:35:07 -07:00
) ;
2021-03-22 10:22:59 -07:00
this . _rpcRequest = createRpcRequest ( this . _rpcClient ) ;
this . _rpcBatchRequest = createRpcBatchRequest ( this . _rpcClient ) ;
2021-04-26 08:35:07 -07:00
2021-05-27 14:57:32 -07:00
this . _rpcWebSocket = new RpcWebSocketClient ( this . _rpcWsEndpoint , {
2018-11-04 11:41:21 -08:00
autoconnect : false ,
max_reconnects : Infinity ,
} ) ;
2018-10-26 21:37:39 -07:00
this . _rpcWebSocket . on ( 'open' , this . _wsOnOpen . bind ( this ) ) ;
this . _rpcWebSocket . on ( 'error' , this . _wsOnError . bind ( this ) ) ;
this . _rpcWebSocket . on ( 'close' , this . _wsOnClose . bind ( this ) ) ;
2018-11-04 11:41:21 -08:00
this . _rpcWebSocket . on (
'accountNotification' ,
this . _wsOnAccountNotification . bind ( this ) ,
) ;
2019-03-08 16:02:39 -08:00
this . _rpcWebSocket . on (
'programNotification' ,
this . _wsOnProgramAccountNotification . bind ( this ) ,
) ;
2019-11-25 08:04:35 -08:00
this . _rpcWebSocket . on (
'slotNotification' ,
this . _wsOnSlotNotification . bind ( this ) ,
) ;
2021-05-02 05:14:30 -07:00
this . _rpcWebSocket . on (
'slotsUpdatesNotification' ,
this . _wsOnSlotUpdatesNotification . bind ( this ) ,
) ;
2020-02-03 07:22:11 -08:00
this . _rpcWebSocket . on (
'signatureNotification' ,
this . _wsOnSignatureNotification . bind ( this ) ,
) ;
2020-03-27 07:22:53 -07:00
this . _rpcWebSocket . on (
'rootNotification' ,
this . _wsOnRootNotification . bind ( this ) ,
) ;
2021-03-23 20:05:17 -07:00
this . _rpcWebSocket . on (
'logsNotification' ,
this . _wsOnLogsNotification . bind ( this ) ,
) ;
2018-08-23 10:52:48 -07:00
}
2020-04-06 02:56:26 -07:00
/ * *
* The default commitment used for requests
* /
2021-03-14 20:01:35 -07:00
get commitment ( ) : Commitment | undefined {
2020-04-06 02:56:26 -07:00
return this . _commitment ;
}
2022-03-23 11:05:37 -07:00
/ * *
* The RPC endpoint
* /
get rpcEndpoint ( ) : string {
return this . _rpcEndpoint ;
}
2018-08-24 09:05:23 -07:00
/ * *
2020-01-08 13:44:50 -08:00
* Fetch the balance for the specified public key , return with context
2018-08-24 09:05:23 -07:00
* /
2019-11-13 14:31:31 -08:00
async getBalanceAndContext (
2019-11-11 10:01:10 -08:00
publicKey : PublicKey ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetBalanceConfig ,
2019-11-13 14:31:31 -08:00
) : Promise < RpcResponseAndContext < number > > {
2022-06-29 09:22:34 -07:00
/** @internal */
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ publicKey . toBase58 ( ) ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getBalance' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResultAndContext ( number ( ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get balance for ${ publicKey . toBase58 ( ) } ` ,
2020-04-08 16:49:51 -07:00
) ;
2018-08-23 10:52:48 -07:00
}
2020-01-08 12:59:58 -08:00
return res . result ;
2019-11-13 14:31:31 -08:00
}
2020-01-08 13:44:50 -08:00
/ * *
* Fetch the balance for the specified public key
* /
2019-11-13 14:31:31 -08:00
async getBalance (
publicKey : PublicKey ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetBalanceConfig ,
2019-11-13 14:31:31 -08:00
) : Promise < number > {
2022-06-29 09:22:34 -07:00
return await this . getBalanceAndContext ( publicKey , commitmentOrConfig )
2019-11-13 14:31:31 -08:00
. then ( x = > x . value )
. catch ( e = > {
2020-04-08 16:49:51 -07:00
throw new Error (
2020-04-09 09:48:18 -07:00
'failed to get balance of account ' + publicKey . toBase58 ( ) + ': ' + e ,
2020-04-08 16:49:51 -07:00
) ;
2019-11-13 14:31:31 -08:00
} ) ;
2018-08-23 10:52:48 -07:00
}
2020-05-18 20:27:36 -07:00
/ * *
* Fetch the estimated production time of a block
* /
async getBlockTime ( slot : number ) : Promise < number | null > {
const unsafeRes = await this . _rpcRequest ( 'getBlockTime' , [ slot ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( nullable ( number ( ) ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get block time for slot ${ slot } ` ,
2020-05-18 20:27:36 -07:00
) ;
}
return res . result ;
}
2020-05-21 01:58:17 -07:00
/ * *
* 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 ( ) : Promise < number > {
const unsafeRes = await this . _rpcRequest ( 'minimumLedgerSlot' , [ ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( number ( ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get minimum ledger slot' ,
2020-05-21 01:58:17 -07:00
) ;
}
return res . result ;
}
2020-05-23 02:33:04 -07:00
/ * *
* Fetch the slot of the lowest confirmed block that has not been purged from the ledger
* /
async getFirstAvailableBlock ( ) : Promise < number > {
const unsafeRes = await this . _rpcRequest ( 'getFirstAvailableBlock' , [ ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , SlotRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get first available block' ,
2020-05-23 02:33:04 -07:00
) ;
}
return res . result ;
}
2020-05-22 04:30:22 -07:00
/ * *
* Fetch information about the current supply
* /
async getSupply (
2021-10-22 13:12:49 -07:00
config? : GetSupplyConfig | Commitment ,
2020-05-22 04:30:22 -07:00
) : Promise < RpcResponseAndContext < Supply > > {
2021-10-22 13:12:49 -07:00
let configArg : GetSupplyConfig = { } ;
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 ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetSupplyRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get supply' ) ;
2020-05-22 04:30:22 -07:00
}
return res . result ;
}
2020-07-30 21:33:54 -07:00
/ * *
* Fetch the current supply of a token mint
* /
async getTokenSupply (
tokenMintAddress : PublicKey ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-08-05 21:17:29 -07:00
) : Promise < RpcResponseAndContext < TokenAmount > > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ tokenMintAddress . toBase58 ( ) ] , commitment ) ;
2020-07-30 21:33:54 -07:00
const unsafeRes = await this . _rpcRequest ( 'getTokenSupply' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResultAndContext ( TokenAmountResult ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get token supply' ) ;
2020-07-30 21:33:54 -07:00
}
return res . result ;
}
/ * *
* Fetch the current balance of a token account
* /
async getTokenAccountBalance (
tokenAddress : PublicKey ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-08-05 21:17:29 -07:00
) : Promise < RpcResponseAndContext < TokenAmount > > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ tokenAddress . toBase58 ( ) ] , commitment ) ;
2020-07-30 21:33:54 -07:00
const unsafeRes = await this . _rpcRequest ( 'getTokenAccountBalance' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResultAndContext ( TokenAmountResult ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get token account balance' ,
2020-07-30 21:33:54 -07:00
) ;
}
return res . result ;
}
/ * *
* Fetch all the token accounts owned by the specified account
*
2020-08-06 08:47:22 -07:00
* @return { Promise < RpcResponseAndContext < Array < { pubkey : PublicKey , account : AccountInfo < Buffer > } >>> }
2020-07-30 21:33:54 -07:00
* /
async getTokenAccountsByOwner (
ownerAddress : PublicKey ,
filter : TokenAccountsFilter ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetTokenAccountsByOwnerConfig ,
2020-07-30 21:33:54 -07:00
) : Promise <
2020-08-06 08:47:22 -07:00
RpcResponseAndContext <
2021-03-14 20:01:35 -07:00
Array < { pubkey : PublicKey ; account : AccountInfo < Buffer > } >
>
2020-07-30 21:33:54 -07:00
> {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2021-03-14 20:01:35 -07:00
let _args : any [ ] = [ ownerAddress . toBase58 ( ) ] ;
if ( 'mint' in filter ) {
2020-08-06 08:47:22 -07:00
_args . push ( { mint : filter.mint.toBase58 ( ) } ) ;
} else {
_args . push ( { programId : filter.programId.toBase58 ( ) } ) ;
}
2020-07-30 21:33:54 -07:00
2022-06-29 09:22:34 -07:00
const args = this . _buildArgs ( _args , commitment , 'base64' , config ) ;
2020-07-30 21:33:54 -07:00
const unsafeRes = await this . _rpcRequest ( 'getTokenAccountsByOwner' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetTokenAccountsByOwner ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get token accounts owned by account ${ ownerAddress . toBase58 ( ) } ` ,
2020-07-30 21:33:54 -07:00
) ;
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-07-30 21:33:54 -07:00
}
2020-08-06 08:47:22 -07:00
/ * *
* Fetch parsed token accounts owned by the specified account
*
* @return { Promise < RpcResponseAndContext < Array < { pubkey : PublicKey , account : AccountInfo < ParsedAccountData > } >>> }
* /
async getParsedTokenAccountsByOwner (
ownerAddress : PublicKey ,
filter : TokenAccountsFilter ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-08-06 08:47:22 -07:00
) : Promise <
RpcResponseAndContext <
2021-03-14 20:01:35 -07:00
Array < { pubkey : PublicKey ; account : AccountInfo < ParsedAccountData > } >
>
2020-08-06 08:47:22 -07:00
> {
2021-03-14 20:01:35 -07:00
let _args : any [ ] = [ ownerAddress . toBase58 ( ) ] ;
if ( 'mint' in filter ) {
2020-08-06 08:47:22 -07:00
_args . push ( { mint : filter.mint.toBase58 ( ) } ) ;
} else {
_args . push ( { programId : filter.programId.toBase58 ( ) } ) ;
}
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( _args , commitment , 'jsonParsed' ) ;
2020-08-06 08:47:22 -07:00
const unsafeRes = await this . _rpcRequest ( 'getTokenAccountsByOwner' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetParsedTokenAccountsByOwner ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get token accounts owned by account ${ ownerAddress . toBase58 ( ) } ` ,
2020-08-06 08:47:22 -07:00
) ;
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-08-06 08:47:22 -07:00
}
2020-05-22 10:23:29 -07:00
/ * *
* Fetch the 20 largest accounts with their current balances
* /
async getLargestAccounts (
2021-03-14 20:01:35 -07:00
config? : GetLargestAccountsConfig ,
2020-05-22 10:23:29 -07:00
) : Promise < RpcResponseAndContext < Array < AccountBalancePair > >> {
const arg = {
. . . config ,
commitment : ( config && config . commitment ) || this . commitment ,
} ;
const args = arg . filter || arg . commitment ? [ arg ] : [ ] ;
const unsafeRes = await this . _rpcRequest ( 'getLargestAccounts' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetLargestAccountsRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get largest accounts' ) ;
2020-05-22 10:23:29 -07:00
}
return res . result ;
}
2020-08-11 02:28:07 -07:00
/ * *
* Fetch the 20 largest token accounts with their current balances
* for a given mint .
* /
async getTokenLargestAccounts (
mintAddress : PublicKey ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-08-11 02:28:07 -07:00
) : Promise < RpcResponseAndContext < Array < TokenAccountBalancePair > >> {
const args = this . _buildArgs ( [ mintAddress . toBase58 ( ) ] , commitment ) ;
const unsafeRes = await this . _rpcRequest ( 'getTokenLargestAccounts' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetTokenLargestAccountsResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get token largest accounts' ,
2020-08-11 02:28:07 -07:00
) ;
}
return res . result ;
}
2018-09-20 15:08:52 -07:00
/ * *
2020-01-08 13:44:50 -08:00
* Fetch all the account info for the specified public key , return with context
2018-09-20 15:08:52 -07:00
* /
2019-11-13 14:31:31 -08:00
async getAccountInfoAndContext (
2019-11-11 10:01:10 -08:00
publicKey : PublicKey ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetAccountInfoConfig ,
2020-08-06 08:47:22 -07:00
) : Promise < RpcResponseAndContext < AccountInfo < Buffer > | null >> {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ publicKey . toBase58 ( ) ] ,
commitment ,
'base64' ,
config ,
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getAccountInfo' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create (
unsafeRes ,
jsonRpcResultAndContext ( nullable ( AccountInfoResult ) ) ,
) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get info about account ${ publicKey . toBase58 ( ) } ` ,
2020-04-08 16:49:51 -07:00
) ;
2018-09-20 15:08:52 -07:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2018-09-20 15:08:52 -07:00
}
2020-01-08 13:44:50 -08:00
2020-08-06 08:47:22 -07:00
/ * *
* Fetch parsed account info for the specified public key
* /
async getParsedAccountInfo (
publicKey : PublicKey ,
2022-08-11 07:28:54 -07:00
commitmentOrConfig? : Commitment | GetAccountInfoConfig ,
2020-08-06 08:47:22 -07:00
) : Promise <
2021-03-14 20:01:35 -07:00
RpcResponseAndContext < AccountInfo < Buffer | ParsedAccountData > | null >
2020-08-06 08:47:22 -07:00
> {
2022-08-11 07:28:54 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs (
2020-08-06 08:47:22 -07:00
[ publicKey . toBase58 ( ) ] ,
commitment ,
'jsonParsed' ,
2022-08-11 07:28:54 -07:00
config ,
2020-08-06 08:47:22 -07:00
) ;
const unsafeRes = await this . _rpcRequest ( 'getAccountInfo' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create (
unsafeRes ,
jsonRpcResultAndContext ( nullable ( ParsedAccountInfoResult ) ) ,
) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get info about account ${ publicKey . toBase58 ( ) } ` ,
2020-08-06 08:47:22 -07:00
) ;
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-08-06 08:47:22 -07:00
}
2020-01-08 13:44:50 -08:00
/ * *
* Fetch all the account info for the specified public key
* /
2019-11-13 14:31:31 -08:00
async getAccountInfo (
publicKey : PublicKey ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetAccountInfoConfig ,
2020-08-06 08:47:22 -07:00
) : Promise < AccountInfo < Buffer > | null > {
2021-02-25 23:06:12 -08:00
try {
2022-06-29 09:22:34 -07:00
const res = await this . getAccountInfoAndContext (
publicKey ,
commitmentOrConfig ,
) ;
2021-02-25 23:06:12 -08:00
return res . value ;
} catch ( e ) {
throw new Error (
'failed to get info about account ' + publicKey . toBase58 ( ) + ': ' + e ,
) ;
}
2019-11-13 14:31:31 -08:00
}
2018-09-20 15:08:52 -07:00
2022-10-16 00:26:08 -07:00
/ * *
* Fetch all the account info for multiple accounts specified by an array of public keys , return with context
* /
async getMultipleParsedAccounts (
publicKeys : PublicKey [ ] ,
rawConfig? : GetMultipleAccountsConfig ,
) : Promise <
RpcResponseAndContext < ( AccountInfo < Buffer | ParsedAccountData > | null ) [ ] >
> {
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 = create (
unsafeRes ,
jsonRpcResultAndContext ( array ( nullable ( ParsedAccountInfoResult ) ) ) ,
) ;
if ( 'error' in res ) {
throw new SolanaJSONRPCError (
res . error ,
` failed to get info for accounts ${ keys } ` ,
) ;
}
return res . result ;
}
2021-07-20 09:42:14 -07:00
/ * *
2022-01-22 07:09:48 -08:00
* Fetch all the account info for multiple accounts specified by an array of public keys , return with context
2021-07-20 09:42:14 -07:00
* /
2022-01-22 07:09:48 -08:00
async getMultipleAccountsInfoAndContext (
2021-07-20 09:42:14 -07:00
publicKeys : PublicKey [ ] ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetMultipleAccountsConfig ,
2022-01-22 07:09:48 -08:00
) : Promise < RpcResponseAndContext < ( AccountInfo < Buffer > | null ) [ ] >> {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2021-07-20 09:42:14 -07:00
const keys = publicKeys . map ( key = > key . toBase58 ( ) ) ;
2022-06-29 09:22:34 -07:00
const args = this . _buildArgs ( [ keys ] , commitment , 'base64' , config ) ;
2021-07-20 09:42:14 -07:00
const unsafeRes = await this . _rpcRequest ( 'getMultipleAccounts' , args ) ;
const res = create (
unsafeRes ,
2022-01-22 07:09:48 -08:00
jsonRpcResultAndContext ( array ( nullable ( AccountInfoResult ) ) ) ,
2021-07-20 09:42:14 -07:00
) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get info for accounts ${ keys } ` ,
2021-07-20 09:42:14 -07:00
) ;
}
2022-01-22 07:09:48 -08:00
return res . result ;
}
/ * *
* Fetch all the account info for multiple accounts specified by an array of public keys
* /
async getMultipleAccountsInfo (
publicKeys : PublicKey [ ] ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetMultipleAccountsConfig ,
2022-01-22 07:09:48 -08:00
) : Promise < ( AccountInfo < Buffer > | null ) [ ] > {
const res = await this . getMultipleAccountsInfoAndContext (
publicKeys ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig ,
2022-01-22 07:09:48 -08:00
) ;
return res . value ;
2021-07-20 09:42:14 -07:00
}
2020-09-16 23:50:13 -07:00
/ * *
* Returns epoch activation information for a stake account that has been delegated
* /
async getStakeActivation (
publicKey : PublicKey ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetStakeActivationConfig ,
2021-03-14 20:01:35 -07:00
epoch? : number ,
2020-09-16 23:50:13 -07:00
) : Promise < StakeActivationData > {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2020-09-16 23:50:13 -07:00
const args = this . _buildArgs (
[ publicKey . toBase58 ( ) ] ,
commitment ,
2022-06-29 09:22:34 -07:00
undefined /* encoding */ ,
{
. . . config ,
epoch : epoch != null ? epoch : config?.epoch ,
} ,
2020-09-16 23:50:13 -07:00
) ;
const unsafeRes = await this . _rpcRequest ( 'getStakeActivation' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( StakeActivationResult ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get Stake Activation ${ publicKey . toBase58 ( ) } ` ,
2020-09-16 23:50:13 -07:00
) ;
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-09-16 23:50:13 -07:00
}
2019-06-28 18:28:06 -07:00
/ * *
* Fetch all the accounts owned by the specified program id
2020-02-14 07:01:01 -08:00
*
2020-08-06 08:47:22 -07:00
* @return { Promise < Array < { pubkey : PublicKey , account : AccountInfo < Buffer > } >> }
2019-06-28 18:28:06 -07:00
* /
async getProgramAccounts (
programId : PublicKey ,
2021-04-16 10:18:19 -07:00
configOrCommitment? : GetProgramAccountsConfig | Commitment ,
2021-03-14 20:01:35 -07:00
) : Promise < Array < { pubkey : PublicKey ; account : AccountInfo < Buffer > } >> {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( configOrCommitment ) ;
const { encoding , . . . configWithoutEncoding } = config || { } ;
2021-04-16 10:18:19 -07:00
const args = this . _buildArgs (
[ programId . toBase58 ( ) ] ,
commitment ,
encoding || 'base64' ,
2022-06-29 09:22:34 -07:00
configWithoutEncoding ,
2021-04-16 10:18:19 -07:00
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getProgramAccounts' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( array ( KeyedAccountInfoResult ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get accounts owned by program ${ programId . toBase58 ( ) } ` ,
2020-04-08 16:49:51 -07:00
) ;
2019-06-28 18:28:06 -07:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2019-06-28 18:28:06 -07:00
}
2020-08-06 08:47:22 -07:00
/ * *
* Fetch and parse all the accounts owned by the specified program id
*
* @return { Promise < Array < { pubkey : PublicKey , account : AccountInfo < Buffer | ParsedAccountData > } >> }
* /
async getParsedProgramAccounts (
programId : PublicKey ,
2021-04-16 10:18:19 -07:00
configOrCommitment? : GetParsedProgramAccountsConfig | Commitment ,
2020-08-06 08:47:22 -07:00
) : Promise <
Array < {
2021-03-14 20:01:35 -07:00
pubkey : PublicKey ;
account : AccountInfo < Buffer | ParsedAccountData > ;
} >
2020-08-06 08:47:22 -07:00
> {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( configOrCommitment ) ;
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs (
2020-08-06 08:47:22 -07:00
[ programId . toBase58 ( ) ] ,
commitment ,
'jsonParsed' ,
2022-06-29 09:22:34 -07:00
config ,
2020-08-06 08:47:22 -07:00
) ;
const unsafeRes = await this . _rpcRequest ( 'getProgramAccounts' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create (
unsafeRes ,
jsonRpcResult ( array ( KeyedParsedAccountInfoResult ) ) ,
) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` failed to get accounts owned by program ${ programId . toBase58 ( ) } ` ,
2020-08-06 08:47:22 -07:00
) ;
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-08-06 08:47:22 -07:00
}
2022-05-13 18:42:40 -07:00
confirmTransaction (
2022-05-17 16:59:04 -07:00
strategy : BlockheightBasedTransactionConfirmationStrategy ,
2022-05-13 18:42:40 -07:00
commitment? : Commitment ,
) : Promise < RpcResponseAndContext < SignatureResult > > ;
/** @deprecated Instead, call `confirmTransaction` using a `TransactionConfirmationConfig` */
// eslint-disable-next-line no-dupe-class-members
confirmTransaction (
strategy : TransactionSignature ,
commitment? : Commitment ,
) : Promise < RpcResponseAndContext < SignatureResult > > ;
// eslint-disable-next-line no-dupe-class-members
2019-11-13 14:31:31 -08:00
async confirmTransaction (
2022-05-13 18:42:40 -07:00
strategy :
2022-05-17 16:59:04 -07:00
| BlockheightBasedTransactionConfirmationStrategy
2022-05-13 18:42:40 -07:00
| TransactionSignature ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-09-07 22:12:47 -07:00
) : Promise < RpcResponseAndContext < SignatureResult > > {
2022-05-13 18:42:40 -07:00
let rawSignature : string ;
if ( typeof strategy == 'string' ) {
rawSignature = strategy ;
} else {
2022-05-17 16:59:04 -07:00
const config =
strategy as BlockheightBasedTransactionConfirmationStrategy ;
2022-05-13 18:42:40 -07:00
rawSignature = config . signature ;
}
2020-09-07 22:12:47 -07:00
let decodedSignature ;
2022-05-13 18:42:40 -07:00
2020-09-07 22:12:47 -07:00
try {
2022-05-13 18:42:40 -07:00
decodedSignature = bs58 . decode ( rawSignature ) ;
2020-09-07 22:12:47 -07:00
} catch ( err ) {
2022-05-13 18:42:40 -07:00
throw new Error ( 'signature must be base58 encoded: ' + rawSignature ) ;
2020-09-07 22:12:47 -07:00
}
assert ( decodedSignature . length === 64 , 'signature has invalid length' ) ;
2020-10-29 10:22:53 -07:00
const subscriptionCommitment = commitment || this . commitment ;
2022-05-13 18:42:40 -07:00
let timeoutId ;
2020-09-07 22:12:47 -07:00
let subscriptionId ;
2022-05-13 18:42:40 -07:00
let done = false ;
const confirmationPromise = new Promise < {
__type : TransactionStatus.PROCESSED ;
response : RpcResponseAndContext < SignatureResult > ;
} > ( ( resolve , reject ) = > {
2020-09-07 22:12:47 -07:00
try {
subscriptionId = this . onSignature (
2022-05-13 18:42:40 -07:00
rawSignature ,
2021-03-14 20:01:35 -07:00
( result : SignatureResult , context : Context ) = > {
2020-09-07 22:12:47 -07:00
subscriptionId = undefined ;
2022-05-13 18:42:40 -07:00
const response = {
2020-09-07 22:12:47 -07:00
context ,
value : result ,
} ;
2022-05-13 18:42:40 -07:00
done = true ;
resolve ( { __type : TransactionStatus.PROCESSED , response } ) ;
2020-09-07 22:12:47 -07:00
} ,
subscriptionCommitment ,
) ;
} catch ( err ) {
reject ( err ) ;
}
} ) ;
2022-05-13 18:42:40 -07:00
const expiryPromise = new Promise <
| { __type : TransactionStatus.BLOCKHEIGHT_EXCEEDED }
| { __type : TransactionStatus.TIMED_OUT ; timeoutMs : number }
> ( resolve = > {
if ( typeof strategy === 'string' ) {
let timeoutMs = this . _confirmTransactionInitialTimeout || 60 * 1000 ;
switch ( subscriptionCommitment ) {
case 'processed' :
case 'recent' :
case 'single' :
case 'confirmed' :
case 'singleGossip' : {
timeoutMs = this . _confirmTransactionInitialTimeout || 30 * 1000 ;
break ;
}
// exhaust enums to ensure full coverage
case 'finalized' :
case 'max' :
case 'root' :
}
2020-09-07 22:12:47 -07:00
2022-05-13 18:42:40 -07:00
timeoutId = setTimeout (
( ) = > resolve ( { __type : TransactionStatus.TIMED_OUT , timeoutMs } ) ,
timeoutMs ,
) ;
} else {
2022-05-17 16:59:04 -07:00
let config =
strategy as BlockheightBasedTransactionConfirmationStrategy ;
2022-06-07 20:40:01 -07:00
const checkBlockHeight = async ( ) = > {
try {
const blockHeight = await this . getBlockHeight ( commitment ) ;
return blockHeight ;
} catch ( _e ) {
return - 1 ;
}
} ;
2022-05-13 18:42:40 -07:00
( async ( ) = > {
let currentBlockHeight = await checkBlockHeight ( ) ;
if ( done ) return ;
while ( currentBlockHeight <= config . lastValidBlockHeight ) {
await sleep ( 1000 ) ;
if ( done ) return ;
currentBlockHeight = await checkBlockHeight ( ) ;
if ( done ) return ;
}
resolve ( { __type : TransactionStatus.BLOCKHEIGHT_EXCEEDED } ) ;
} ) ( ) ;
}
} ) ;
let result : RpcResponseAndContext < SignatureResult > ;
2020-09-07 22:12:47 -07:00
try {
2022-05-13 18:42:40 -07:00
const outcome = await Promise . race ( [ confirmationPromise , expiryPromise ] ) ;
switch ( outcome . __type ) {
case TransactionStatus . BLOCKHEIGHT_EXCEEDED :
throw new TransactionExpiredBlockheightExceededError ( rawSignature ) ;
case TransactionStatus . PROCESSED :
result = outcome . response ;
break ;
case TransactionStatus . TIMED_OUT :
throw new TransactionExpiredTimeoutError (
rawSignature ,
outcome . timeoutMs / 1000 ,
) ;
}
2020-09-07 22:12:47 -07:00
} finally {
2022-05-13 18:42:40 -07:00
clearTimeout ( timeoutId ) ;
2020-09-07 22:12:47 -07:00
if ( subscriptionId ) {
this . removeSignatureListener ( subscriptionId ) ;
}
}
2022-05-13 18:42:40 -07:00
return result ;
2018-08-23 10:52:48 -07:00
}
2019-04-23 09:53:26 -07:00
/ * *
2019-06-12 10:26:55 -07:00
* Return the list of nodes that are currently participating in the cluster
2019-04-23 09:53:26 -07:00
* /
2019-06-12 10:26:55 -07:00
async getClusterNodes ( ) : Promise < Array < ContactInfo > > {
const unsafeRes = await this . _rpcRequest ( 'getClusterNodes' , [ ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( array ( ContactInfoResult ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get cluster nodes' ) ;
2019-04-23 09:53:26 -07:00
}
return res . result ;
}
/ * *
2019-04-24 08:23:10 -07:00
* Return the list of nodes that are currently participating in the cluster
2019-04-23 09:53:26 -07:00
* /
2021-03-14 20:01:35 -07:00
async getVoteAccounts ( commitment? : Commitment ) : Promise < VoteAccountStatus > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ ] , commitment ) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getVoteAccounts' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetVoteAccounts ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get vote accounts' ) ;
2019-06-12 10:26:55 -07:00
}
return res . result ;
}
2019-08-09 06:04:34 -07:00
/ * *
2019-08-02 16:06:54 -07:00
* Fetch the current slot that the node is processing
* /
2022-06-29 09:22:34 -07:00
async getSlot (
commitmentOrConfig? : Commitment | GetSlotConfig ,
) : Promise < number > {
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getSlot' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( number ( ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get slot' ) ;
2019-08-02 16:06:54 -07:00
}
return res . result ;
}
2019-06-12 10:26:55 -07:00
/ * *
* Fetch the current slot leader of the cluster
* /
2022-06-29 09:22:34 -07:00
async getSlotLeader (
commitmentOrConfig? : Commitment | GetSlotLeaderConfig ,
) : Promise < string > {
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getSlotLeader' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( string ( ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get slot leader' ) ;
2019-04-23 09:53:26 -07:00
}
return res . result ;
}
2021-05-01 20:54:27 -07:00
/ * *
* 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 : number ,
limit : number ,
) : Promise < Array < PublicKey > > {
const args = [ startSlot , limit ] ;
const unsafeRes = await this . _rpcRequest ( 'getSlotLeaders' , args ) ;
const res = create ( unsafeRes , jsonRpcResult ( array ( PublicKeyFromString ) ) ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get slot leaders' ) ;
2021-05-01 20:54:27 -07:00
}
return res . result ;
}
2018-09-26 19:16:17 -07:00
/ * *
2020-01-17 09:08:40 -08:00
* Fetch the current status of a signature
2018-09-26 19:16:17 -07:00
* /
2018-11-04 11:41:21 -08:00
async getSignatureStatus (
signature : TransactionSignature ,
2021-03-14 20:01:35 -07:00
config? : SignatureStatusConfig ,
2020-03-26 06:37:45 -07:00
) : Promise < RpcResponseAndContext < SignatureStatus | null > > {
2021-02-25 23:06:12 -08:00
const { context , value : values } = await this . getSignatureStatuses (
2020-03-26 06:37:45 -07:00
[ signature ] ,
2020-04-06 02:56:26 -07:00
config ,
2020-03-26 06:37:45 -07:00
) ;
2021-02-25 23:06:12 -08:00
assert ( values . length === 1 ) ;
const value = values [ 0 ] ;
return { context , value } ;
2020-03-23 08:01:12 -07:00
}
/ * *
2020-04-06 02:56:26 -07:00
* Fetch the current statuses of a batch of signatures
2020-03-23 08:01:12 -07:00
* /
2020-04-01 10:51:30 -07:00
async getSignatureStatuses (
2020-03-23 08:01:12 -07:00
signatures : Array < TransactionSignature > ,
2021-03-14 20:01:35 -07:00
config? : SignatureStatusConfig ,
2020-03-26 06:37:45 -07:00
) : Promise < RpcResponseAndContext < Array < SignatureStatus | null > >> {
2021-03-14 20:01:35 -07:00
const params : any [ ] = [ signatures ] ;
2020-04-06 02:56:26 -07:00
if ( config ) {
params . push ( config ) ;
}
const unsafeRes = await this . _rpcRequest ( 'getSignatureStatuses' , params ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetSignatureStatusesRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get signature status' ) ;
2018-09-26 19:16:17 -07:00
}
return res . result ;
}
2018-08-24 09:05:23 -07:00
/ * *
2019-03-04 08:06:33 -08:00
* Fetch the current transaction count of the cluster
2018-08-24 09:05:23 -07:00
* /
2022-06-29 09:22:34 -07:00
async getTransactionCount (
commitmentOrConfig? : Commitment | GetTransactionCountConfig ,
) : Promise < number > {
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getTransactionCount' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , jsonRpcResult ( number ( ) ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get transaction count' ,
) ;
2018-08-23 10:52:48 -07:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2018-08-23 10:52:48 -07:00
}
2019-06-25 08:31:22 -07:00
/ * *
2019-06-29 08:48:45 -07:00
* Fetch the current total currency supply of the cluster in lamports
2021-05-25 10:12:47 -07:00
*
* @deprecated Deprecated since v1 . 2.8 . Please use { @link getSupply } instead .
2019-06-25 08:31:22 -07:00
* /
2021-03-14 20:01:35 -07:00
async getTotalSupply ( commitment? : Commitment ) : Promise < number > {
2021-10-22 13:12:49 -07:00
const result = await this . getSupply ( {
commitment ,
excludeNonCirculatingAccountsList : true ,
} ) ;
return result . value . total ;
2019-06-25 08:31:22 -07:00
}
2019-08-28 07:21:39 -07:00
/ * *
2020-06-03 08:38:48 -07:00
* Fetch the cluster InflationGovernor parameters
2019-08-28 07:21:39 -07:00
* /
2020-06-03 08:38:48 -07:00
async getInflationGovernor (
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-06-03 08:38:48 -07:00
) : Promise < InflationGovernor > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ ] , commitment ) ;
2020-06-03 08:38:48 -07:00
const unsafeRes = await this . _rpcRequest ( 'getInflationGovernor' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetInflationGovernorRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get inflation' ) ;
2019-08-28 07:21:39 -07:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2019-08-28 07:21:39 -07:00
}
2021-04-26 11:09:40 -07:00
/ * *
* Fetch the inflation reward for a list of addresses for an epoch
* /
async getInflationReward (
addresses : PublicKey [ ] ,
epoch? : number ,
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetInflationRewardConfig ,
2021-04-26 11:09:40 -07:00
) : Promise < ( InflationReward | null ) [ ] > {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2021-04-26 11:09:40 -07:00
const args = this . _buildArgs (
[ addresses . map ( pubkey = > pubkey . toBase58 ( ) ) ] ,
commitment ,
2022-06-29 09:22:34 -07:00
undefined /* encoding */ ,
2021-04-26 11:09:40 -07:00
{
2022-06-29 09:22:34 -07:00
. . . config ,
epoch : epoch != null ? epoch : config?.epoch ,
2021-04-26 11:09:40 -07:00
} ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getInflationReward' , args ) ;
const res = create ( unsafeRes , GetInflationRewardResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get inflation reward' ) ;
2021-04-26 11:09:40 -07:00
}
return res . result ;
}
2019-10-29 09:50:05 -07:00
/ * *
* Fetch the Epoch Info parameters
* /
2022-06-29 09:22:34 -07:00
async getEpochInfo (
commitmentOrConfig? : Commitment | GetEpochInfoConfig ,
) : Promise < EpochInfo > {
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getEpochInfo' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetEpochInfoRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get epoch info' ) ;
2019-10-29 09:50:05 -07:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2019-10-29 09:50:05 -07:00
}
2019-10-23 06:48:24 -07:00
/ * *
* Fetch the Epoch Schedule parameters
* /
2020-05-21 02:11:32 -07:00
async getEpochSchedule ( ) : Promise < EpochSchedule > {
2019-10-23 06:48:24 -07:00
const unsafeRes = await this . _rpcRequest ( 'getEpochSchedule' , [ ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetEpochScheduleRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get epoch schedule' ) ;
2019-10-23 06:48:24 -07:00
}
2021-06-09 22:47:54 -07:00
const epochSchedule = res . result ;
return new EpochSchedule (
epochSchedule . slotsPerEpoch ,
epochSchedule . leaderScheduleSlotOffset ,
epochSchedule . warmup ,
epochSchedule . firstNormalEpoch ,
epochSchedule . firstNormalSlot ,
) ;
2019-10-23 06:48:24 -07:00
}
2020-07-17 08:16:44 -07:00
/ * *
* Fetch the leader schedule for the current epoch
* @return { Promise < RpcResponseAndContext < LeaderSchedule > > }
* /
async getLeaderSchedule ( ) : Promise < LeaderSchedule > {
const unsafeRes = await this . _rpcRequest ( 'getLeaderSchedule' , [ ] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetLeaderScheduleRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get leader schedule' ) ;
2020-07-17 08:16:44 -07:00
}
return res . result ;
}
2019-09-26 13:13:57 -07:00
/ * *
* Fetch the minimum balance needed to exempt an account of ` dataLength `
* size from rent
* /
2019-11-11 10:01:10 -08:00
async getMinimumBalanceForRentExemption (
dataLength : number ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2019-11-11 10:01:10 -08:00
) : Promise < number > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ dataLength ] , commitment ) ;
2019-09-26 13:13:57 -07:00
const unsafeRes = await this . _rpcRequest (
'getMinimumBalanceForRentExemption' ,
2019-11-11 10:01:10 -08:00
args ,
2019-09-26 13:13:57 -07:00
) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetMinimumBalanceForRentExemptionRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2019-10-19 11:36:06 -07:00
console . warn ( 'Unable to fetch minimum balance for rent exemption' ) ;
2019-09-29 10:14:18 -07:00
return 0 ;
2019-09-26 13:13:57 -07:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2019-09-26 13:13:57 -07:00
}
2018-08-24 09:05:23 -07:00
/ * *
2020-01-08 13:44:50 -08:00
* Fetch a recent blockhash from the cluster , return with context
2020-02-14 07:01:01 -08:00
* @return { Promise < RpcResponseAndContext < { blockhash : Blockhash , feeCalculator : FeeCalculator } > > }
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getLatestBlockhash } instead .
2018-08-24 09:05:23 -07:00
* /
2019-11-13 14:31:31 -08:00
async getRecentBlockhashAndContext (
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-02-14 07:01:01 -08:00
) : Promise <
2021-03-14 20:01:35 -07:00
RpcResponseAndContext < { blockhash : Blockhash ; feeCalculator : FeeCalculator } >
2020-02-14 07:01:01 -08:00
> {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ ] , commitment ) ;
2019-11-11 10:01:10 -08:00
const unsafeRes = await this . _rpcRequest ( 'getRecentBlockhash' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetRecentBlockhashAndContextRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get recent blockhash' ) ;
2018-08-23 10:52:48 -07:00
}
2020-01-08 12:59:58 -08:00
return res . result ;
2019-11-13 14:31:31 -08:00
}
2020-01-08 13:44:50 -08:00
2020-10-08 20:26:58 -07:00
/ * *
* Fetch recent performance samples
* @return { Promise < Array < PerfSample > > }
* /
async getRecentPerformanceSamples (
2021-03-14 20:01:35 -07:00
limit? : number ,
2020-10-08 20:26:58 -07:00
) : Promise < Array < PerfSample > > {
const unsafeRes = await this . _rpcRequest (
'getRecentPerformanceSamples' ,
2022-07-01 22:34:05 -07:00
limit ? [ limit ] : [ ] ,
2020-10-08 20:26:58 -07:00
) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetRecentPerformanceSamplesRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get recent performance samples' ,
2020-10-08 20:26:58 -07:00
) ;
}
return res . result ;
}
2020-06-04 03:12:59 -07:00
/ * *
* Fetch the fee calculator for a recent blockhash from the cluster , return with context
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getFeeForMessage } instead .
2020-06-04 03:12:59 -07:00
* /
async getFeeCalculatorForBlockhash (
blockhash : Blockhash ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-06-04 03:12:59 -07:00
) : Promise < RpcResponseAndContext < FeeCalculator | null > > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ blockhash ] , commitment ) ;
2020-06-04 03:12:59 -07:00
const unsafeRes = await this . _rpcRequest (
'getFeeCalculatorForBlockhash' ,
args ,
) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetFeeCalculatorRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get fee calculator' ) ;
2020-06-04 03:12:59 -07:00
}
const { context , value } = res . result ;
return {
context ,
2021-03-14 20:01:35 -07:00
value : value !== null ? value.feeCalculator : null ,
2020-06-04 03:12:59 -07:00
} ;
}
2022-01-11 01:49:28 -08:00
/ * *
* Fetch the fee for a message from the cluster , return with context
* /
async getFeeForMessage (
message : Message ,
commitment? : Commitment ,
) : Promise < RpcResponseAndContext < number > > {
const wireMessage = message . serialize ( ) . toString ( 'base64' ) ;
const args = this . _buildArgs ( [ wireMessage ] , commitment ) ;
const unsafeRes = await this . _rpcRequest ( 'getFeeForMessage' , args ) ;
const res = create ( unsafeRes , jsonRpcResultAndContext ( nullable ( number ( ) ) ) ) ;
if ( 'error' in res ) {
2022-10-20 18:50:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get fee for message' ) ;
2022-01-11 01:49:28 -08:00
}
if ( res . result === null ) {
throw new Error ( 'invalid blockhash' ) ;
}
return res . result as unknown as RpcResponseAndContext < number > ;
}
2020-01-08 13:44:50 -08:00
/ * *
* Fetch a recent blockhash from the cluster
2020-02-14 07:01:01 -08:00
* @return { Promise < { blockhash : Blockhash , feeCalculator : FeeCalculator } > }
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getLatestBlockhash } instead .
2020-01-08 13:44:50 -08:00
* /
2019-11-13 14:31:31 -08:00
async getRecentBlockhash (
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
) : Promise < { blockhash : Blockhash ; feeCalculator : FeeCalculator } > {
2021-02-25 23:06:12 -08:00
try {
const res = await this . getRecentBlockhashAndContext ( commitment ) ;
return res . value ;
} catch ( e ) {
throw new Error ( 'failed to get recent blockhash: ' + e ) ;
}
2019-11-11 11:08:00 -08:00
}
2022-01-27 15:43:01 -08:00
/ * *
* Fetch the latest blockhash from the cluster
2022-05-14 21:54:12 -07:00
* @return { Promise < BlockhashWithExpiryBlockHeight > }
2022-01-27 15:43:01 -08:00
* /
async getLatestBlockhash (
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetLatestBlockhashConfig ,
2022-05-14 21:54:12 -07:00
) : Promise < BlockhashWithExpiryBlockHeight > {
2022-01-27 15:43:01 -08:00
try {
2022-06-29 09:22:34 -07:00
const res = await this . getLatestBlockhashAndContext ( commitmentOrConfig ) ;
2022-01-27 15:43:01 -08:00
return res . value ;
} catch ( e ) {
throw new Error ( 'failed to get recent blockhash: ' + e ) ;
}
}
/ * *
* Fetch the latest blockhash from the cluster
2022-05-14 21:54:12 -07:00
* @return { Promise < BlockhashWithExpiryBlockHeight > }
2022-01-27 15:43:01 -08:00
* /
async getLatestBlockhashAndContext (
2022-06-29 09:22:34 -07:00
commitmentOrConfig? : Commitment | GetLatestBlockhashConfig ,
2022-05-14 21:54:12 -07:00
) : Promise < RpcResponseAndContext < BlockhashWithExpiryBlockHeight > > {
2022-06-29 09:22:34 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2022-01-27 15:43:01 -08:00
const unsafeRes = await this . _rpcRequest ( 'getLatestBlockhash' , args ) ;
const res = create ( unsafeRes , GetLatestBlockhashRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get latest blockhash' ) ;
2022-01-27 15:43:01 -08:00
}
return res . result ;
}
2019-11-11 17:09:00 -08:00
/ * *
* Fetch the node version
* /
async getVersion ( ) : Promise < Version > {
const unsafeRes = await this . _rpcRequest ( 'getVersion' , [ ] ) ;
2021-03-14 19:52:04 -07:00
const res = create ( unsafeRes , jsonRpcResult ( VersionResult ) ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get version' ) ;
2021-09-09 10:34:43 -07:00
}
return res . result ;
}
/ * *
* Fetch the genesis hash
* /
async getGenesisHash ( ) : Promise < string > {
const unsafeRes = await this . _rpcRequest ( 'getGenesisHash' , [ ] ) ;
const res = create ( unsafeRes , jsonRpcResult ( string ( ) ) ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get genesis hash' ) ;
2019-11-11 17:09:00 -08:00
}
2019-06-12 14:36:05 -07:00
return res . result ;
2018-08-23 10:52:48 -07:00
}
2019-11-12 08:21:19 -08:00
/ * *
2021-05-25 10:12:47 -07:00
* Fetch a processed block from the cluster .
2022-08-31 05:46:24 -07:00
*
* @deprecated Instead , call ` getBlock ` using a ` GetVersionedBlockConfig ` by
* setting the ` maxSupportedTransactionVersion ` property .
2019-11-12 08:21:19 -08:00
* /
2021-05-25 10:12:47 -07:00
async getBlock (
2021-04-09 11:58:08 -07:00
slot : number ,
2022-07-21 21:02:05 -07:00
rawConfig? : GetBlockConfig ,
2022-08-31 05:46:24 -07:00
) : Promise < BlockResponse | null > ;
/ * *
* Fetch a processed block from the cluster .
* /
// eslint-disable-next-line no-dupe-class-members
async getBlock (
slot : number ,
rawConfig? : GetVersionedBlockConfig ,
) : Promise < VersionedBlockResponse | null > ;
/ * *
* Fetch a processed block from the cluster .
* /
// eslint-disable-next-line no-dupe-class-members
async getBlock (
slot : number ,
rawConfig? : GetVersionedBlockConfig ,
) : Promise < VersionedBlockResponse | null > {
2022-07-21 21:02:05 -07:00
const { commitment , config } = extractCommitmentFromConfig ( rawConfig ) ;
2021-05-25 10:12:47 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ slot ] ,
2022-07-21 21:02:05 -07:00
commitment as Finality ,
undefined /* encoding */ ,
config ,
2021-05-25 10:12:47 -07:00
) ;
2022-01-27 15:43:01 -08:00
const unsafeRes = await this . _rpcRequest ( 'getBlock' , args ) ;
const res = create ( unsafeRes , GetBlockRpcResult ) ;
2021-05-25 10:12:47 -07:00
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get confirmed block' ) ;
2019-11-12 08:21:19 -08:00
}
2021-05-25 10:12:47 -07:00
const result = res . result ;
if ( ! result ) return result ;
return {
. . . result ,
2022-08-31 05:46:24 -07:00
transactions : result.transactions.map ( ( { transaction , meta , version } ) = > ( {
meta ,
transaction : {
. . . transaction ,
message : versionedMessageFromResponse ( version , transaction . message ) ,
} ,
version ,
} ) ) ,
2021-05-25 10:12:47 -07:00
} ;
}
2022-10-11 01:13:10 -07:00
/ * *
* Fetch parsed transaction details for a confirmed or finalized block
* /
async getParsedBlock (
slot : number ,
rawConfig? : GetVersionedBlockConfig ,
) : Promise < ParsedBlockResponse | null > {
const { commitment , config } = extractCommitmentFromConfig ( rawConfig ) ;
const args = this . _buildArgsAtLeastConfirmed (
[ slot ] ,
commitment as Finality ,
'jsonParsed' ,
config ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getBlock' , args ) ;
const res = create ( unsafeRes , GetParsedBlockRpcResult ) ;
if ( 'error' in res ) {
throw new SolanaJSONRPCError ( res . error , 'failed to get block' ) ;
}
return res . result ;
}
2022-02-22 18:49:27 -08:00
/ *
* Returns the current block height of the node
* /
2022-06-29 09:22:34 -07:00
async getBlockHeight (
commitmentOrConfig? : Commitment | GetBlockHeightConfig ,
) : Promise < number > {
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
const args = this . _buildArgs (
[ ] ,
commitment ,
undefined /* encoding */ ,
config ,
) ;
2022-02-22 18:49:27 -08:00
const unsafeRes = await this . _rpcRequest ( 'getBlockHeight' , args ) ;
const res = create ( unsafeRes , jsonRpcResult ( number ( ) ) ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get block height information' ,
2022-02-22 18:49:27 -08:00
) ;
}
return res . result ;
}
/ *
* Returns recent block production information from the current or previous epoch
* /
async getBlockProduction (
configOrCommitment? : GetBlockProductionConfig | Commitment ,
) : Promise < RpcResponseAndContext < BlockProduction > > {
let extra : Omit < GetBlockProductionConfig , ' commitment ' > | undefined ;
let commitment : Commitment | undefined ;
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 = create ( unsafeRes , BlockProductionResponseStruct ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get block production information' ,
2022-02-22 18:49:27 -08:00
) ;
}
return res . result ;
}
2021-05-25 10:12:47 -07:00
/ * *
2022-01-27 15:43:01 -08:00
* Fetch a confirmed or finalized transaction from the cluster .
2022-08-31 05:46:24 -07:00
*
* @deprecated Instead , call ` getTransaction ` using a
* ` GetVersionedTransactionConfig ` by setting the
* ` maxSupportedTransactionVersion ` property .
2021-05-25 10:12:47 -07:00
* /
async getTransaction (
signature : string ,
2022-07-21 21:02:05 -07:00
rawConfig? : GetTransactionConfig ,
2022-08-31 05:46:24 -07:00
) : Promise < TransactionResponse | null > ;
/ * *
* Fetch a confirmed or finalized transaction from the cluster .
* /
// eslint-disable-next-line no-dupe-class-members
async getTransaction (
signature : string ,
rawConfig : GetVersionedTransactionConfig ,
) : Promise < VersionedTransactionResponse | null > ;
/ * *
* Fetch a confirmed or finalized transaction from the cluster .
* /
// eslint-disable-next-line no-dupe-class-members
async getTransaction (
signature : string ,
rawConfig? : GetVersionedTransactionConfig ,
) : Promise < VersionedTransactionResponse | null > {
2022-07-21 21:02:05 -07:00
const { commitment , config } = extractCommitmentFromConfig ( rawConfig ) ;
2021-05-25 10:12:47 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
2022-07-21 21:02:05 -07:00
commitment as Finality ,
undefined /* encoding */ ,
config ,
2021-05-25 10:12:47 -07:00
) ;
2022-01-27 15:43:01 -08:00
const unsafeRes = await this . _rpcRequest ( 'getTransaction' , args ) ;
const res = create ( unsafeRes , GetTransactionRpcResult ) ;
2021-05-25 10:12:47 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get transaction' ) ;
2021-05-25 10:12:47 -07:00
}
2020-10-28 20:23:07 -07:00
const result = res . result ;
2021-05-25 10:12:47 -07:00
if ( ! result ) return result ;
return {
. . . result ,
transaction : {
. . . result . transaction ,
2022-08-31 05:46:24 -07:00
message : versionedMessageFromResponse (
result . version ,
result . transaction . message ,
) ,
2021-05-25 10:12:47 -07:00
} ,
} ;
}
2022-01-27 15:43:01 -08:00
/ * *
* Fetch parsed transaction details for a confirmed or finalized transaction
* /
async getParsedTransaction (
signature : TransactionSignature ,
2022-08-31 05:46:24 -07:00
commitmentOrConfig? : GetVersionedTransactionConfig | Finality ,
) : Promise < ParsedTransactionWithMeta | null > {
2022-07-22 00:54:55 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2022-01-27 15:43:01 -08:00
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
2022-07-22 00:54:55 -07:00
commitment as Finality ,
2022-01-27 15:43:01 -08:00
'jsonParsed' ,
2022-07-22 00:54:55 -07:00
config ,
2022-01-27 15:43:01 -08:00
) ;
const unsafeRes = await this . _rpcRequest ( 'getTransaction' , args ) ;
const res = create ( unsafeRes , GetParsedTransactionRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get transaction' ) ;
2022-01-27 15:43:01 -08:00
}
return res . result ;
}
/ * *
* Fetch parsed transaction details for a batch of confirmed transactions
* /
async getParsedTransactions (
signatures : TransactionSignature [ ] ,
2022-08-31 05:46:24 -07:00
commitmentOrConfig? : GetVersionedTransactionConfig | Finality ,
) : Promise < ( ParsedTransactionWithMeta | null ) [ ] > {
2022-07-22 00:54:55 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2022-01-27 15:43:01 -08:00
const batch = signatures . map ( signature = > {
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
2022-07-22 00:54:55 -07:00
commitment as Finality ,
2022-01-27 15:43:01 -08:00
'jsonParsed' ,
2022-07-22 00:54:55 -07:00
config ,
2022-01-27 15:43:01 -08:00
) ;
return {
methodName : 'getTransaction' ,
args ,
} ;
} ) ;
const unsafeRes = await this . _rpcBatchRequest ( batch ) ;
const res = unsafeRes . map ( ( unsafeRes : any ) = > {
const res = create ( unsafeRes , GetParsedTransactionRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get transactions' ) ;
2022-01-27 15:43:01 -08:00
}
return res . result ;
} ) ;
return res ;
}
2022-04-25 06:46:33 -07:00
/ * *
* Fetch transaction details for a batch of confirmed transactions .
* Similar to { @link getParsedTransactions } but returns a { @link TransactionResponse } .
2022-08-31 05:46:24 -07:00
*
* @deprecated Instead , call ` getTransactions ` using a
* ` GetVersionedTransactionConfig ` by setting the
* ` maxSupportedTransactionVersion ` property .
2022-04-25 06:46:33 -07:00
* /
async getTransactions (
signatures : TransactionSignature [ ] ,
2022-07-22 00:54:55 -07:00
commitmentOrConfig? : GetTransactionConfig | Finality ,
2022-08-31 05:46:24 -07:00
) : Promise < ( TransactionResponse | null ) [ ] > ;
/ * *
* 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 : TransactionSignature [ ] ,
commitmentOrConfig : GetVersionedTransactionConfig | Finality ,
) : Promise < ( VersionedTransactionResponse | null ) [ ] > ;
/ * *
* 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 : TransactionSignature [ ] ,
commitmentOrConfig : GetVersionedTransactionConfig | Finality ,
) : Promise < ( VersionedTransactionResponse | null ) [ ] > {
2022-07-22 00:54:55 -07:00
const { commitment , config } =
extractCommitmentFromConfig ( commitmentOrConfig ) ;
2022-04-25 06:46:33 -07:00
const batch = signatures . map ( signature = > {
2022-07-22 00:54:55 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
commitment as Finality ,
undefined /* encoding */ ,
config ,
) ;
2022-04-25 06:46:33 -07:00
return {
methodName : 'getTransaction' ,
args ,
} ;
} ) ;
const unsafeRes = await this . _rpcBatchRequest ( batch ) ;
const res = unsafeRes . map ( ( unsafeRes : any ) = > {
const res = create ( unsafeRes , GetTransactionRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get transactions' ) ;
2022-04-25 06:46:33 -07:00
}
2022-06-21 10:31:42 -07:00
const result = res . result ;
if ( ! result ) return result ;
return {
. . . result ,
transaction : {
. . . result . transaction ,
2022-08-31 05:46:24 -07:00
message : versionedMessageFromResponse (
result . version ,
result . transaction . message ,
) ,
2022-06-21 10:31:42 -07:00
} ,
} ;
2022-04-25 06:46:33 -07:00
} ) ;
return res ;
}
2021-05-25 10:12:47 -07:00
/ * *
* Fetch a list of Transactions and transaction statuses from the cluster
* for a confirmed block .
*
* @deprecated Deprecated since v1 . 13.0 . Please use { @link getBlock } instead .
* /
async getConfirmedBlock (
slot : number ,
commitment? : Finality ,
) : Promise < ConfirmedBlock > {
2022-01-27 15:43:01 -08:00
const args = this . _buildArgsAtLeastConfirmed ( [ slot ] , commitment ) ;
const unsafeRes = await this . _rpcRequest ( 'getConfirmedBlock' , args ) ;
const res = create ( unsafeRes , GetConfirmedBlockRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get confirmed block' ) ;
2022-01-27 15:43:01 -08:00
}
const result = res . result ;
2020-06-10 22:15:14 -07:00
if ( ! result ) {
2020-02-03 00:59:39 -08:00
throw new Error ( 'Confirmed block ' + slot + ' not found' ) ;
2020-01-22 12:05:19 -08:00
}
2021-05-25 10:12:47 -07:00
2022-01-27 15:43:01 -08:00
const block = {
2021-05-25 10:12:47 -07:00
. . . result ,
transactions : result.transactions.map ( ( { transaction , meta } ) = > {
2022-01-27 15:43:01 -08:00
const message = new Message ( transaction . message ) ;
return {
meta ,
transaction : {
. . . transaction ,
message ,
} ,
} ;
} ) ,
} ;
return {
. . . block ,
transactions : block.transactions.map ( ( { transaction , meta } ) = > {
2021-05-25 10:12:47 -07:00
return {
meta ,
transaction : Transaction.populate (
transaction . message ,
transaction . signatures ,
) ,
} ;
} ) ,
} ;
2019-11-12 08:21:19 -08:00
}
2021-09-20 20:08:12 -07:00
/ * *
* Fetch confirmed blocks between two slots
* /
async getBlocks (
startSlot : number ,
endSlot? : number ,
commitment? : Finality ,
) : Promise < Array < number > > {
const args = this . _buildArgsAtLeastConfirmed (
endSlot !== undefined ? [ startSlot , endSlot ] : [ startSlot ] ,
commitment ,
) ;
2022-01-27 15:43:01 -08:00
const unsafeRes = await this . _rpcRequest ( 'getBlocks' , args ) ;
2021-09-20 20:08:12 -07:00
const res = create ( unsafeRes , jsonRpcResult ( array ( number ( ) ) ) ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get blocks' ) ;
2021-09-20 20:08:12 -07:00
}
return res . result ;
}
2022-01-27 15:43:01 -08:00
/ * *
* Fetch a list of Signatures from the cluster for a block , excluding rewards
* /
async getBlockSignatures (
slot : number ,
commitment? : Finality ,
) : Promise < BlockSignatures > {
const args = this . _buildArgsAtLeastConfirmed (
[ slot ] ,
commitment ,
undefined ,
{
transactionDetails : 'signatures' ,
rewards : false ,
} ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getBlock' , args ) ;
const res = create ( unsafeRes , GetBlockSignaturesRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get block' ) ;
2022-01-27 15:43:01 -08:00
}
const result = res . result ;
if ( ! result ) {
throw new Error ( 'Block ' + slot + ' not found' ) ;
}
return result ;
}
2021-04-13 23:56:08 -07:00
/ * *
* Fetch a list of Signatures from the cluster for a confirmed block , excluding rewards
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getBlockSignatures } instead .
2021-04-13 23:56:08 -07:00
* /
async getConfirmedBlockSignatures (
slot : number ,
2021-04-09 11:58:08 -07:00
commitment? : Finality ,
2022-01-27 15:43:01 -08:00
) : Promise < BlockSignatures > {
2021-04-09 11:58:08 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ slot ] ,
commitment ,
undefined ,
{
transactionDetails : 'signatures' ,
rewards : false ,
} ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getConfirmedBlock' , args ) ;
2022-01-27 15:43:01 -08:00
const res = create ( unsafeRes , GetBlockSignaturesRpcResult ) ;
2021-04-13 23:56:08 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get confirmed block' ) ;
2021-04-13 23:56:08 -07:00
}
const result = res . result ;
if ( ! result ) {
throw new Error ( 'Confirmed block ' + slot + ' not found' ) ;
}
return result ;
}
2020-04-21 00:40:44 -07:00
/ * *
* Fetch a transaction details for a confirmed transaction
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getTransaction } instead .
2020-04-21 00:40:44 -07:00
* /
async getConfirmedTransaction (
signature : TransactionSignature ,
2021-04-09 11:58:08 -07:00
commitment? : Finality ,
2020-04-21 00:40:44 -07:00
) : Promise < ConfirmedTransaction | null > {
2022-01-27 15:43:01 -08:00
const args = this . _buildArgsAtLeastConfirmed ( [ signature ] , commitment ) ;
const unsafeRes = await this . _rpcRequest ( 'getConfirmedTransaction' , args ) ;
const res = create ( unsafeRes , GetTransactionRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError ( res . error , 'failed to get transaction' ) ;
2022-01-27 15:43:01 -08:00
}
const result = res . result ;
2021-05-25 10:12:47 -07:00
if ( ! result ) return result ;
2022-01-27 15:43:01 -08:00
const message = new Message ( result . transaction . message ) ;
const signatures = result . transaction . signatures ;
2021-05-25 10:12:47 -07:00
return {
. . . result ,
transaction : Transaction.populate ( message , signatures ) ,
} ;
2020-04-21 00:40:44 -07:00
}
2020-08-06 04:16:01 -07:00
/ * *
* Fetch parsed transaction details for a confirmed transaction
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getParsedTransaction } instead .
2020-08-06 04:16:01 -07:00
* /
async getParsedConfirmedTransaction (
signature : TransactionSignature ,
2021-04-09 11:58:08 -07:00
commitment? : Finality ,
2020-08-06 04:16:01 -07:00
) : Promise < ParsedConfirmedTransaction | null > {
2021-04-09 11:58:08 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
commitment ,
2020-08-06 04:16:01 -07:00
'jsonParsed' ,
2021-04-09 11:58:08 -07:00
) ;
const unsafeRes = await this . _rpcRequest ( 'getConfirmedTransaction' , args ) ;
2022-01-27 15:43:01 -08:00
const res = create ( unsafeRes , GetParsedTransactionRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get confirmed transaction' ,
2021-02-25 23:06:12 -08:00
) ;
2020-12-14 19:22:22 -08:00
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-08-06 04:16:01 -07:00
}
2021-03-22 10:22:59 -07:00
/ * *
* Fetch parsed transaction details for a batch of confirmed transactions
2022-01-27 15:43:01 -08:00
*
* @deprecated Deprecated since Solana v1 . 8.0 . Please use { @link getParsedTransactions } instead .
2021-03-22 10:22:59 -07:00
* /
async getParsedConfirmedTransactions (
signatures : TransactionSignature [ ] ,
2021-04-09 11:58:08 -07:00
commitment? : Finality ,
2021-03-22 10:22:59 -07:00
) : Promise < ( ParsedConfirmedTransaction | null ) [ ] > {
const batch = signatures . map ( signature = > {
2021-04-09 11:58:08 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
commitment ,
'jsonParsed' ,
) ;
2021-03-22 10:22:59 -07:00
return {
methodName : 'getConfirmedTransaction' ,
2021-04-09 11:58:08 -07:00
args ,
2021-03-22 10:22:59 -07:00
} ;
} ) ;
const unsafeRes = await this . _rpcBatchRequest ( batch ) ;
const res = unsafeRes . map ( ( unsafeRes : any ) = > {
2022-01-27 15:43:01 -08:00
const res = create ( unsafeRes , GetParsedTransactionRpcResult ) ;
2021-03-22 10:22:59 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get confirmed transactions' ,
2021-03-22 10:22:59 -07:00
) ;
}
return res . result ;
} ) ;
return res ;
}
2020-04-21 00:40:44 -07:00
/ * *
* 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 .
2021-05-25 10:12:47 -07:00
*
* @deprecated Deprecated since v1 . 3 . Please use { @link getConfirmedSignaturesForAddress2 } instead .
2020-04-21 00:40:44 -07:00
*
* @param address queried address
* @param startSlot start slot , inclusive
* @param endSlot end slot , inclusive
* /
async getConfirmedSignaturesForAddress (
address : PublicKey ,
startSlot : number ,
endSlot : number ,
) : Promise < Array < TransactionSignature > > {
2021-04-14 01:25:19 -07:00
let options : any = { } ;
let firstAvailableBlock = await this . getFirstAvailableBlock ( ) ;
while ( ! ( 'until' in options ) ) {
startSlot -- ;
if ( startSlot <= 0 || startSlot < firstAvailableBlock ) {
break ;
}
try {
2021-04-09 11:58:08 -07:00
const block = await this . getConfirmedBlockSignatures (
startSlot ,
'finalized' ,
) ;
2021-04-14 01:25:19 -07:00
if ( block . signatures . length > 0 ) {
2021-05-24 20:53:16 -07:00
options . until =
block . signatures [ block . signatures . length - 1 ] . toString ( ) ;
2021-04-14 01:25:19 -07:00
}
} catch ( err ) {
2021-09-25 12:25:14 -07:00
if ( err instanceof Error && err . message . includes ( 'skipped' ) ) {
2021-04-14 01:25:19 -07:00
continue ;
} else {
throw err ;
}
}
2021-04-16 09:11:34 -07:00
}
2021-04-14 01:25:19 -07:00
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 ) {
2021-05-24 20:53:16 -07:00
options . before =
block . signatures [ block . signatures . length - 1 ] . toString ( ) ;
2021-04-14 01:25:19 -07:00
}
} catch ( err ) {
2021-09-25 12:25:14 -07:00
if ( err instanceof Error && err . message . includes ( 'skipped' ) ) {
2021-04-14 01:25:19 -07:00
continue ;
} else {
throw err ;
}
}
}
const confirmedSignatureInfo = await this . getConfirmedSignaturesForAddress2 (
address ,
options ,
) ;
return confirmedSignatureInfo . map ( info = > info . signature ) ;
2020-04-21 00:40:44 -07:00
}
2020-07-29 22:40:46 -07:00
/ * *
* 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 getConfirmedSignaturesForAddress2 (
address : PublicKey ,
2021-03-14 20:01:35 -07:00
options? : ConfirmedSignaturesForAddress2Options ,
2021-04-09 11:58:08 -07:00
commitment? : Finality ,
2020-07-29 22:40:46 -07:00
) : Promise < Array < ConfirmedSignatureInfo > > {
2021-04-09 11:58:08 -07:00
const args = this . _buildArgsAtLeastConfirmed (
[ address . toBase58 ( ) ] ,
commitment ,
undefined ,
options ,
) ;
2020-07-29 22:40:46 -07:00
const unsafeRes = await this . _rpcRequest (
'getConfirmedSignaturesForAddress2' ,
2021-04-09 11:58:08 -07:00
args ,
2020-07-29 22:40:46 -07:00
) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , GetConfirmedSignaturesForAddress2RpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get confirmed signatures for address' ,
2020-07-29 22:40:46 -07:00
) ;
}
2021-02-25 23:06:12 -08:00
return res . result ;
2020-07-29 22:40:46 -07:00
}
2021-06-21 23:07:36 -07:00
/ * *
* 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 : PublicKey ,
options? : SignaturesForAddressOptions ,
commitment? : Finality ,
) : Promise < Array < ConfirmedSignatureInfo > > {
const args = this . _buildArgsAtLeastConfirmed (
[ address . toBase58 ( ) ] ,
commitment ,
undefined ,
options ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getSignaturesForAddress' , args ) ;
const res = create ( unsafeRes , GetSignaturesForAddressRpcResult ) ;
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
'failed to get signatures for address' ,
2021-06-21 23:07:36 -07:00
) ;
}
return res . result ;
}
2022-08-14 03:11:49 -07:00
async getAddressLookupTable (
accountKey : PublicKey ,
config? : GetAccountInfoConfig ,
) : Promise < RpcResponseAndContext < AddressLookupTableAccount | null > > {
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 ,
} ;
}
2020-01-02 17:54:43 -08:00
/ * *
2020-01-08 13:44:50 -08:00
* Fetch the contents of a Nonce account from the cluster , return with context
2020-01-02 17:54:43 -08:00
* /
async getNonceAndContext (
nonceAccount : PublicKey ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-04-05 01:18:45 -07:00
) : Promise < RpcResponseAndContext < NonceAccount | null > > {
const { context , value : accountInfo } = await this . getAccountInfoAndContext (
nonceAccount ,
2020-01-02 17:54:43 -08:00
commitment ,
) ;
2020-04-05 01:18:45 -07:00
let value = null ;
if ( accountInfo !== null ) {
value = NonceAccount . fromAccountData ( accountInfo . data ) ;
}
2020-01-02 17:54:43 -08:00
return {
2020-04-05 01:18:45 -07:00
context ,
2020-01-02 17:54:43 -08:00
value ,
} ;
}
2020-01-08 13:44:50 -08:00
/ * *
* Fetch the contents of a Nonce account from the cluster
* /
2020-01-02 17:54:43 -08:00
async getNonce (
nonceAccount : PublicKey ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-04-05 01:18:45 -07:00
) : Promise < NonceAccount | null > {
2020-01-02 17:54:43 -08:00
return await this . getNonceAndContext ( nonceAccount , commitment )
. then ( x = > x . value )
. catch ( e = > {
2020-04-08 16:49:51 -07:00
throw new Error (
'failed to get nonce for account ' +
nonceAccount . toBase58 ( ) +
': ' +
e ,
) ;
2020-01-02 17:54:43 -08:00
} ) ;
}
2018-08-24 09:05:23 -07:00
/ * *
2021-06-06 12:20:14 -07:00
* 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 ) ;
* } ) ( ) ;
* ` ` `
2018-08-24 09:05:23 -07:00
* /
2018-11-04 11:41:21 -08:00
async requestAirdrop (
to : PublicKey ,
2021-06-06 12:20:14 -07:00
lamports : number ,
2018-11-04 11:41:21 -08:00
) : Promise < TransactionSignature > {
2020-06-10 09:10:25 -07:00
const unsafeRes = await this . _rpcRequest ( 'requestAirdrop' , [
to . toBase58 ( ) ,
2021-06-06 12:20:14 -07:00
lamports ,
2020-06-10 09:10:25 -07:00
] ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , RequestAirdropRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2022-06-30 13:08:10 -07:00
throw new SolanaJSONRPCError (
res . error ,
` airdrop to ${ to . toBase58 ( ) } failed ` ,
2020-04-08 16:49:51 -07:00
) ;
2018-08-23 16:39:52 -07:00
}
2018-09-12 17:41:20 -07:00
return res . result ;
2018-08-23 10:52:48 -07:00
}
2021-03-14 20:01:35 -07:00
/ * *
* @internal
* /
2022-05-14 21:54:12 -07:00
async _blockhashWithExpiryBlockHeight (
disableCache : boolean ,
) : Promise < BlockhashWithExpiryBlockHeight > {
2020-08-10 23:35:56 -07:00
if ( ! disableCache ) {
2020-08-25 21:59:56 -07:00
// Wait for polling to finish
while ( this . _pollingBlockhash ) {
await sleep ( 100 ) ;
}
2021-03-14 20:01:35 -07:00
const timeSinceFetch = Date . now ( ) - this . _blockhashInfo . lastFetch ;
const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS ;
2022-05-14 21:54:12 -07:00
if ( this . _blockhashInfo . latestBlockhash !== null && ! expired ) {
return this . _blockhashInfo . latestBlockhash ;
2020-08-10 23:35:56 -07:00
}
}
return await this . _pollNewBlockhash ( ) ;
}
2021-03-14 20:01:35 -07:00
/ * *
* @internal
* /
2022-05-14 21:54:12 -07:00
async _pollNewBlockhash ( ) : Promise < BlockhashWithExpiryBlockHeight > {
2020-08-25 21:59:56 -07:00
this . _pollingBlockhash = true ;
try {
const startTime = Date . now ( ) ;
2022-05-14 21:54:12 -07:00
const cachedLatestBlockhash = this . _blockhashInfo . latestBlockhash ;
const cachedBlockhash = cachedLatestBlockhash
? cachedLatestBlockhash . blockhash
: null ;
2020-08-25 21:59:56 -07:00
for ( let i = 0 ; i < 50 ; i ++ ) {
2022-05-14 21:54:12 -07:00
const latestBlockhash = await this . getLatestBlockhash ( 'finalized' ) ;
2020-08-25 21:59:56 -07:00
2022-05-14 21:54:12 -07:00
if ( cachedBlockhash !== latestBlockhash . blockhash ) {
2020-08-25 21:59:56 -07:00
this . _blockhashInfo = {
2022-05-14 21:54:12 -07:00
latestBlockhash ,
2021-03-14 20:01:35 -07:00
lastFetch : Date.now ( ) ,
2020-08-25 21:59:56 -07:00
transactionSignatures : [ ] ,
simulatedSignatures : [ ] ,
} ;
2022-05-14 21:54:12 -07:00
return latestBlockhash ;
2020-08-25 21:59:56 -07:00
}
// Sleep for approximately half a slot
await sleep ( MS_PER_SLOT / 2 ) ;
2020-08-10 23:35:56 -07:00
}
2020-08-25 21:59:56 -07:00
throw new Error (
` Unable to obtain a new blockhash after ${ Date . now ( ) - startTime } ms ` ,
) ;
} finally {
this . _pollingBlockhash = false ;
2020-08-10 23:35:56 -07:00
}
}
2022-07-22 01:02:49 -07:00
/ * *
* get the stake minimum delegation
* /
async getStakeMinimumDelegation (
config? : GetStakeMinimumDelegationConfig ,
) : Promise < RpcResponseAndContext < number > > {
const { commitment , config : configArg } = extractCommitmentFromConfig ( config ) ;
const args = this . _buildArgs ( [ ] , commitment , 'base64' , configArg ) ;
const unsafeRes = await this . _rpcRequest ( 'getStakeMinimumDelegation' , args ) ;
const res = create ( unsafeRes , jsonRpcResultAndContext ( number ( ) ) ) ;
if ( 'error' in res ) {
throw new SolanaJSONRPCError (
res . error ,
` failed to get stake minimum delegation ` ,
) ;
}
return res . result ;
}
2020-08-10 23:35:56 -07:00
/ * *
* Simulate a transaction
2022-09-06 20:53:42 -07:00
*
* @deprecated Instead , call { @link simulateTransaction } with { @link
* VersionedTransaction } and { @link SimulateTransactionConfig } parameters
2020-08-10 23:35:56 -07:00
* /
2022-09-06 20:53:42 -07:00
simulateTransaction (
2021-09-16 14:10:28 -07:00
transactionOrMessage : Transaction | Message ,
2021-05-07 01:59:51 -07:00
signers? : Array < Signer > ,
2021-09-16 14:10:28 -07:00
includeAccounts? : boolean | Array < PublicKey > ,
2022-09-06 20:53:42 -07:00
) : Promise < RpcResponseAndContext < SimulatedTransactionResponse > > ;
/ * *
* Simulate a transaction
* /
// eslint-disable-next-line no-dupe-class-members
simulateTransaction (
transaction : VersionedTransaction ,
config? : SimulateTransactionConfig ,
) : Promise < RpcResponseAndContext < SimulatedTransactionResponse > > ;
/ * *
* Simulate a transaction
* /
// eslint-disable-next-line no-dupe-class-members
async simulateTransaction (
transactionOrMessage : VersionedTransaction | Transaction | Message ,
configOrSigners? : SimulateTransactionConfig | Array < Signer > ,
includeAccounts? : boolean | Array < PublicKey > ,
2020-08-10 23:35:56 -07:00
) : Promise < RpcResponseAndContext < SimulatedTransactionResponse > > {
2022-09-06 20:53:42 -07:00
if ( 'message' in transactionOrMessage ) {
const versionedTx = transactionOrMessage ;
const wireTransaction = versionedTx . serialize ( ) ;
const encodedTransaction =
Buffer . from ( wireTransaction ) . toString ( 'base64' ) ;
if ( Array . isArray ( configOrSigners ) || includeAccounts !== undefined ) {
throw new Error ( 'Invalid arguments' ) ;
}
const config : any = configOrSigners || { } ;
config . encoding = 'base64' ;
if ( ! ( 'commitment' in config ) ) {
config . commitment = this . commitment ;
}
const args = [ encodedTransaction , config ] ;
const unsafeRes = await this . _rpcRequest ( 'simulateTransaction' , args ) ;
const res = create ( unsafeRes , SimulatedTransactionResponseStruct ) ;
if ( 'error' in res ) {
throw new Error ( 'failed to simulate transaction: ' + res . error . message ) ;
}
return res . result ;
}
2021-09-16 14:10:28 -07:00
let transaction ;
if ( transactionOrMessage instanceof Transaction ) {
2022-04-12 21:54:46 -07:00
let originalTx : Transaction = transactionOrMessage ;
2022-05-14 21:54:12 -07:00
transaction = new Transaction ( ) ;
transaction . feePayer = originalTx . feePayer ;
2022-04-12 21:54:46 -07:00
transaction . instructions = transactionOrMessage . instructions ;
2022-05-14 21:54:12 -07:00
transaction . nonceInfo = originalTx . nonceInfo ;
transaction . signatures = originalTx . signatures ;
2021-09-16 14:10:28 -07:00
} else {
transaction = Transaction . populate ( transactionOrMessage ) ;
2022-04-16 12:28:57 -07:00
// HACK: this function relies on mutating the populated transaction
transaction . _message = transaction . _json = undefined ;
2021-09-16 14:10:28 -07:00
}
2022-09-06 20:53:42 -07:00
if ( configOrSigners !== undefined && ! Array . isArray ( configOrSigners ) ) {
throw new Error ( 'Invalid arguments' ) ;
}
const signers = configOrSigners ;
2020-08-10 23:35:56 -07:00
if ( transaction . nonceInfo && signers ) {
transaction . sign ( . . . signers ) ;
} else {
let disableCache = this . _disableBlockhashCaching ;
for ( ; ; ) {
2022-05-14 21:54:12 -07:00
const latestBlockhash = await this . _blockhashWithExpiryBlockHeight (
disableCache ,
) ;
transaction . lastValidBlockHeight = latestBlockhash . lastValidBlockHeight ;
transaction . recentBlockhash = latestBlockhash . blockhash ;
2020-08-10 23:35:56 -07:00
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 )
) {
2021-03-30 21:10:14 -07:00
// The signature of this transaction has not been seen before with the
// current recentBlockhash, all done. Let's break
2020-08-10 23:35:56 -07:00
this . _blockhashInfo . simulatedSignatures . push ( signature ) ;
break ;
} else {
2021-03-30 21:10:14 -07:00
// 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).
2020-08-10 23:35:56 -07:00
disableCache = true ;
}
}
}
2021-09-16 14:10:28 -07:00
const message = transaction . _compile ( ) ;
const signData = message . serialize ( ) ;
2020-08-10 23:35:56 -07:00
const wireTransaction = transaction . _serialize ( signData ) ;
2020-10-16 08:54:30 -07:00
const encodedTransaction = wireTransaction . toString ( 'base64' ) ;
2020-12-24 10:43:45 -08:00
const config : any = {
encoding : 'base64' ,
commitment : this.commitment ,
} ;
2020-08-10 23:35:56 -07:00
2021-09-16 14:10:28 -07:00
if ( includeAccounts ) {
const addresses = (
Array . isArray ( includeAccounts )
? includeAccounts
: message . nonProgramIds ( )
) . map ( key = > key . toBase58 ( ) ) ;
config [ 'accounts' ] = {
encoding : 'base64' ,
addresses ,
} ;
}
2020-08-10 23:35:56 -07:00
if ( signers ) {
2020-10-16 08:54:30 -07:00
config . sigVerify = true ;
2020-08-10 23:35:56 -07:00
}
2021-03-14 20:01:35 -07:00
const args = [ encodedTransaction , config ] ;
2020-08-10 23:35:56 -07:00
const unsafeRes = await this . _rpcRequest ( 'simulateTransaction' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , SimulatedTransactionResponseStruct ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2021-07-13 07:14:20 -07:00
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 (
'failed to simulate transaction: ' + res . error . message ,
logs ,
) ;
2020-08-10 23:35:56 -07:00
}
return res . result ;
}
2018-08-24 09:05:23 -07:00
/ * *
2018-09-14 08:27:40 -07:00
* Sign and send a transaction
2022-09-06 20:53:42 -07:00
*
* @deprecated Instead , call { @link sendTransaction } with a { @link
* VersionedTransaction }
2018-08-24 09:05:23 -07:00
* /
2022-09-06 20:53:42 -07:00
sendTransaction (
2018-11-04 11:41:21 -08:00
transaction : Transaction ,
2021-05-07 01:59:51 -07:00
signers : Array < Signer > ,
2020-06-03 04:55:42 -07:00
options? : SendOptions ,
2022-09-06 20:53:42 -07:00
) : Promise < TransactionSignature > ;
/ * *
* Send a signed transaction
* /
// eslint-disable-next-line no-dupe-class-members
sendTransaction (
transaction : VersionedTransaction ,
options? : SendOptions ,
) : Promise < TransactionSignature > ;
/ * *
* Sign and send a transaction
* /
// eslint-disable-next-line no-dupe-class-members
async sendTransaction (
transaction : VersionedTransaction | Transaction ,
signersOrOptions? : Array < Signer > | SendOptions ,
options? : SendOptions ,
2018-11-04 11:41:21 -08:00
) : Promise < TransactionSignature > {
2022-09-12 17:22:12 -07:00
if ( 'version' in transaction ) {
2022-09-06 20:53:42 -07:00
if ( signersOrOptions && Array . isArray ( signersOrOptions ) ) {
throw new Error ( 'Invalid arguments' ) ;
}
const wireTransaction = transaction . serialize ( ) ;
return await this . sendRawTransaction ( wireTransaction , options ) ;
}
if ( signersOrOptions === undefined || ! Array . isArray ( signersOrOptions ) ) {
throw new Error ( 'Invalid arguments' ) ;
}
const signers = signersOrOptions ;
2020-01-07 16:57:56 -08:00
if ( transaction . nonceInfo ) {
transaction . sign ( . . . signers ) ;
} else {
2020-08-10 23:35:56 -07:00
let disableCache = this . _disableBlockhashCaching ;
2020-01-07 16:57:56 -08:00
for ( ; ; ) {
2022-05-14 21:54:12 -07:00
const latestBlockhash = await this . _blockhashWithExpiryBlockHeight (
disableCache ,
) ;
transaction . lastValidBlockHeight = latestBlockhash . lastValidBlockHeight ;
transaction . recentBlockhash = latestBlockhash . blockhash ;
2020-08-10 23:35:56 -07:00
transaction . sign ( . . . signers ) ;
if ( ! transaction . signature ) {
throw new Error ( '!signature' ) ; // should never happen
2018-10-22 20:03:44 -07:00
}
2020-08-10 23:35:56 -07:00
const signature = transaction . signature . toString ( 'base64' ) ;
if ( ! this . _blockhashInfo . transactionSignatures . includes ( signature ) ) {
2021-03-30 21:10:14 -07:00
// The signature of this transaction has not been seen before with the
// current recentBlockhash, all done. Let's break
2020-08-10 23:35:56 -07:00
this . _blockhashInfo . transactionSignatures . push ( signature ) ;
break ;
} else {
2021-03-30 21:10:14 -07:00
// 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).
2020-08-10 23:35:56 -07:00
disableCache = true ;
2020-01-07 16:57:56 -08:00
}
2018-10-22 15:31:56 -07:00
}
}
2018-08-24 17:14:58 -07:00
2018-09-13 18:48:51 -07:00
const wireTransaction = transaction . serialize ( ) ;
2020-06-03 04:55:42 -07:00
return await this . sendRawTransaction ( wireTransaction , options ) ;
2018-11-27 21:06:03 -08:00
}
/ * *
* Send a transaction that has already been signed and serialized into the
* wire format
* /
async sendRawTransaction (
2020-02-12 16:25:22 -08:00
rawTransaction : Buffer | Uint8Array | Array < number > ,
2021-03-14 20:01:35 -07:00
options? : SendOptions ,
2020-01-21 21:16:56 -08:00
) : Promise < TransactionSignature > {
2020-10-16 08:54:30 -07:00
const encodedTransaction = toBuffer ( rawTransaction ) . toString ( 'base64' ) ;
2020-06-03 04:55:42 -07:00
const result = await this . sendEncodedTransaction (
encodedTransaction ,
options ,
) ;
2020-01-21 21:16:56 -08:00
return result ;
}
/ * *
* Send a transaction that has already been signed , serialized into the
2020-10-16 08:54:30 -07:00
* wire format , and encoded as a base64 string
2020-01-21 21:16:56 -08:00
* /
async sendEncodedTransaction (
encodedTransaction : string ,
2021-03-14 20:01:35 -07:00
options? : SendOptions ,
2018-11-27 21:06:03 -08:00
) : Promise < TransactionSignature > {
2020-10-16 08:54:30 -07:00
const config : any = { encoding : 'base64' } ;
2020-06-03 04:55:42 -07:00
const skipPreflight = options && options . skipPreflight ;
2021-02-12 17:29:26 -08:00
const preflightCommitment =
( options && options . preflightCommitment ) || this . commitment ;
2020-09-24 17:49:34 -07:00
2022-06-30 23:20:22 -07:00
if ( options && options . maxRetries != null ) {
2022-02-03 10:54:43 -08:00
config . maxRetries = options . maxRetries ;
}
2022-06-29 09:22:34 -07:00
if ( options && options . minContextSlot != null ) {
config . minContextSlot = options . minContextSlot ;
}
2020-09-24 17:49:34 -07:00
if ( skipPreflight ) {
2020-10-16 08:54:30 -07:00
config . skipPreflight = skipPreflight ;
2020-11-16 09:15:51 -08:00
}
if ( preflightCommitment ) {
2020-10-16 08:54:30 -07:00
config . preflightCommitment = preflightCommitment ;
2020-09-24 17:49:34 -07:00
}
2021-03-14 20:01:35 -07:00
const args = [ encodedTransaction , config ] ;
2020-06-03 04:55:42 -07:00
const unsafeRes = await this . _rpcRequest ( 'sendTransaction' , args ) ;
2021-02-25 23:06:12 -08:00
const res = create ( unsafeRes , SendTransactionRpcResult ) ;
2021-03-14 20:01:35 -07:00
if ( 'error' in res ) {
2021-07-13 07:14:20 -07:00
let logs ;
2021-03-14 20:01:35 -07:00
if ( 'data' in res . error ) {
2021-07-13 07:14:20 -07:00
logs = res . error . data . logs ;
2020-10-28 17:59:16 -07:00
}
2021-07-13 07:14:20 -07:00
throw new SendTransactionError (
'failed to send transaction: ' + res . error . message ,
logs ,
) ;
2018-08-23 20:10:30 -07:00
}
return res . result ;
2018-08-23 10:52:48 -07:00
}
2018-10-26 21:37:39 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2018-10-26 21:37:39 -07:00
* /
_wsOnOpen() {
2020-09-07 08:12:22 -07:00
this . _rpcWebSocketConnected = true ;
2020-09-06 19:24:16 -07:00
this . _rpcWebSocketHeartbeat = setInterval ( ( ) = > {
// Ping server every 5s to prevent idle timeouts
this . _rpcWebSocket . notify ( 'ping' ) . catch ( ( ) = > { } ) ;
} , 5000 ) ;
2018-10-26 21:37:39 -07:00
this . _updateSubscriptions ( ) ;
}
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2018-10-26 21:37:39 -07:00
* /
_wsOnError ( err : Error ) {
2022-05-13 02:07:13 -07:00
this . _rpcWebSocketConnected = false ;
2020-04-09 04:34:33 -07:00
console . error ( 'ws error:' , err . message ) ;
2018-10-26 21:37:39 -07:00
}
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2018-10-26 21:37:39 -07:00
* /
2020-09-07 08:12:22 -07:00
_wsOnClose ( code : number ) {
2022-05-13 02:07:13 -07:00
this . _rpcWebSocketConnected = false ;
2022-10-16 23:33:28 -07:00
this . _rpcWebSocketGeneration =
( this . _rpcWebSocketGeneration + 1 ) % Number . MAX_SAFE_INTEGER ;
2022-07-24 21:56:03 -07:00
if ( this . _rpcWebSocketIdleTimeout ) {
clearTimeout ( this . _rpcWebSocketIdleTimeout ) ;
this . _rpcWebSocketIdleTimeout = null ;
}
2021-03-14 20:01:35 -07:00
if ( this . _rpcWebSocketHeartbeat ) {
clearInterval ( this . _rpcWebSocketHeartbeat ) ;
this . _rpcWebSocketHeartbeat = null ;
}
2020-09-07 08:12:22 -07:00
if ( code === 1000 ) {
// explicit close, check if any subscriptions have been made since close
this . _updateSubscriptions ( ) ;
return ;
}
// implicit close, prepare subscriptions for auto-reconnect
2022-04-28 16:21:39 -07:00
this . _subscriptionCallbacksByServerSubscriptionId = { } ;
Object . entries (
this . _subscriptionsByHash as Record < SubscriptionConfigHash , Subscription > ,
) . forEach ( ( [ hash , subscription ] ) = > {
this . _subscriptionsByHash [ hash ] = {
. . . subscription ,
state : 'pending' ,
} ;
} ) ;
2020-04-09 04:34:33 -07:00
}
2018-10-26 21:37:39 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2018-10-26 21:37:39 -07:00
* /
2022-04-28 16:21:39 -07:00
async _updateSubscriptions() {
if ( Object . keys ( this . _subscriptionsByHash ) . length === 0 ) {
2020-09-07 08:12:22 -07:00
if ( this . _rpcWebSocketConnected ) {
this . _rpcWebSocketConnected = false ;
this . _rpcWebSocketIdleTimeout = setTimeout ( ( ) = > {
this . _rpcWebSocketIdleTimeout = null ;
2022-02-04 03:21:58 -08:00
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 } ` ,
) ;
}
}
2020-09-07 08:12:22 -07:00
} , 500 ) ;
}
2018-10-26 21:37:39 -07:00
return ;
}
2020-09-07 08:12:22 -07:00
if ( this . _rpcWebSocketIdleTimeout !== null ) {
clearTimeout ( this . _rpcWebSocketIdleTimeout ) ;
this . _rpcWebSocketIdleTimeout = null ;
this . _rpcWebSocketConnected = true ;
}
if ( ! this . _rpcWebSocketConnected ) {
2018-10-26 21:37:39 -07:00
this . _rpcWebSocket . connect ( ) ;
return ;
}
2022-04-28 16:21:39 -07:00
const activeWebSocketGeneration = this . _rpcWebSocketGeneration ;
const isCurrentConnectionStillActive = ( ) = > {
return activeWebSocketGeneration === this . _rpcWebSocketGeneration ;
} ;
2021-05-02 05:14:30 -07:00
2022-04-28 16:21:39 -07:00
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 . _subscriptionsByHash [ hash ] = {
. . . subscription ,
state : 'subscribing' ,
} ;
const serverSubscriptionId : ServerSubscriptionId =
( await this . _rpcWebSocket . call ( method , args ) ) as number ;
this . _subscriptionsByHash [ hash ] = {
. . . subscription ,
serverSubscriptionId ,
state : 'subscribed' ,
} ;
this . _subscriptionCallbacksByServerSubscriptionId [
serverSubscriptionId
] = subscription . callbacks ;
await this . _updateSubscriptions ( ) ;
} catch ( e ) {
if ( e instanceof Error ) {
console . error (
` ${ method } error for argument ` ,
args ,
e . message ,
) ;
}
if ( ! isCurrentConnectionStillActive ( ) ) {
return ;
}
// TODO: Maybe add an 'errored' state or a retry limit?
this . _subscriptionsByHash [ 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 . _subscriptionsByHash [ 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 . _subscriptionsByHash [ hash ] = {
. . . subscription ,
state : 'subscribed' ,
} ;
await this . _updateSubscriptions ( ) ;
return ;
}
}
this . _subscriptionsByHash [ hash ] = {
. . . subscription ,
state : 'unsubscribed' ,
} ;
await this . _updateSubscriptions ( ) ;
} ) ( ) ;
}
break ;
case 'subscribing' :
case 'unsubscribing' :
break ;
}
} ) ,
) ;
}
2020-03-27 07:22:53 -07:00
2022-04-28 16:21:39 -07:00
/ * *
* @internal
* /
private _handleServerNotification <
TCallback extends SubscriptionConfig [ 'callback' ] ,
> (
serverSubscriptionId : ServerSubscriptionId ,
callbackArgs : Parameters < TCallback > ,
) : void {
const callbacks =
this . _subscriptionCallbacksByServerSubscriptionId [ serverSubscriptionId ] ;
if ( callbacks === undefined ) {
return ;
2020-03-27 07:22:53 -07:00
}
2022-04-28 16:21:39 -07:00
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 ) ;
2021-03-23 20:05:17 -07:00
}
2022-04-28 16:21:39 -07:00
} ) ;
2019-03-08 16:02:39 -08:00
}
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-03-08 16:02:39 -08:00
* /
2021-03-14 20:01:35 -07:00
_wsOnAccountNotification ( notification : object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = create (
notification ,
AccountNotificationResult ,
) ;
this . _handleServerNotification < AccountChangeCallback > ( subscription , [
result . value ,
result . context ,
] ) ;
}
/ * *
* @internal
* /
private _makeSubscription (
subscriptionConfig : 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 : IWSRequestParams ,
) : ClientSubscriptionId {
const clientSubscriptionId = this . _nextClientSubscriptionId ++ ;
const hash = fastStableStringify (
[ subscriptionConfig . method , args ] ,
true /* isArrayProp */ ,
) ;
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 ) ;
2019-03-08 16:02:39 -08:00
}
2022-04-28 16:21:39 -07:00
this . _subscriptionDisposeFunctionsByClientSubscriptionId [
clientSubscriptionId
] = async ( ) = > {
delete this . _subscriptionDisposeFunctionsByClientSubscriptionId [
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 ;
2018-10-26 21:37:39 -07:00
}
/ * *
* Register a callback to be invoked whenever the specified account changes
*
2020-05-20 21:17:38 -07:00
* @param publicKey Public key of the account to monitor
2018-10-26 21:37:39 -07:00
* @param callback Function to invoke whenever the account is changed
2020-05-20 21:17:38 -07:00
* @param commitment Specify the commitment level account changes must reach before notification
2018-10-26 21:37:39 -07:00
* @return subscription id
* /
2018-11-04 11:41:21 -08:00
onAccountChange (
publicKey : PublicKey ,
callback : AccountChangeCallback ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2022-04-28 16:21:39 -07:00
) : ClientSubscriptionId {
const args = this . _buildArgs (
[ publicKey . toBase58 ( ) ] ,
commitment || this . _commitment || 'finalized' , // Apply connection/server default.
'base64' ,
) ;
return this . _makeSubscription (
{
callback ,
method : 'accountSubscribe' ,
unsubscribeMethod : 'accountUnsubscribe' ,
} ,
args ,
) ;
2018-10-26 21:37:39 -07:00
}
/ * *
* Deregister an account notification callback
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister
2018-10-26 21:37:39 -07:00
* /
2022-04-28 16:21:39 -07:00
async removeAccountChangeListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription (
clientSubscriptionId ,
'account change' ,
) ;
2018-10-26 21:37:39 -07:00
}
2019-03-08 16:02:39 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-03-08 16:02:39 -08:00
* /
_wsOnProgramAccountNotification ( notification : Object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = create (
notification ,
ProgramAccountNotificationResult ,
) ;
this . _handleServerNotification < ProgramAccountChangeCallback > ( subscription , [
{
accountId : result.value.pubkey ,
accountInfo : result.value.account ,
} ,
result . context ,
] ) ;
2019-03-08 16:02:39 -08:00
}
/ * *
* 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
2020-05-20 21:17:38 -07:00
* @param commitment Specify the commitment level account changes must reach before notification
2021-06-28 07:21:47 -07:00
* @param filters The program account filters to pass into the RPC method
2019-03-08 16:02:39 -08:00
* @return subscription id
* /
onProgramAccountChange (
programId : PublicKey ,
callback : ProgramAccountChangeCallback ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2021-06-28 07:21:47 -07:00
filters? : GetProgramAccountsFilter [ ] ,
2022-04-28 16:21:39 -07:00
) : ClientSubscriptionId {
const args = this . _buildArgs (
[ programId . toBase58 ( ) ] ,
commitment || this . _commitment || 'finalized' , // Apply connection/server default.
'base64' /* encoding */ ,
filters ? { filters : filters } : undefined /* extra */ ,
) ;
return this . _makeSubscription (
{
callback ,
method : 'programSubscribe' ,
unsubscribeMethod : 'programUnsubscribe' ,
} ,
args ,
) ;
2019-03-08 16:02:39 -08:00
}
/ * *
* Deregister an account notification callback
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister
2019-03-08 16:02:39 -08:00
* /
2022-04-28 16:21:39 -07:00
async removeProgramAccountChangeListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription (
clientSubscriptionId ,
'program account change' ,
) ;
2019-03-08 16:02:39 -08:00
}
2019-11-11 10:01:10 -08:00
2021-03-23 20:05:17 -07:00
/ * *
* Registers a callback to be invoked whenever logs are emitted .
* /
onLogs (
filter : LogsFilter ,
callback : LogsCallback ,
commitment? : Commitment ,
2022-04-28 16:21:39 -07:00
) : ClientSubscriptionId {
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 ,
) ;
2021-03-23 20:05:17 -07:00
}
/ * *
* Deregister a logs callback .
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister .
2021-03-23 20:05:17 -07:00
* /
2022-04-28 16:21:39 -07:00
async removeOnLogsListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription ( clientSubscriptionId , 'logs' ) ;
2021-03-23 20:05:17 -07:00
}
/ * *
* @internal
* /
_wsOnLogsNotification ( notification : Object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = create ( notification , LogsNotificationResult ) ;
this . _handleServerNotification < LogsCallback > ( subscription , [
result . value ,
result . context ,
] ) ;
2021-03-23 20:05:17 -07:00
}
2019-11-25 08:04:35 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-11-25 08:04:35 -08:00
* /
_wsOnSlotNotification ( notification : Object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = create ( notification , SlotNotificationResult ) ;
this . _handleServerNotification < SlotChangeCallback > ( subscription , [ result ] ) ;
2019-11-25 08:04:35 -08:00
}
/ * *
* Register a callback to be invoked upon slot changes
*
* @param callback Function to invoke whenever the slot changes
* @return subscription id
* /
2022-04-28 16:21:39 -07:00
onSlotChange ( callback : SlotChangeCallback ) : ClientSubscriptionId {
return this . _makeSubscription (
{
callback ,
method : 'slotSubscribe' ,
unsubscribeMethod : 'slotUnsubscribe' ,
} ,
[ ] /* args */ ,
) ;
2019-11-25 08:04:35 -08:00
}
/ * *
* Deregister a slot notification callback
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister
2019-11-25 08:04:35 -08:00
* /
2022-04-28 16:21:39 -07:00
async removeSlotChangeListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription (
clientSubscriptionId ,
'slot change' ,
) ;
2019-11-25 08:04:35 -08:00
}
2021-03-14 20:01:35 -07:00
/ * *
* @internal
* /
2021-05-02 05:14:30 -07:00
_wsOnSlotUpdatesNotification ( notification : Object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = create (
notification ,
SlotUpdateNotificationResult ,
) ;
this . _handleServerNotification < SlotUpdateCallback > ( subscription , [ result ] ) ;
2021-05-02 05:14:30 -07:00
}
/ * *
* 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
* /
2022-04-28 16:21:39 -07:00
onSlotUpdate ( callback : SlotUpdateCallback ) : ClientSubscriptionId {
return this . _makeSubscription (
{
callback ,
method : 'slotsUpdatesSubscribe' ,
unsubscribeMethod : 'slotsUpdatesUnsubscribe' ,
} ,
[ ] /* args */ ,
) ;
2021-05-02 05:14:30 -07:00
}
/ * *
* Deregister a slot update notification callback
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister
2021-05-02 05:14:30 -07:00
* /
2022-04-28 16:21:39 -07:00
async removeSlotUpdateListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription (
clientSubscriptionId ,
'slot update' ,
) ;
}
/ * *
* @internal
* /
private async _unsubscribeClientSubscription (
clientSubscriptionId : ClientSubscriptionId ,
subscriptionName : string ,
) {
const dispose =
this . _subscriptionDisposeFunctionsByClientSubscriptionId [
clientSubscriptionId
] ;
if ( dispose ) {
await dispose ( ) ;
2021-05-02 05:14:30 -07:00
} else {
2022-04-28 16:21:39 -07:00
console . warn (
'Ignored unsubscribe request because an active subscription with id ' +
` \` ${ clientSubscriptionId } \` for ' ${ subscriptionName } ' events ` +
'could not be found.' ,
) ;
2021-05-02 05:14:30 -07:00
}
}
2020-08-10 01:26:48 -07:00
_buildArgs (
2020-08-06 08:47:22 -07:00
args : Array < any > ,
2022-07-01 22:34:05 -07:00
override? : Commitment ,
2020-08-15 21:57:23 -07:00
encoding ? : 'jsonParsed' | 'base64' ,
2020-09-16 23:50:13 -07:00
extra? : any ,
2020-08-06 08:47:22 -07:00
) : Array < any > {
2022-07-01 22:34:05 -07:00
const commitment = override || this . _commitment ;
2020-09-16 23:50:13 -07:00
if ( commitment || encoding || extra ) {
2020-08-06 08:47:22 -07:00
let options : any = { } ;
if ( encoding ) {
options . encoding = encoding ;
}
if ( commitment ) {
options . commitment = commitment ;
}
2020-09-16 23:50:13 -07:00
if ( extra ) {
options = Object . assign ( options , extra ) ;
}
2020-08-06 08:47:22 -07:00
args . push ( options ) ;
2019-11-11 10:01:10 -08:00
}
return args ;
}
2020-02-03 07:22:11 -08:00
2021-04-09 11:58:08 -07:00
/ * *
* @internal
* /
_buildArgsAtLeastConfirmed (
args : Array < any > ,
override? : Finality ,
encoding ? : 'jsonParsed' | 'base64' ,
extra? : any ,
) : Array < any > {
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 ) ;
}
2020-02-03 07:22:11 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-02-03 07:22:11 -08:00
* /
_wsOnSignatureNotification ( notification : Object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = 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 ) ;
2020-02-03 07:22:11 -08:00
}
2022-04-28 16:21:39 -07:00
this . _handleServerNotification < SignatureSubscriptionCallback > (
subscription ,
result . value === 'receivedSignature'
? [ { type : 'received' } , result . context ]
: [ { type : 'status' , result : result.value } , result . context ] ,
) ;
2020-02-03 07:22:11 -08:00
}
/ * *
* Register a callback to be invoked upon signature updates
*
2020-02-10 06:45:52 -08:00
* @param signature Transaction signature string in base 58
2020-02-03 07:22:11 -08:00
* @param callback Function to invoke on signature notifications
2020-05-20 21:17:38 -07:00
* @param commitment Specify the commitment level signature must reach before notification
2020-02-03 07:22:11 -08:00
* @return subscription id
* /
onSignature (
signature : TransactionSignature ,
callback : SignatureResultCallback ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2022-04-28 16:21:39 -07:00
) : ClientSubscriptionId {
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
2022-05-11 20:32:02 -07:00
} catch ( _err ) {
2022-04-28 16:21:39 -07:00
// Already removed.
}
}
} ,
method : 'signatureSubscribe' ,
unsubscribeMethod : 'signatureUnsubscribe' ,
2021-03-18 18:30:36 -07:00
} ,
2022-04-28 16:21:39 -07:00
args ,
) ;
return clientSubscriptionId ;
2021-03-18 18:30:36 -07:00
}
/ * *
* 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 : TransactionSignature ,
callback : SignatureSubscriptionCallback ,
options? : SignatureSubscriptionOptions ,
2022-04-28 16:21:39 -07:00
) : ClientSubscriptionId {
const { commitment , . . . extra } = {
. . . options ,
commitment :
( options && options . commitment ) || this . _commitment || 'finalized' , // Apply connection/server default.
2020-02-03 07:22:11 -08:00
} ;
2022-04-28 16:21:39 -07:00
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
2022-05-11 20:32:02 -07:00
} catch ( _err ) {
2022-04-28 16:21:39 -07:00
// Already removed.
}
} ,
method : 'signatureSubscribe' ,
unsubscribeMethod : 'signatureUnsubscribe' ,
} ,
args ,
) ;
return clientSubscriptionId ;
2020-02-03 07:22:11 -08:00
}
/ * *
* Deregister a signature notification callback
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister
2020-02-03 07:22:11 -08:00
* /
2022-04-28 16:21:39 -07:00
async removeSignatureListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription (
clientSubscriptionId ,
'signature result' ,
) ;
2020-02-03 07:22:11 -08:00
}
2020-03-27 07:22:53 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-03-27 07:22:53 -07:00
* /
_wsOnRootNotification ( notification : Object ) {
2022-04-28 16:21:39 -07:00
const { result , subscription } = create ( notification , RootNotificationResult ) ;
this . _handleServerNotification < RootChangeCallback > ( subscription , [ result ] ) ;
2020-03-27 07:22:53 -07:00
}
/ * *
* Register a callback to be invoked upon root changes
*
* @param callback Function to invoke whenever the root changes
* @return subscription id
* /
2022-04-28 16:21:39 -07:00
onRootChange ( callback : RootChangeCallback ) : ClientSubscriptionId {
return this . _makeSubscription (
{
callback ,
method : 'rootSubscribe' ,
unsubscribeMethod : 'rootUnsubscribe' ,
} ,
[ ] /* args */ ,
) ;
2020-03-27 07:22:53 -07:00
}
/ * *
* Deregister a root notification callback
*
2022-04-28 16:21:39 -07:00
* @param id client subscription id to deregister
2020-03-27 07:22:53 -07:00
* /
2022-04-28 16:21:39 -07:00
async removeRootChangeListener (
clientSubscriptionId : ClientSubscriptionId ,
) : Promise < void > {
await this . _unsubscribeClientSubscription (
clientSubscriptionId ,
'root change' ,
) ;
2020-03-27 07:22:53 -07:00
}
2018-08-23 10:52:48 -07:00
}