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-15 23:49:31 -07:00
import crossFetch from 'cross-fetch' ;
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' ;
import { IWSRequestParams } from 'rpc-websockets/dist/lib/client' ;
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' ;
2021-07-13 07:14:20 -07:00
import { SendTransactionError } from './errors' ;
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' ;
2019-03-05 09:53:56 -08:00
import { Transaction } from './transaction' ;
2020-06-10 22:15:14 -07:00
import { Message } from './message' ;
2021-07-08 22:33:41 -07:00
import assert from './util/assert' ;
2018-10-22 15:31:56 -07:00
import { sleep } from './util/sleep' ;
2020-09-07 22:12:47 -07:00
import { promiseTimeout } from './util/promise-timeout' ;
2020-02-12 16:25:22 -08:00
import { toBuffer } from './util/to-buffer' ;
2021-05-27 14:57:32 -07:00
import { makeWebsocketUrl } from './util/url' ;
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 ;
2018-08-23 20:10:30 -07:00
type RpcRequest = ( methodName : string , args : Array < any > ) = > any ;
2018-08-23 10:52:48 -07:00
2021-03-22 10:22:59 -07:00
type RpcBatchRequest = ( requests : RpcParams [ ] ) = > any ;
/ * *
* @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 ;
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 ;
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 ;
} ;
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
} ;
/ * *
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
} ) ;
}
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' ;
/ * *
* 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 ;
} ;
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 ;
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 ( ) ) ,
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 ;
/ * *
* 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 ;
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 ;
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 ;
} ;
2020-04-21 00:40:44 -07:00
/ * *
* A confirmed transaction on the ledger
* /
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 ;
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
/ * *
* 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 ;
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 ;
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 ;
} > ;
/** 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
/ * *
* A ConfirmedBlock on the ledger
* /
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 ,
useHttps : boolean ,
httpHeaders? : HttpHeaders ,
2022-04-15 23:49:31 -07:00
customFetch? : typeof crossFetch ,
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-04-15 23:49:31 -07:00
const fetch = customFetch ? customFetch : crossFetch ;
2021-03-14 20:01:35 -07:00
let agentManager : AgentManager | undefined ;
2021-02-01 18:53:24 -08:00
if ( ! process . env . BROWSER ) {
agentManager = new AgentManager ( useHttps ) ;
}
2020-10-08 20:26:58 -07:00
2021-11-28 21:43:33 -08:00
let fetchWithMiddleware :
| ( ( url : string , options : any ) = > Promise < Response > )
| undefined ;
2021-04-26 08:35:07 -07:00
if ( fetchMiddleware ) {
2021-11-28 21:43:33 -08:00
fetchWithMiddleware = async ( url : string , options : any ) = > {
const modifiedFetchArgs = await new Promise < [ string , any ] > (
( resolve , reject ) = > {
2021-04-26 08:35:07 -07:00
try {
2021-11-28 21:43:33 -08:00
fetchMiddleware ( url , options , ( modifiedUrl , modifiedOptions ) = >
resolve ( [ modifiedUrl , modifiedOptions ] ) ,
) ;
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 || { } ,
) ,
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
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 ( ) ,
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 ( ) ,
2020-08-06 04:16:01 -07:00
} ) ,
2021-02-25 23:06:12 -08:00
) ,
instructions : array ( ParsedOrRawInstruction ) ,
recentBlockhash : string ( ) ,
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 ,
} ) ;
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 ) ) ) ,
} ) ;
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 ) ) ) ,
} ) ;
2020-04-21 00:40:44 -07:00
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 ) ,
} ) ,
) ,
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 ,
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 ( ) ) ) ,
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 [ ] ;
} ;
/ * *
* 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 [ ] ;
} ;
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 ;
/** Optional encoding for account data (default base64) */
encoding ? : 'base64' | 'jsonParsed' ;
} ;
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
2020-02-10 06:45:52 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-02-10 06:45:52 -08:00
* /
type SubscriptionId = 'subscribing' | number ;
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
* /
type AccountSubscriptionInfo = {
2021-03-14 20:01:35 -07:00
publicKey : string ; // PublicKey of the account as a base 58 string
callback : AccountChangeCallback ;
commitment? : Commitment ;
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
2018-11-04 11:41:21 -08:00
} ;
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 ;
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2019-03-08 16:02:39 -08:00
* /
type ProgramAccountSubscriptionInfo = {
2021-03-14 20:01:35 -07:00
programId : string ; // PublicKey of the program as a base 58 string
callback : ProgramAccountChangeCallback ;
commitment? : Commitment ;
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
2021-06-28 07:21:47 -07:00
filters? : GetProgramAccountsFilter [ ] ;
2019-03-08 16:02:39 -08:00
} ;
2020-02-03 07:22:11 -08:00
/ * *
* Callback function for slot change notifications
* /
export type SlotChangeCallback = ( slotInfo : SlotInfo ) = > void ;
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
* /
type SlotSubscriptionInfo = {
2021-03-14 20:01:35 -07:00
callback : SlotChangeCallback ;
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
2019-11-25 08:04:35 -08:00
} ;
2021-05-02 05:14:30 -07:00
/ * *
* Callback function for slot update notifications
* /
export type SlotUpdateCallback = ( slotUpdate : SlotUpdate ) = > void ;
/ * *
* @private
* /
type SlotUpdateSubscriptionInfo = {
callback : SlotUpdateCallback ;
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
} ;
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-02-03 07:22:11 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-02-03 07:22:11 -08:00
* /
type SignatureSubscriptionInfo = {
2021-03-14 20:01:35 -07:00
signature : TransactionSignature ; // TransactionSignature as a base 58 string
2021-03-18 18:30:36 -07:00
callback : SignatureSubscriptionCallback ;
options? : SignatureSubscriptionOptions ;
2021-03-14 20:01:35 -07:00
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
2020-02-03 07:22:11 -08:00
} ;
2019-11-25 08:04:35 -08:00
2020-03-27 07:22:53 -07:00
/ * *
* Callback function for root change notifications
* /
export type RootChangeCallback = ( root : number ) = > void ;
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-03-27 07:22:53 -07:00
* /
type RootSubscriptionInfo = {
2021-03-14 20:01:35 -07:00
callback : RootChangeCallback ;
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
2020-03-27 07:22:53 -07:00
} ;
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 ;
/ * *
* @private
* /
type LogsSubscriptionInfo = {
callback : LogsCallback ;
filter : LogsFilter ;
subscriptionId : SubscriptionId | null ; // null when there's no current server subscription id
commitment? : Commitment ;
} ;
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
* /
export type HttpHeaders = { [ header : string ] : string } ;
/ * *
* A callback used to augment the outgoing HTTP request
* /
export type FetchMiddleware = (
url : string ,
options : any ,
2021-11-28 21:43:33 -08:00
fetch : ( modifiedUrl : string , modifiedOptions : any ) = > 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 */
fetch? : typeof crossFetch ;
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
} ;
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 ;
/** @internal */ _disableBlockhashCaching : boolean = false ;
/** @internal */ _pollingBlockhash : boolean = false ;
/** @internal */ _blockhashInfo : {
recentBlockhash : Blockhash | null ;
lastFetch : number ;
simulatedSignatures : Array < string > ;
transactionSignatures : Array < string > ;
2021-05-27 14:57:32 -07:00
} = {
recentBlockhash : null ,
lastFetch : 0 ,
transactionSignatures : [ ] ,
simulatedSignatures : [ ] ,
2018-10-22 20:03:44 -07:00
} ;
2021-03-14 20:01:35 -07:00
/** @internal */ _accountChangeSubscriptionCounter : number = 0 ;
/** @internal */ _accountChangeSubscriptions : {
[ id : number ] : AccountSubscriptionInfo ;
2019-03-08 16:02:39 -08:00
} = { } ;
2021-03-14 20:01:35 -07:00
/** @internal */ _programAccountChangeSubscriptionCounter : number = 0 ;
/** @internal */ _programAccountChangeSubscriptions : {
[ id : number ] : ProgramAccountSubscriptionInfo ;
2019-11-25 08:04:35 -08:00
} = { } ;
2021-03-14 20:01:35 -07:00
/** @internal */ _rootSubscriptionCounter : number = 0 ;
/** @internal */ _rootSubscriptions : {
[ id : number ] : RootSubscriptionInfo ;
2020-02-03 07:22:11 -08:00
} = { } ;
2021-03-14 20:01:35 -07:00
/** @internal */ _signatureSubscriptionCounter : number = 0 ;
/** @internal */ _signatureSubscriptions : {
[ id : number ] : SignatureSubscriptionInfo ;
} = { } ;
/** @internal */ _slotSubscriptionCounter : number = 0 ;
/** @internal */ _slotSubscriptions : {
[ id : number ] : SlotSubscriptionInfo ;
2020-03-27 07:22:53 -07:00
} = { } ;
2018-08-23 10:52:48 -07:00
2021-03-23 20:05:17 -07:00
/** @internal */ _logsSubscriptionCounter : number = 0 ;
/** @internal */ _logsSubscriptions : {
[ id : number ] : LogsSubscriptionInfo ;
} = { } ;
2021-05-02 05:14:30 -07:00
/** @internal */ _slotUpdateSubscriptionCounter : number = 0 ;
/** @internal */ _slotUpdateSubscriptions : {
[ id : number ] : SlotUpdateSubscriptionInfo ;
} = { } ;
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-07-08 22:33:41 -07:00
let url = new URL ( endpoint ) ;
2020-10-06 09:41:18 -07:00
const useHttps = url . protocol === 'https:' ;
2018-10-26 21:37:39 -07:00
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
}
2021-05-27 14:57:32 -07:00
this . _rpcEndpoint = endpoint ;
this . _rpcWsEndpoint = wsEndpoint || makeWebsocketUrl ( endpoint ) ;
2021-04-26 08:35:07 -07:00
this . _rpcClient = createRpcClient (
2021-07-08 22:33:41 -07:00
url . toString ( ) ,
2021-04-26 08:35:07 -07:00
useHttps ,
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2019-11-13 14:31:31 -08:00
) : Promise < RpcResponseAndContext < number > > {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs ( [ publicKey . toBase58 ( ) ] , commitment ) ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error (
'failed to get balance for ' +
publicKey . toBase58 ( ) +
': ' +
res . error . message ,
) ;
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2019-11-13 14:31:31 -08:00
) : Promise < number > {
return await this . getBalanceAndContext ( publicKey , commitment )
. 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 ) {
2020-05-18 20:27:36 -07:00
throw new Error (
'failed to get block time for slot ' + slot + ': ' + res . error . message ,
) ;
}
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 ) {
2020-05-21 01:58:17 -07:00
throw new Error (
'failed to get minimum ledger slot: ' + res . error . message ,
) ;
}
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 ) {
2020-05-23 02:33:04 -07:00
throw new Error (
'failed to get first available block: ' + res . error . message ,
) ;
}
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 ) {
2020-05-22 04:30:22 -07:00
throw new Error ( 'failed to get supply: ' + res . error . message ) ;
}
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 ) {
2020-07-30 21:33:54 -07:00
throw new Error ( 'failed to get token supply: ' + res . error . message ) ;
}
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 ) {
2020-07-30 21:33:54 -07:00
throw new Error (
'failed to get token account balance: ' + res . error . message ,
) ;
}
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
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
> {
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
2020-08-15 21:57:23 -07:00
const args = this . _buildArgs ( _args , commitment , 'base64' ) ;
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 ) {
2020-07-30 21:33:54 -07:00
throw new Error (
'failed to get token accounts owned by account ' +
ownerAddress . toBase58 ( ) +
': ' +
res . error . message ,
) ;
}
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 ) {
2020-08-06 08:47:22 -07:00
throw new Error (
'failed to get token accounts owned by account ' +
ownerAddress . toBase58 ( ) +
': ' +
res . error . message ,
) ;
}
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 ) {
2020-05-22 10:23:29 -07:00
throw new Error ( 'failed to get largest accounts: ' + res . error . message ) ;
}
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 ) {
2020-08-11 02:28:07 -07:00
throw new Error (
'failed to get token largest accounts: ' + res . error . message ,
) ;
}
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-08-06 08:47:22 -07:00
) : Promise < RpcResponseAndContext < AccountInfo < Buffer > | null >> {
2020-08-25 09:05:33 -07:00
const args = this . _buildArgs ( [ publicKey . toBase58 ( ) ] , commitment , 'base64' ) ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error (
2020-04-09 09:48:18 -07:00
'failed to get info about account ' +
2020-04-08 16:49:51 -07:00
publicKey . toBase58 ( ) +
': ' +
res . error . message ,
) ;
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
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
> {
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs (
2020-08-06 08:47:22 -07:00
[ publicKey . toBase58 ( ) ] ,
commitment ,
'jsonParsed' ,
) ;
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 ) {
2020-08-06 08:47:22 -07:00
throw new Error (
'failed to get info about account ' +
publicKey . toBase58 ( ) +
': ' +
res . error . message ,
) ;
}
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-08-06 08:47:22 -07:00
) : Promise < AccountInfo < Buffer > | null > {
2021-02-25 23:06:12 -08:00
try {
const res = await this . getAccountInfoAndContext ( publicKey , commitment ) ;
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
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-01-22 07:09:48 -08:00
commitment? : Commitment ,
) : Promise < RpcResponseAndContext < ( AccountInfo < Buffer > | null ) [ ] >> {
2021-07-20 09:42:14 -07:00
const keys = publicKeys . map ( key = > key . toBase58 ( ) ) ;
2022-01-22 07:09:48 -08:00
const args = this . _buildArgs ( [ keys ] , commitment , 'base64' ) ;
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 ) {
throw new Error (
'failed to get info for accounts ' + keys + ': ' + res . error . message ,
) ;
}
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 [ ] ,
commitment? : Commitment ,
) : Promise < ( AccountInfo < Buffer > | null ) [ ] > {
const res = await this . getMultipleAccountsInfoAndContext (
publicKeys ,
commitment ,
) ;
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 ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
epoch? : number ,
2020-09-16 23:50:13 -07:00
) : Promise < StakeActivationData > {
const args = this . _buildArgs (
[ publicKey . toBase58 ( ) ] ,
commitment ,
undefined ,
epoch !== undefined ? { epoch } : undefined ,
) ;
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 ) {
2020-09-16 23:50:13 -07:00
throw new Error (
` failed to get Stake Activation ${ publicKey . toBase58 ( ) } : ${
res . error . message
} ` ,
) ;
}
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 > } >> {
2021-04-16 10:18:19 -07:00
const extra : Pick < GetProgramAccountsConfig , ' dataSlice ' | ' filters ' > = { } ;
let commitment ;
let encoding ;
if ( configOrCommitment ) {
if ( typeof configOrCommitment === 'string' ) {
commitment = configOrCommitment ;
} else {
commitment = configOrCommitment . commitment ;
encoding = configOrCommitment . encoding ;
if ( configOrCommitment . dataSlice ) {
extra . dataSlice = configOrCommitment . dataSlice ;
}
if ( configOrCommitment . filters ) {
extra . filters = configOrCommitment . filters ;
}
}
}
const args = this . _buildArgs (
[ programId . toBase58 ( ) ] ,
commitment ,
encoding || 'base64' ,
extra ,
) ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error (
2020-04-09 09:48:18 -07:00
'failed to get accounts owned by program ' +
2020-04-08 16:49:51 -07:00
programId . toBase58 ( ) +
': ' +
res . error . message ,
) ;
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
> {
2021-04-16 10:18:19 -07:00
const extra : Pick < GetParsedProgramAccountsConfig , ' filters ' > = { } ;
let commitment ;
if ( configOrCommitment ) {
if ( typeof configOrCommitment === 'string' ) {
commitment = configOrCommitment ;
} else {
commitment = configOrCommitment . commitment ;
if ( configOrCommitment . filters ) {
extra . filters = configOrCommitment . filters ;
}
}
}
2020-08-10 01:26:48 -07:00
const args = this . _buildArgs (
2020-08-06 08:47:22 -07:00
[ programId . toBase58 ( ) ] ,
commitment ,
'jsonParsed' ,
2021-04-16 10:18:19 -07:00
extra ,
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 ) {
2020-08-06 08:47:22 -07:00
throw new Error (
'failed to get accounts owned by program ' +
programId . toBase58 ( ) +
': ' +
res . error . message ,
) ;
}
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
/ * *
2020-09-05 00:34:03 -07:00
* Confirm the transaction identified by the specified signature .
2020-01-08 13:44:50 -08:00
* /
2019-11-13 14:31:31 -08:00
async confirmTransaction (
signature : TransactionSignature ,
2021-03-14 20:01:35 -07:00
commitment? : Commitment ,
2020-09-07 22:12:47 -07:00
) : Promise < RpcResponseAndContext < SignatureResult > > {
let decodedSignature ;
try {
decodedSignature = bs58 . decode ( signature ) ;
} catch ( err ) {
throw new Error ( 'signature must be base58 encoded: ' + signature ) ;
}
assert ( decodedSignature . length === 64 , 'signature has invalid length' ) ;
2020-06-15 03:32:57 -07:00
const start = Date . now ( ) ;
2020-10-29 10:22:53 -07:00
const subscriptionCommitment = commitment || this . commitment ;
2020-09-07 22:12:47 -07:00
let subscriptionId ;
let response : RpcResponseAndContext < SignatureResult > | null = null ;
const confirmPromise = new Promise ( ( resolve , reject ) = > {
try {
subscriptionId = this . onSignature (
signature ,
2021-03-14 20:01:35 -07:00
( result : SignatureResult , context : Context ) = > {
2020-09-07 22:12:47 -07:00
subscriptionId = undefined ;
response = {
context ,
value : result ,
} ;
2021-03-14 20:01:35 -07:00
resolve ( null ) ;
2020-09-07 22:12:47 -07:00
} ,
subscriptionCommitment ,
) ;
} catch ( err ) {
reject ( err ) ;
}
} ) ;
2021-09-17 09:54:25 -07:00
let timeoutMs = this . _confirmTransactionInitialTimeout || 60 * 1000 ;
2020-09-07 22:12:47 -07:00
switch ( subscriptionCommitment ) {
2021-02-17 16:15:09 -08:00
case 'processed' :
2020-09-07 22:12:47 -07:00
case 'recent' :
case 'single' :
2021-02-17 16:15:09 -08:00
case 'confirmed' :
2020-09-07 22:12:47 -07:00
case 'singleGossip' : {
2021-09-17 09:54:25 -07:00
timeoutMs = this . _confirmTransactionInitialTimeout || 30 * 1000 ;
2020-05-20 02:13:21 -07:00
break ;
}
2020-09-07 22:12:47 -07:00
// exhaust enums to ensure full coverage
2021-02-17 16:15:09 -08:00
case 'finalized' :
2020-09-07 22:12:47 -07:00
case 'max' :
case 'root' :
}
try {
await promiseTimeout ( confirmPromise , timeoutMs ) ;
} finally {
if ( subscriptionId ) {
this . removeSignatureListener ( subscriptionId ) ;
}
}
2020-05-20 02:13:21 -07:00
2020-09-07 22:12:47 -07:00
if ( response === null ) {
const duration = ( Date . now ( ) - start ) / 1000 ;
throw new Error (
2020-11-11 04:12:09 -08:00
` Transaction was not confirmed in ${ duration . toFixed (
2 ,
) } seconds . It is unknown if it succeeded or failed . Check signature $ { signature } using the Solana Explorer or CLI tools . ` ,
2020-09-07 22:12:47 -07:00
) ;
2020-05-20 02:13:21 -07:00
}
2020-09-07 22:12:47 -07:00
return response ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get cluster nodes: ' + res . error . message ) ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get vote accounts: ' + res . error . message ) ;
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
* /
2021-03-14 20:01:35 -07:00
async getSlot ( commitment? : Commitment ) : Promise < number > {
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 ( '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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get slot: ' + res . error . message ) ;
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
* /
2021-03-14 20:01:35 -07:00
async getSlotLeader ( commitment? : Commitment ) : Promise < string > {
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 ( '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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get slot leader: ' + res . error . message ) ;
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 ) {
throw new Error ( 'failed to get slot leaders: ' + res . error . message ) ;
}
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get signature status: ' + res . error . message ) ;
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
* /
2021-03-14 20:01:35 -07:00
async getTransactionCount ( commitment? : Commitment ) : Promise < number > {
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 ( '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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get transaction count: ' + res . error . message ) ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get inflation: ' + res . error . message ) ;
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 ,
commitment? : Commitment ,
) : Promise < ( InflationReward | null ) [ ] > {
const args = this . _buildArgs (
[ addresses . map ( pubkey = > pubkey . toBase58 ( ) ) ] ,
commitment ,
undefined ,
{
epoch ,
} ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getInflationReward' , args ) ;
const res = create ( unsafeRes , GetInflationRewardResult ) ;
if ( 'error' in res ) {
throw new Error ( 'failed to get inflation reward: ' + res . error . message ) ;
}
return res . result ;
}
2019-10-29 09:50:05 -07:00
/ * *
* Fetch the Epoch Info parameters
* /
2021-03-14 20:01:35 -07:00
async getEpochInfo ( commitment? : Commitment ) : Promise < EpochInfo > {
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 ( '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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get epoch info: ' + res . error . message ) ;
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get epoch schedule: ' + res . error . message ) ;
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 ) {
2020-07-17 08:16:44 -07:00
throw new Error ( 'failed to get leader schedule: ' + res . error . message ) ;
}
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get recent blockhash: ' + res . error . message ) ;
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 args = this . _buildArgs ( limit ? [ limit ] : [ ] ) ;
const unsafeRes = await this . _rpcRequest (
'getRecentPerformanceSamples' ,
args ,
) ;
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 ) {
2020-10-08 20:26:58 -07:00
throw new Error (
'failed to get recent performance samples: ' + res . error . message ,
) ;
}
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 ) {
2020-06-04 03:12:59 -07:00
throw new Error ( 'failed to get fee calculator: ' + res . error . message ) ;
}
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 ) {
throw new Error ( 'failed to get slot: ' + res . error . message ) ;
}
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
* @return { Promise < { blockhash : Blockhash , lastValidBlockHeight : number } > }
* /
async getLatestBlockhash (
commitment? : Commitment ,
) : Promise < { blockhash : Blockhash ; lastValidBlockHeight : number } > {
try {
const res = await this . getLatestBlockhashAndContext ( commitment ) ;
return res . value ;
} catch ( e ) {
throw new Error ( 'failed to get recent blockhash: ' + e ) ;
}
}
/ * *
* Fetch the latest blockhash from the cluster
* @return { Promise < { blockhash : Blockhash , lastValidBlockHeight : number } > }
* /
async getLatestBlockhashAndContext (
commitment? : Commitment ,
) : Promise <
RpcResponseAndContext < { blockhash : Blockhash ; lastValidBlockHeight : number } >
> {
const args = this . _buildArgs ( [ ] , commitment ) ;
const unsafeRes = await this . _rpcRequest ( 'getLatestBlockhash' , args ) ;
const res = create ( unsafeRes , GetLatestBlockhashRpcResult ) ;
if ( 'error' in res ) {
throw new Error ( 'failed to get latest blockhash: ' + res . error . message ) ;
}
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error ( 'failed to get version: ' + res . error . message ) ;
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 ) {
throw new Error ( 'failed to get genesis hash: ' + res . error . message ) ;
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 .
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 ,
2021-05-25 10:12:47 -07:00
opts ? : { commitment? : Finality } ,
) : Promise < BlockResponse | null > {
const args = this . _buildArgsAtLeastConfirmed (
[ slot ] ,
opts && opts . commitment ,
) ;
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 ) {
2020-10-28 20:23:07 -07:00
throw new Error ( 'failed to get confirmed block: ' + res . error . message ) ;
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 ,
transactions : result.transactions.map ( ( { transaction , meta } ) = > {
const message = new Message ( transaction . message ) ;
return {
meta ,
transaction : {
. . . transaction ,
message ,
} ,
} ;
} ) ,
} ;
}
2022-02-22 18:49:27 -08:00
/ *
* Returns the current block height of the node
* /
async getBlockHeight ( commitment? : Commitment ) : Promise < number > {
const args = this . _buildArgs ( [ ] , commitment ) ;
const unsafeRes = await this . _rpcRequest ( 'getBlockHeight' , args ) ;
const res = create ( unsafeRes , jsonRpcResult ( number ( ) ) ) ;
if ( 'error' in res ) {
throw new Error (
'failed to get block height information: ' + res . error . message ,
) ;
}
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 ) {
throw new Error (
'failed to get block production information: ' + res . error . message ,
) ;
}
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 .
2021-05-25 10:12:47 -07:00
* /
async getTransaction (
signature : string ,
opts ? : { commitment? : Finality } ,
) : Promise < TransactionResponse | null > {
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
opts && opts . commitment ,
) ;
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-01-27 15:43:01 -08:00
throw new Error ( 'failed to get transaction: ' + res . error . message ) ;
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 ,
message : new Message ( result . transaction . message ) ,
} ,
} ;
}
2022-01-27 15:43:01 -08:00
/ * *
* Fetch parsed transaction details for a confirmed or finalized transaction
* /
async getParsedTransaction (
signature : TransactionSignature ,
commitment? : Finality ,
) : Promise < ParsedConfirmedTransaction | null > {
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
commitment ,
'jsonParsed' ,
) ;
const unsafeRes = await this . _rpcRequest ( 'getTransaction' , args ) ;
const res = create ( unsafeRes , GetParsedTransactionRpcResult ) ;
if ( 'error' in res ) {
throw new Error ( 'failed to get transaction: ' + res . error . message ) ;
}
return res . result ;
}
/ * *
* Fetch parsed transaction details for a batch of confirmed transactions
* /
async getParsedTransactions (
signatures : TransactionSignature [ ] ,
commitment? : Finality ,
) : Promise < ( ParsedConfirmedTransaction | null ) [ ] > {
const batch = signatures . map ( signature = > {
const args = this . _buildArgsAtLeastConfirmed (
[ signature ] ,
commitment ,
'jsonParsed' ,
) ;
return {
methodName : 'getTransaction' ,
args ,
} ;
} ) ;
const unsafeRes = await this . _rpcBatchRequest ( batch ) ;
const res = unsafeRes . map ( ( unsafeRes : any ) = > {
const res = create ( unsafeRes , GetParsedTransactionRpcResult ) ;
if ( 'error' in res ) {
throw new Error ( 'failed to get transactions: ' + res . error . message ) ;
}
return res . result ;
} ) ;
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 ) {
throw new Error ( 'failed to get confirmed block: ' + res . error . message ) ;
}
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 ) {
throw new Error ( 'failed to get blocks: ' + res . error . message ) ;
}
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 ) {
throw new Error ( 'failed to get block: ' + res . error . message ) ;
}
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 ) {
throw new Error ( 'failed to get confirmed block: ' + res . error . message ) ;
}
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 ) {
throw new Error ( 'failed to get transaction: ' + res . error . message ) ;
}
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 ) {
2021-02-25 23:06:12 -08:00
throw new Error (
'failed to get confirmed transaction: ' + res . error . message ,
) ;
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 ) {
throw new Error (
'failed to get confirmed transactions: ' + res . error . message ,
) ;
}
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 ) {
2020-07-29 22:40:46 -07:00
throw new Error (
2021-02-25 23:06:12 -08:00
'failed to get confirmed signatures for address: ' + res . error . message ,
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 ) {
throw new Error (
'failed to get signatures for address: ' + res . error . message ,
) ;
}
return res . result ;
}
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 ) {
2020-04-08 16:49:51 -07:00
throw new Error (
'airdrop to ' + to . toBase58 ( ) + ' failed: ' + res . error . message ,
) ;
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
* /
2020-08-10 23:35:56 -07:00
async _recentBlockhash ( disableCache : boolean ) : Promise < Blockhash > {
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 ;
2020-08-10 23:35:56 -07:00
if ( this . _blockhashInfo . recentBlockhash !== null && ! expired ) {
return this . _blockhashInfo . recentBlockhash ;
}
}
return await this . _pollNewBlockhash ( ) ;
}
2021-03-14 20:01:35 -07:00
/ * *
* @internal
* /
2020-08-10 23:35:56 -07:00
async _pollNewBlockhash ( ) : Promise < Blockhash > {
2020-08-25 21:59:56 -07:00
this . _pollingBlockhash = true ;
try {
const startTime = Date . now ( ) ;
for ( let i = 0 ; i < 50 ; i ++ ) {
2021-02-17 16:15:09 -08:00
const { blockhash } = await this . getRecentBlockhash ( 'finalized' ) ;
2020-08-25 21:59:56 -07:00
if ( this . _blockhashInfo . recentBlockhash != blockhash ) {
this . _blockhashInfo = {
recentBlockhash : blockhash ,
2021-03-14 20:01:35 -07:00
lastFetch : Date.now ( ) ,
2020-08-25 21:59:56 -07:00
transactionSignatures : [ ] ,
simulatedSignatures : [ ] ,
} ;
return blockhash ;
}
// 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
}
}
/ * *
* Simulate a transaction
* /
async 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 > ,
2020-08-10 23:35:56 -07:00
) : Promise < RpcResponseAndContext < SimulatedTransactionResponse > > {
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 ;
transaction = new Transaction ( {
recentBlockhash : originalTx.recentBlockhash ,
nonceInfo : originalTx.nonceInfo ,
feePayer : originalTx.feePayer ,
signatures : [ . . . originalTx . signatures ] ,
} ) ;
transaction . instructions = transactionOrMessage . instructions ;
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
}
2020-08-10 23:35:56 -07:00
if ( transaction . nonceInfo && signers ) {
transaction . sign ( . . . signers ) ;
} else {
let disableCache = this . _disableBlockhashCaching ;
for ( ; ; ) {
2022-04-12 21:54:46 -07:00
transaction . recentBlockhash = await this . _recentBlockhash ( disableCache ) ;
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
2018-08-24 09:05:23 -07:00
* /
2018-11-04 11:41:21 -08:00
async sendTransaction (
transaction : Transaction ,
2021-05-07 01:59:51 -07:00
signers : Array < Signer > ,
2020-06-03 04:55:42 -07:00
options? : SendOptions ,
2018-11-04 11:41:21 -08:00
) : Promise < TransactionSignature > {
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 ( ; ; ) {
2020-08-10 23:35:56 -07:00
transaction . recentBlockhash = await this . _recentBlockhash ( disableCache ) ;
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-02-03 10:54:43 -08:00
if ( options && options . maxRetries ) {
config . maxRetries = options . maxRetries ;
}
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 ) {
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 ) {
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
2020-04-09 04:34:33 -07:00
this . _resetSubscriptions ( ) ;
2018-10-26 21:37:39 -07:00
}
2020-02-10 06:45:52 -08:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-02-10 06:45:52 -08:00
* /
2021-03-14 20:01:35 -07:00
async _subscribe (
sub : { subscriptionId : SubscriptionId | null } ,
2020-02-10 06:45:52 -08:00
rpcMethod : string ,
2021-03-14 20:01:35 -07:00
rpcArgs : IWSRequestParams ,
2020-02-10 06:45:52 -08:00
) {
if ( sub . subscriptionId == null ) {
sub . subscriptionId = 'subscribing' ;
try {
const id = await this . _rpcWebSocket . call ( rpcMethod , rpcArgs ) ;
2021-03-14 20:01:35 -07:00
if ( typeof id === 'number' && sub . subscriptionId === 'subscribing' ) {
2020-02-10 06:45:52 -08:00
// eslint-disable-next-line require-atomic-updates
sub . subscriptionId = id ;
}
} catch ( err ) {
if ( sub . subscriptionId === 'subscribing' ) {
// eslint-disable-next-line require-atomic-updates
sub . subscriptionId = null ;
}
2021-09-25 12:25:14 -07:00
if ( err instanceof Error ) {
console . error (
` ${ rpcMethod } error for argument ` ,
rpcArgs ,
err . message ,
) ;
}
2020-02-10 06:45:52 -08:00
}
}
}
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-02-10 06:45:52 -08:00
* /
2021-03-14 20:01:35 -07:00
async _unsubscribe (
sub : { subscriptionId : SubscriptionId | null } ,
2020-02-10 06:45:52 -08:00
rpcMethod : string ,
) {
const subscriptionId = sub . subscriptionId ;
if ( subscriptionId != null && typeof subscriptionId != 'string' ) {
const unsubscribeId : number = subscriptionId ;
try {
await this . _rpcWebSocket . call ( rpcMethod , [ unsubscribeId ] ) ;
} catch ( err ) {
2021-09-25 12:25:14 -07:00
if ( err instanceof Error ) {
console . error ( ` ${ rpcMethod } error: ` , err . message ) ;
}
2020-02-10 06:45:52 -08:00
}
}
}
2020-04-09 04:34:33 -07:00
/ * *
2021-03-14 20:01:35 -07:00
* @internal
2020-04-09 04:34:33 -07:00
* /
_resetSubscriptions() {
2021-03-14 20:01:35 -07:00
Object . values ( this . _accountChangeSubscriptions ) . forEach (
2020-04-09 04:34:33 -07:00
s = > ( s . subscriptionId = null ) ,
) ;
2022-04-07 15:42:58 -07:00
Object . values ( this . _logsSubscriptions ) . forEach (
s = > ( s . subscriptionId = null ) ,
) ;
2021-03-14 20:01:35 -07:00
Object . values ( this . _programAccountChangeSubscriptions ) . forEach (
2020-04-09 04:34:33 -07:00
s = > ( s . subscriptionId = null ) ,
) ;
2021-05-02 05:14:30 -07:00
Object . values ( this . _rootSubscriptions ) . forEach (
s = > ( s . subscriptionId = null ) ,
) ;
2021-03-14 20:01:35 -07:00
Object . values ( this . _signatureSubscriptions ) . forEach (
2020-04-09 04:34:33 -07:00
s = > ( s . subscriptionId = null ) ,
) ;
2021-03-14 20:01:35 -07:00
Object . values ( this . _slotSubscriptions ) . forEach (
2020-04-09 04:34:33 -07:00
s = > ( s . subscriptionId = null ) ,
) ;
2021-05-02 05:14:30 -07:00
Object . values ( this . _slotUpdateSubscriptions ) . forEach (
2020-04-09 04:34:33 -07:00
s = > ( s . subscriptionId = null ) ,
) ;
}
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-02-11 06:33:50 -08:00
_updateSubscriptions() {
2019-03-08 16:02:39 -08:00
const accountKeys = Object . keys ( this . _accountChangeSubscriptions ) . map (
Number ,
) ;
const programKeys = Object . keys (
this . _programAccountChangeSubscriptions ,
) . map ( Number ) ;
2019-11-25 08:04:35 -08:00
const slotKeys = Object . keys ( this . _slotSubscriptions ) . map ( Number ) ;
2021-05-02 05:14:30 -07:00
const slotUpdateKeys = Object . keys ( this . _slotUpdateSubscriptions ) . map (
Number ,
) ;
2020-02-03 07:22:11 -08:00
const signatureKeys = Object . keys ( this . _signatureSubscriptions ) . map ( Number ) ;
2020-03-27 07:22:53 -07:00
const rootKeys = Object . keys ( this . _rootSubscriptions ) . map ( Number ) ;
2021-03-23 20:05:17 -07:00
const logsKeys = Object . keys ( this . _logsSubscriptions ) . map ( Number ) ;
2019-11-25 08:04:35 -08:00
if (
accountKeys . length === 0 &&
programKeys . length === 0 &&
2020-02-03 07:22:11 -08:00
slotKeys . length === 0 &&
2021-05-02 05:14:30 -07:00
slotUpdateKeys . length === 0 &&
2020-03-27 07:22:53 -07:00
signatureKeys . length === 0 &&
2021-03-23 20:05:17 -07:00
rootKeys . length === 0 &&
logsKeys . length === 0
2019-11-25 08:04:35 -08:00
) {
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 ;
}
2019-03-08 16:02:39 -08:00
for ( let id of accountKeys ) {
2020-02-11 06:33:50 -08:00
const sub = this . _accountChangeSubscriptions [ id ] ;
2020-05-20 21:17:38 -07:00
this . _subscribe (
sub ,
'accountSubscribe' ,
2020-08-15 21:57:23 -07:00
this . _buildArgs ( [ sub . publicKey ] , sub . commitment , 'base64' ) ,
2020-05-20 21:17:38 -07:00
) ;
2018-10-26 21:37:39 -07:00
}
2020-02-10 06:45:52 -08:00
2019-03-08 16:02:39 -08:00
for ( let id of programKeys ) {
2020-02-10 06:45:52 -08:00
const sub = this . _programAccountChangeSubscriptions [ id ] ;
2020-05-20 21:17:38 -07:00
this . _subscribe (
sub ,
'programSubscribe' ,
2021-06-28 07:21:47 -07:00
this . _buildArgs ( [ sub . programId ] , sub . commitment , 'base64' , {
filters : sub.filters ,
} ) ,
2020-05-20 21:17:38 -07:00
) ;
2019-03-08 16:02:39 -08:00
}
2020-02-10 06:45:52 -08:00
2019-11-25 08:04:35 -08:00
for ( let id of slotKeys ) {
2020-02-10 06:45:52 -08:00
const sub = this . _slotSubscriptions [ id ] ;
2020-02-11 06:33:50 -08:00
this . _subscribe ( sub , 'slotSubscribe' , [ ] ) ;
2019-11-25 08:04:35 -08:00
}
2020-02-10 06:45:52 -08:00
2021-05-02 05:14:30 -07:00
for ( let id of slotUpdateKeys ) {
const sub = this . _slotUpdateSubscriptions [ id ] ;
this . _subscribe ( sub , 'slotsUpdatesSubscribe' , [ ] ) ;
}
2020-02-03 07:22:11 -08:00
for ( let id of signatureKeys ) {
2020-02-10 06:45:52 -08:00
const sub = this . _signatureSubscriptions [ id ] ;
2021-03-18 18:30:36 -07:00
const args : any [ ] = [ sub . signature ] ;
if ( sub . options ) args . push ( sub . options ) ;
this . _subscribe ( sub , 'signatureSubscribe' , args ) ;
2020-02-03 07:22:11 -08:00
}
2020-03-27 07:22:53 -07:00
for ( let id of rootKeys ) {
const sub = this . _rootSubscriptions [ id ] ;
this . _subscribe ( sub , 'rootSubscribe' , [ ] ) ;
}
2021-03-23 20:05:17 -07:00
for ( let id of logsKeys ) {
const sub = this . _logsSubscriptions [ id ] ;
let filter ;
if ( typeof sub . filter === 'object' ) {
filter = { mentions : [ sub . filter . toString ( ) ] } ;
} else {
filter = sub . filter ;
}
this . _subscribe (
sub ,
'logsSubscribe' ,
this . _buildArgs ( [ filter ] , sub . commitment ) ,
) ;
}
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 ) {
2021-02-25 23:06:12 -08:00
const res = create ( notification , AccountNotificationResult ) ;
2021-03-14 20:01:35 -07:00
for ( const sub of Object . values ( this . _accountChangeSubscriptions ) ) {
2019-03-08 16:02:39 -08:00
if ( sub . subscriptionId === res . subscription ) {
2021-02-25 23:06:12 -08:00
sub . callback ( res . result . value , res . result . context ) ;
2021-03-14 20:01:35 -07:00
return ;
2019-03-08 16:02:39 -08:00
}
}
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 ,
2018-11-04 11:41:21 -08:00
) : number {
2018-10-26 21:37:39 -07:00
const id = ++ this . _accountChangeSubscriptionCounter ;
this . _accountChangeSubscriptions [ id ] = {
publicKey : publicKey.toBase58 ( ) ,
callback ,
2020-05-20 21:17:38 -07:00
commitment ,
2018-11-04 11:41:21 -08:00
subscriptionId : null ,
2018-10-26 21:37:39 -07:00
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister an account notification callback
*
* @param id subscription id to deregister
* /
async removeAccountChangeListener ( id : number ) : Promise < void > {
if ( this . _accountChangeSubscriptions [ id ] ) {
2020-02-10 06:45:52 -08:00
const subInfo = this . _accountChangeSubscriptions [ id ] ;
2018-10-26 21:37:39 -07:00
delete this . _accountChangeSubscriptions [ id ] ;
2020-02-10 06:45:52 -08:00
await this . _unsubscribe ( subInfo , 'accountUnsubscribe' ) ;
2018-10-26 21:37:39 -07:00
this . _updateSubscriptions ( ) ;
} else {
throw new Error ( ` Unknown account change id: ${ id } ` ) ;
}
}
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 ) {
2021-02-25 23:06:12 -08:00
const res = create ( notification , ProgramAccountNotificationResult ) ;
2021-03-14 20:01:35 -07:00
for ( const sub of Object . values ( this . _programAccountChangeSubscriptions ) ) {
2019-03-08 16:02:39 -08:00
if ( sub . subscriptionId === res . subscription ) {
2021-02-25 23:06:12 -08:00
const { value , context } = res . result ;
2020-03-23 07:19:32 -07:00
sub . callback (
{
accountId : value.pubkey ,
2021-02-25 23:06:12 -08:00
accountInfo : value.account ,
2019-03-08 16:02:39 -08:00
} ,
2020-03-23 07:19:32 -07:00
context ,
) ;
2021-03-14 20:01:35 -07:00
return ;
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 [ ] ,
2019-03-08 16:02:39 -08:00
) : number {
const id = ++ this . _programAccountChangeSubscriptionCounter ;
this . _programAccountChangeSubscriptions [ id ] = {
programId : programId.toBase58 ( ) ,
callback ,
2020-05-20 21:17:38 -07:00
commitment ,
2019-03-08 16:02:39 -08:00
subscriptionId : null ,
2021-06-28 07:21:47 -07:00
filters ,
2019-03-08 16:02:39 -08:00
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister an account notification callback
*
* @param id subscription id to deregister
* /
async removeProgramAccountChangeListener ( id : number ) : Promise < void > {
if ( this . _programAccountChangeSubscriptions [ id ] ) {
2020-02-10 06:45:52 -08:00
const subInfo = this . _programAccountChangeSubscriptions [ id ] ;
2019-03-08 16:02:39 -08:00
delete this . _programAccountChangeSubscriptions [ id ] ;
2020-02-10 06:45:52 -08:00
await this . _unsubscribe ( subInfo , 'programUnsubscribe' ) ;
2019-03-08 16:02:39 -08:00
this . _updateSubscriptions ( ) ;
} else {
2020-02-10 06:45:52 -08:00
throw new Error ( ` Unknown program account change id: ${ id } ` ) ;
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 ,
) : number {
const id = ++ this . _logsSubscriptionCounter ;
this . _logsSubscriptions [ id ] = {
filter ,
callback ,
commitment ,
subscriptionId : null ,
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister a logs callback .
*
* @param id subscription id to deregister .
* /
async removeOnLogsListener ( id : number ) : Promise < void > {
if ( ! this . _logsSubscriptions [ id ] ) {
throw new Error ( ` Unknown logs id: ${ id } ` ) ;
}
const subInfo = this . _logsSubscriptions [ id ] ;
delete this . _logsSubscriptions [ id ] ;
await this . _unsubscribe ( subInfo , 'logsUnsubscribe' ) ;
this . _updateSubscriptions ( ) ;
}
/ * *
* @internal
* /
_wsOnLogsNotification ( notification : Object ) {
const res = create ( notification , LogsNotificationResult ) ;
const keys = Object . keys ( this . _logsSubscriptions ) . map ( Number ) ;
for ( let id of keys ) {
const sub = this . _logsSubscriptions [ id ] ;
if ( sub . subscriptionId === res . subscription ) {
sub . callback ( res . result . value , res . result . context ) ;
return ;
}
}
}
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 ) {
2021-02-25 23:06:12 -08:00
const res = create ( notification , SlotNotificationResult ) ;
2021-03-14 20:01:35 -07:00
for ( const sub of Object . values ( this . _slotSubscriptions ) ) {
2019-11-25 08:04:35 -08:00
if ( sub . subscriptionId === res . subscription ) {
2021-02-25 23:06:12 -08:00
sub . callback ( res . result ) ;
2021-03-14 20:01:35 -07:00
return ;
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
* /
onSlotChange ( callback : SlotChangeCallback ) : number {
const id = ++ this . _slotSubscriptionCounter ;
this . _slotSubscriptions [ id ] = {
callback ,
2020-02-03 08:18:55 -08:00
subscriptionId : null ,
2019-11-25 08:04:35 -08:00
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister a slot notification callback
*
* @param id subscription id to deregister
* /
async removeSlotChangeListener ( id : number ) : Promise < void > {
if ( this . _slotSubscriptions [ id ] ) {
2020-02-10 06:45:52 -08:00
const subInfo = this . _slotSubscriptions [ id ] ;
2019-11-25 08:04:35 -08:00
delete this . _slotSubscriptions [ id ] ;
2020-02-10 06:45:52 -08:00
await this . _unsubscribe ( subInfo , 'slotUnsubscribe' ) ;
2019-11-25 08:04:35 -08:00
this . _updateSubscriptions ( ) ;
} else {
throw new Error ( ` Unknown slot change id: ${ id } ` ) ;
}
}
2021-03-14 20:01:35 -07:00
/ * *
* @internal
* /
2021-05-02 05:14:30 -07:00
_wsOnSlotUpdatesNotification ( notification : Object ) {
const res = create ( notification , SlotUpdateNotificationResult ) ;
for ( const sub of Object . values ( this . _slotUpdateSubscriptions ) ) {
if ( sub . subscriptionId === res . subscription ) {
sub . callback ( res . result ) ;
return ;
}
}
}
/ * *
* Register a callback to be invoked upon slot updates . { @link SlotUpdate } ' s
* may be useful to track live progress of a cluster .
*
* @param callback Function to invoke whenever the slot updates
* @return subscription id
* /
onSlotUpdate ( callback : SlotUpdateCallback ) : number {
const id = ++ this . _slotUpdateSubscriptionCounter ;
this . _slotUpdateSubscriptions [ id ] = {
callback ,
subscriptionId : null ,
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister a slot update notification callback
*
* @param id subscription id to deregister
* /
async removeSlotUpdateListener ( id : number ) : Promise < void > {
if ( this . _slotUpdateSubscriptions [ id ] ) {
const subInfo = this . _slotUpdateSubscriptions [ id ] ;
delete this . _slotUpdateSubscriptions [ id ] ;
await this . _unsubscribe ( subInfo , 'slotsUpdatesUnsubscribe' ) ;
this . _updateSubscriptions ( ) ;
} else {
throw new Error ( ` Unknown slot update id: ${ id } ` ) ;
}
}
2020-08-10 01:26:48 -07:00
_buildArgs (
2020-08-06 08:47:22 -07:00
args : Array < any > ,
2021-03-14 20:01:35 -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 > {
2019-11-11 10:01:10 -08: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 ) {
2021-02-25 23:06:12 -08:00
const res = create ( notification , SignatureNotificationResult ) ;
2021-03-14 20:01:35 -07:00
for ( const [ id , sub ] of Object . entries ( this . _signatureSubscriptions ) ) {
2020-02-03 07:22:11 -08:00
if ( sub . subscriptionId === res . subscription ) {
2021-03-18 18:30:36 -07:00
if ( res . result . value === 'receivedSignature' ) {
sub . callback (
{
type : 'received' ,
} ,
res . result . context ,
) ;
} else {
// Signatures subscriptions are auto-removed by the RPC service so
// no need to explicitly send an unsubscribe message
delete this . _signatureSubscriptions [ Number ( id ) ] ;
this . _updateSubscriptions ( ) ;
sub . callback (
{
type : 'status' ,
result : res.result.value ,
} ,
res . result . context ,
) ;
}
2020-02-03 07:22:11 -08:00
return ;
}
}
}
/ * *
* 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 ,
2021-03-18 18:30:36 -07:00
) : number {
const id = ++ this . _signatureSubscriptionCounter ;
this . _signatureSubscriptions [ id ] = {
signature ,
callback : ( notification , context ) = > {
if ( notification . type === 'status' ) {
callback ( notification . result , context ) ;
}
} ,
options : { commitment } ,
subscriptionId : null ,
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* 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 ,
2020-02-03 07:22:11 -08:00
) : number {
const id = ++ this . _signatureSubscriptionCounter ;
this . _signatureSubscriptions [ id ] = {
signature ,
callback ,
2021-03-18 18:30:36 -07:00
options ,
2020-02-03 07:22:11 -08:00
subscriptionId : null ,
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister a signature notification callback
*
* @param id subscription id to deregister
* /
async removeSignatureListener ( id : number ) : Promise < void > {
if ( this . _signatureSubscriptions [ id ] ) {
2020-02-10 06:45:52 -08:00
const subInfo = this . _signatureSubscriptions [ id ] ;
2020-02-03 07:22:11 -08:00
delete this . _signatureSubscriptions [ id ] ;
2020-02-10 06:45:52 -08:00
await this . _unsubscribe ( subInfo , 'signatureUnsubscribe' ) ;
2020-02-03 07:22:11 -08:00
this . _updateSubscriptions ( ) ;
} else {
2020-02-10 06:45:52 -08:00
throw new Error ( ` Unknown signature result id: ${ id } ` ) ;
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 ) {
2021-02-25 23:06:12 -08:00
const res = create ( notification , RootNotificationResult ) ;
2021-03-14 20:01:35 -07:00
for ( const sub of Object . values ( this . _rootSubscriptions ) ) {
2020-03-27 07:22:53 -07:00
if ( sub . subscriptionId === res . subscription ) {
2021-02-25 23:06:12 -08:00
sub . callback ( res . result ) ;
2021-03-14 20:01:35 -07:00
return ;
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
* /
onRootChange ( callback : RootChangeCallback ) : number {
const id = ++ this . _rootSubscriptionCounter ;
this . _rootSubscriptions [ id ] = {
callback ,
subscriptionId : null ,
} ;
this . _updateSubscriptions ( ) ;
return id ;
}
/ * *
* Deregister a root notification callback
*
* @param id subscription id to deregister
* /
async removeRootChangeListener ( id : number ) : Promise < void > {
if ( this . _rootSubscriptions [ id ] ) {
const subInfo = this . _rootSubscriptions [ id ] ;
delete this . _rootSubscriptions [ id ] ;
await this . _unsubscribe ( subInfo , 'rootUnsubscribe' ) ;
this . _updateSubscriptions ( ) ;
} else {
throw new Error ( ` Unknown root change id: ${ id } ` ) ;
}
}
2018-08-23 10:52:48 -07:00
}