@exodus/solana-api 2.0.14 → 2.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-api",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
4
4
  "description": "Exodus internal Solana asset API wrapper",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -14,15 +14,13 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@exodus/asset-json-rpc": "^1.0.0",
17
- "@exodus/asset-lib": "^3.6.2",
17
+ "@exodus/asset-lib": "^3.6.0",
18
18
  "@exodus/assets": "^8.0.71",
19
19
  "@exodus/assets-base": "^8.0.150",
20
- "@exodus/fetch": "^1.2.0",
21
20
  "@exodus/models": "^8.7.2",
22
21
  "@exodus/nfts-core": "^0.5.0",
23
- "@exodus/solana-lib": "^1.3.15",
22
+ "@exodus/solana-lib": "^1.3.14",
24
23
  "bn.js": "^4.11.0",
25
- "debug": "^4.1.1",
26
24
  "lodash": "^4.17.11",
27
25
  "url-join": "4.0.0",
28
26
  "wretch": "^1.5.2"
@@ -30,5 +28,5 @@
30
28
  "devDependencies": {
31
29
  "node-fetch": "~2.6.0"
32
30
  },
33
- "gitHead": "16410d60f413eda6aeb3372c23875b98c20de06c"
31
+ "gitHead": "9ec7084bcdfe14f1c6f11df393351885773046a6"
34
32
  }
package/src/api.js CHANGED
@@ -20,21 +20,17 @@ import lodash from 'lodash'
20
20
  import urljoin from 'url-join'
21
21
  import wretch, { Wretcher } from 'wretch'
22
22
  import { magicEden } from '@exodus/nfts-core'
23
- import { Connection } from './connection'
24
23
 
25
24
  // Doc: https://docs.solana.com/apps/jsonrpc-api
26
25
 
27
26
  const RPC_URL = 'https://solana.a.exodus.io' // https://vip-api.mainnet-beta.solana.com/, https://api.mainnet-beta.solana.com, https://solana-api.projectserum.com
28
- const WS_ENDPOINT = 'wss://solana.a.exodus.io/ws'
29
27
 
30
28
  // Tokens + SOL api support
31
29
  export class Api {
32
- constructor(rpcUrl, wsUrl) {
30
+ constructor(rpcUrl) {
33
31
  this.setServer(rpcUrl)
34
- this.setWsEndpoint(wsUrl)
35
32
  this.setTokens(assets)
36
33
  this.tokensToSkip = {}
37
- this.connections = {}
38
34
  }
39
35
 
40
36
  setServer(rpcUrl) {
@@ -42,10 +38,6 @@ export class Api {
42
38
  this.api = createApi(this.rpcUrl)
43
39
  }
44
40
 
45
- setWsEndpoint(wsUrl) {
46
- this.wsUrl = wsUrl || WS_ENDPOINT
47
- }
48
-
49
41
  setTokens(assets = {}) {
50
42
  const solTokens = lodash.pickBy(assets, (asset) => asset.assetType === 'SOLANA_TOKEN')
51
43
  this.tokens = lodash.mapKeys(solTokens, (v) => v.mintAddress)
@@ -57,103 +49,76 @@ export class Api {
57
49
  })
58
50
  }
59
51
 
60
- async watchAddress({
61
- address,
62
- tokensAddresses = [],
63
- handleAccounts,
64
- handleTransfers,
65
- handleReconnect,
66
- reconnectDelay,
67
- }) {
68
- const conn = new Connection({
69
- endpoint: this.wsUrl,
70
- address,
71
- tokensAddresses,
72
- callback: (updates) =>
73
- this.handleUpdates({ updates, address, handleAccounts, handleTransfers }),
74
- reconnectCallback: handleReconnect,
75
- reconnectDelay,
76
- })
77
-
78
- this.connections[address] = conn
79
- return conn.start()
80
- }
81
-
82
- async unwatchAddress({ address }) {
83
- if (this.connections[address]) {
84
- await this.connections[address].stop()
85
- delete this.connections[address]
86
- }
87
- }
88
-
89
- async handleUpdates({ updates, address, handleAccounts, handleTransfers }) {
90
- // console.log(`got ws updates from ${address}:`, updates)
91
- if (handleTransfers) return handleTransfers(updates)
92
- }
93
-
94
- async rpcCall(method, params = [], { address = '', forceHttp = false } = {}) {
95
- // ws request
96
- const connection = this.connections[address] || lodash.sample(Object.values(this.connections)) // pick random connection
97
- if (lodash.get(connection, 'isOpen') && !lodash.get(connection, 'shutdown') && !forceHttp) {
98
- return connection.sendMessage(method, params)
99
- }
100
- // http fallback
101
- return this.api.post({ method, params })
102
- }
103
-
104
52
  isTokenSupported(mint: string) {
105
53
  return !!this.tokens[mint]
106
54
  }
107
55
 
108
56
  async getEpochInfo(): number {
109
- const { epoch } = await this.rpcCall('getEpochInfo')
57
+ const { epoch } = await this.api.post({
58
+ method: 'getEpochInfo',
59
+ })
110
60
  return Number(epoch)
111
61
  }
112
62
 
113
63
  async getStakeActivation(address): string {
114
- const { state } = await this.rpcCall('getStakeActivation', [address])
64
+ const { state } = await this.api.post({
65
+ method: 'getStakeActivation',
66
+ params: [address],
67
+ })
115
68
  return state
116
69
  }
117
70
 
118
71
  async getRecentBlockHash(): string {
119
- const result = await this.rpcCall(
120
- 'getRecentBlockhash',
121
- [{ commitment: 'finalized', encoding: 'jsonParsed' }],
122
- { forceHttp: true }
123
- )
124
- return lodash.get(result, 'value.blockhash')
72
+ const {
73
+ value: { blockhash },
74
+ } = await this.api.post({
75
+ method: 'getRecentBlockhash',
76
+ })
77
+ return blockhash
125
78
  }
126
79
 
127
80
  // Transaction structure: https://docs.solana.com/apps/jsonrpc-api#transaction-structure
128
81
  async getTransactionById(id: string) {
129
- return this.rpcCall('getTransaction', [
130
- id,
131
- { encoding: 'jsonParsed', maxSupportedTransactionVersion: 0 },
132
- ])
82
+ const result = await this.api.post({
83
+ method: 'getTransaction',
84
+ params: [id, { encoding: 'jsonParsed', maxSupportedTransactionVersion: 0 }],
85
+ })
86
+ return result
133
87
  }
134
88
 
135
89
  async getFee(): number {
136
- const result = await this.rpcCall('getRecentBlockhash', [
137
- { commitment: 'finalized', encoding: 'jsonParsed' },
138
- ])
139
- return lodash.get(result, 'value.feeCalculator.lamportsPerSignature')
90
+ const {
91
+ value: {
92
+ feeCalculator: { lamportsPerSignature },
93
+ },
94
+ } = await this.api.post({
95
+ method: 'getRecentBlockhash',
96
+ })
97
+ return lamportsPerSignature
140
98
  }
141
99
 
142
100
  async getBalance(address: string): number {
143
- const result = await this.rpcCall('getBalance', [address, { encoding: 'jsonParsed' }], {
144
- address,
101
+ const res = await this.api.post({
102
+ method: 'getBalance',
103
+ params: [address],
145
104
  })
146
- return lodash.get(result, 'value', 0)
105
+ return res.value || 0
147
106
  }
148
107
 
149
108
  async getBlockTime(slot: number) {
150
109
  // might result in error if executed on a validator with partial ledger (https://github.com/solana-labs/solana/issues/12413)
151
- return this.rpcCall('getBlockTime', [slot])
110
+ return this.api.post({
111
+ method: 'getBlockTime',
112
+ params: [slot],
113
+ })
152
114
  }
153
115
 
154
116
  async getConfirmedSignaturesForAddress(address: string, { until, before, limit } = {}): any {
155
117
  until = until || undefined
156
- return this.rpcCall('getSignaturesForAddress', [address, { until, before, limit }], { address })
118
+ return this.api.post({
119
+ method: 'getSignaturesForAddress',
120
+ params: [address, { until, before, limit }],
121
+ })
157
122
  }
158
123
 
159
124
  /**
@@ -560,8 +525,13 @@ export class Api {
560
525
  }
561
526
 
562
527
  async getSupply(mintAddress: string): string {
563
- const result = await this.rpcCall('getTokenSupply', [mintAddress])
564
- return lodash.get(result, 'value.amount')
528
+ const {
529
+ value: { amount },
530
+ } = await this.api.post({
531
+ method: 'getTokenSupply',
532
+ params: [mintAddress],
533
+ })
534
+ return amount
565
535
  }
566
536
 
567
537
  async getWalletTokensList({ tokenAccounts }) {
@@ -587,11 +557,10 @@ export class Api {
587
557
  }
588
558
 
589
559
  async getTokenAccountsByOwner(address: string, tokenTicker: ?string): Array {
590
- const { value: accountsList } = await this.rpcCall(
591
- 'getTokenAccountsByOwner',
592
- [address, { programId: TOKEN_PROGRAM_ID.toBase58() }, { encoding: 'jsonParsed' }],
593
- { address }
594
- )
560
+ const { value: accountsList } = await this.api.post({
561
+ method: 'getTokenAccountsByOwner',
562
+ params: [address, { programId: TOKEN_PROGRAM_ID.toBase58() }, { encoding: 'jsonParsed' }],
563
+ })
595
564
 
596
565
  const tokenAccounts = []
597
566
  for (let entry of accountsList) {
@@ -636,7 +605,10 @@ export class Api {
636
605
  async isAssociatedTokenAccountActive(tokenAddress: string) {
637
606
  // Returns the token balance of an SPL Token account.
638
607
  try {
639
- await this.rpcCall('getTokenAccountBalance', [tokenAddress])
608
+ await this.api.post({
609
+ method: 'getTokenAccountBalance',
610
+ params: [tokenAddress],
611
+ })
640
612
  return true
641
613
  } catch (e) {
642
614
  return false
@@ -645,16 +617,21 @@ export class Api {
645
617
 
646
618
  // Returns account balance of a SPL Token account.
647
619
  async getTokenBalance(tokenAddress: string) {
648
- const result = await this.rpcCall('getTokenAccountBalance', [tokenAddress])
649
- return lodash.get(result, 'value.amount')
620
+ const {
621
+ value: { amount },
622
+ } = await this.api.post({
623
+ method: 'getTokenAccountBalance',
624
+ params: [tokenAddress],
625
+ })
626
+
627
+ return amount
650
628
  }
651
629
 
652
630
  async getAccountInfo(address: string) {
653
- const { value } = await this.rpcCall(
654
- 'getAccountInfo',
655
- [address, { encoding: 'jsonParsed', commitment: 'single' }],
656
- { address }
657
- )
631
+ const { value } = await this.api.post({
632
+ method: 'getAccountInfo',
633
+ params: [address, { encoding: 'jsonParsed', commitment: 'single' }],
634
+ })
658
635
  return value
659
636
  }
660
637
 
@@ -673,8 +650,8 @@ export class Api {
673
650
  }
674
651
 
675
652
  async getDecimals(tokenMintAddress: string) {
676
- const result = await this.rpcCall('getTokenSupply', [tokenMintAddress])
677
- return lodash.get(result, 'value.decimals', null)
653
+ const res = await this.api.post({ method: 'getTokenSupply', params: [tokenMintAddress] })
654
+ return lodash.get(res, 'value.decimals', null)
678
655
  }
679
656
 
680
657
  async getAddressType(address: string) {
@@ -718,22 +695,24 @@ export class Api {
718
695
  }
719
696
 
720
697
  async getStakeAccountsInfo(address: string) {
721
- const params = [
722
- STAKE_PROGRAM_ID.toBase58(),
723
- {
724
- filters: [
725
- {
726
- memcmp: {
727
- offset: 12,
728
- bytes: address,
698
+ // get staked amount and other info
699
+ const res = await this.api.post({
700
+ method: 'getProgramAccounts',
701
+ params: [
702
+ STAKE_PROGRAM_ID.toBase58(),
703
+ {
704
+ filters: [
705
+ {
706
+ memcmp: {
707
+ offset: 12,
708
+ bytes: address,
709
+ },
729
710
  },
730
- },
731
- ],
732
- encoding: 'jsonParsed',
733
- },
734
- ]
735
- const res = await this.rpcCall('getProgramAccounts', params, { address })
736
-
711
+ ],
712
+ encoding: 'jsonParsed',
713
+ },
714
+ ],
715
+ })
737
716
  const accounts = {}
738
717
  let totalStake = 0
739
718
  let locked = 0
@@ -782,15 +761,29 @@ export class Api {
782
761
  }
783
762
 
784
763
  async getMinimumBalanceForRentExemption(size: number) {
785
- return this.rpcCall('getMinimumBalanceForRentExemption', [size])
764
+ const minimumBalance = await this.api.post({
765
+ method: 'getMinimumBalanceForRentExemption',
766
+ params: [size],
767
+ })
768
+
769
+ return minimumBalance
786
770
  }
787
771
 
788
772
  async getProgramAccounts(programId: string, config) {
789
- return this.rpcCall('getProgramAccounts', [programId, config])
773
+ const response = await this.api.post({
774
+ method: 'getProgramAccounts',
775
+ params: [programId, config],
776
+ })
777
+
778
+ return response
790
779
  }
791
780
 
792
781
  async getMultipleAccounts(pubkeys: string[], config) {
793
- const response = await this.rpcCall('getMultipleAccounts', [pubkeys, config])
782
+ const response = await this.api.post({
783
+ method: 'getMultipleAccounts',
784
+ params: [pubkeys, config],
785
+ })
786
+
794
787
  return response && response.value ? response.value : []
795
788
  }
796
789
 
@@ -800,8 +793,10 @@ export class Api {
800
793
  broadcastTransaction = async (signedTx: string): string => {
801
794
  console.log('Solana broadcasting TX:', signedTx) // base64
802
795
 
803
- const params = [signedTx, { encoding: 'base64', commitment: 'finalized' }]
804
- const result = await this.rpcCall('sendTransaction', params, { forceHttp: true })
796
+ const result = await this.api.post({
797
+ method: 'sendTransaction',
798
+ params: [signedTx, { encoding: 'base64', commitment: 'singleGossip' }],
799
+ })
805
800
 
806
801
  console.log(`tx ${JSON.stringify(result)} sent!`)
807
802
  return result || null
@@ -810,7 +805,10 @@ export class Api {
810
805
  simulateTransaction = async (encodedTransaction, options) => {
811
806
  const {
812
807
  value: { accounts },
813
- } = await this.rpcCall('simulateTransaction', [encodedTransaction, options])
808
+ } = await this.api.post({
809
+ method: 'simulateTransaction',
810
+ params: [encodedTransaction, options],
811
+ })
814
812
 
815
813
  return accounts
816
814
  }
@@ -4,11 +4,7 @@ import assert from 'minimalistic-assert'
4
4
 
5
5
  const DEFAULT_POOL_ADDRESS = '9QU2QSxhb24FUX3Tu2FpczXjpK3VYrvRudywSZaM29mF' // Everstake
6
6
 
7
- const DEFAULT_REMOTE_CONFIG = {
8
- rpcs: [],
9
- ws: [],
10
- staking: { enabled: true, pool: DEFAULT_POOL_ADDRESS },
11
- }
7
+ const DEFAULT_REMOTE_CONFIG = { rpcs: [], staking: { enabled: true, pool: DEFAULT_POOL_ADDRESS } }
12
8
 
13
9
  export class SolanaMonitor extends BaseMonitor {
14
10
  constructor({ api, includeUnparsed = false, ...args }) {
@@ -18,45 +14,11 @@ export class SolanaMonitor extends BaseMonitor {
18
14
  this.cursors = {}
19
15
  this.assets = {}
20
16
  this.includeUnparsed = includeUnparsed
21
- this.addHook('before-stop', (...args) => this.beforeStop(...args))
22
- }
23
-
24
- async beforeStop() {
25
- const walletAccounts = await this.aci.getWalletAccounts({ assetName: this.asset.name })
26
- return Promise.all(walletAccounts.map((walletAccount) => this.stopListener({ walletAccount })))
27
- }
28
-
29
- async initWalletAccount({ walletAccount }) {
30
- if (this.tickCount[walletAccount] === 0) {
31
- await this.startListener({ walletAccount })
32
- }
33
- }
34
-
35
- async startListener({ walletAccount }) {
36
- const address = await this.aci.getReceiveAddress({ assetName: this.asset.name, walletAccount })
37
- return this.api.watchAddress({
38
- address,
39
- /*
40
- // OPTIONAL. Relying on polling through ws
41
- tokensAddresses: [], // needed for ASA subs
42
- handleAccounts: (updates) => this.accountsCallback({ updates, walletAccount }),
43
- handleTransfers: (txs) => {
44
- // new SOL tx, ticking monitor
45
- this.tick({ walletAccount }) // it will cause refresh for both sender/receiver. Without necessarily fetching the tx if it's not finalized in the node.
46
- },
47
- */
48
- })
49
- }
50
-
51
- async stopListener({ walletAccount }) {
52
- const address = await this.aci.getReceiveAddress({ assetName: this.asset.name, walletAccount })
53
- return this.api.unwatchAddress({ address })
54
17
  }
55
18
 
56
19
  setServer(config = {}) {
57
- const { rpcs, ws, staking = {} } = { ...DEFAULT_REMOTE_CONFIG, ...config }
20
+ const { rpcs, staking = {} } = { ...DEFAULT_REMOTE_CONFIG, ...config }
58
21
  this.api.setServer(rpcs[0])
59
- this.api.setWsEndpoint(ws[0])
60
22
  this.staking = staking
61
23
  }
62
24
 
@@ -73,9 +35,6 @@ export class SolanaMonitor extends BaseMonitor {
73
35
  }
74
36
 
75
37
  async tick({ walletAccount, refresh }) {
76
- // Check for new wallet account
77
- await this.initWalletAccount({ walletAccount })
78
-
79
38
  const assetName = this.asset.name
80
39
  this.assets = await this.aci.getAssetsForNetwork({ baseAssetName: assetName })
81
40
  this.api.setTokens(this.assets)
package/src/connection.js DELETED
@@ -1,237 +0,0 @@
1
- import ms from 'ms'
2
- import delay from 'delay'
3
- import url from 'url'
4
- import lodash from 'lodash'
5
- import debugLogger from 'debug'
6
- import { WebSocket } from '@exodus/fetch'
7
-
8
- // WS subscriptions: https://docs.solana.com/developing/clients/jsonrpc-api#subscription-websocket
9
-
10
- const SOLANA_DEFAULT_ENDPOINT = 'wss://solana.a.exodus.io/ws'
11
- const DEFAULT_RECONNECT_DELAY = ms('15s')
12
- const PING_INTERVAL = ms('50s')
13
- const TIMEOUT = ms('20s')
14
-
15
- const debug = debugLogger('exodus:solana-api')
16
-
17
- export class Connection {
18
- constructor({
19
- endpoint = SOLANA_DEFAULT_ENDPOINT,
20
- address,
21
- tokensAddresses = [],
22
- callback,
23
- reconnectCallback = () => {},
24
- reconnectDelay = DEFAULT_RECONNECT_DELAY,
25
- }) {
26
- this.address = address
27
- this.tokensAddresses = tokensAddresses
28
- this.endpoint = endpoint
29
- this.callback = callback
30
- this.reconnectCallback = reconnectCallback
31
- this.reconnectDelay = reconnectDelay
32
-
33
- this.shutdown = false
34
- this.ws = null
35
- this.rpcQueue = {}
36
- this.messageQueue = []
37
- this.inProcessMessages = false
38
- this.pingTimeout = null
39
- this.reconnectTimeout = null
40
- this.txCache = {}
41
- }
42
-
43
- newSocket(reqUrl) {
44
- // eslint-disable-next-line
45
- const obj = url.parse(reqUrl)
46
- obj.protocol = 'wss:'
47
- reqUrl = url.format(obj)
48
- debug('Opening WS to:', reqUrl)
49
- const ws = new WebSocket(`${reqUrl}`)
50
- ws.onmessage = this.onMessage.bind(this)
51
- ws.onopen = this.onOpen.bind(this)
52
- ws.onclose = this.onClose.bind(this)
53
- ws.onerror = this.onError.bind(this)
54
- return ws
55
- }
56
-
57
- get isConnecting() {
58
- return !!(this.ws && this.ws.readyState === WebSocket.CONNECTING)
59
- }
60
-
61
- get isOpen() {
62
- return !!(this.ws && this.ws.readyState === WebSocket.OPEN)
63
- }
64
-
65
- get isClosing() {
66
- return !!(this.ws && this.ws.readyState === WebSocket.CLOSING)
67
- }
68
-
69
- get isClosed() {
70
- return !!(!this.ws || this.ws.readyState === WebSocket.CLOSED)
71
- }
72
-
73
- get running() {
74
- return !!(!this.isClosed || this.inProcessMessages || this.messageQueue.length)
75
- }
76
-
77
- get connectionState() {
78
- if (this.isConnecting) return 'CONNECTING'
79
- else if (this.isOpen) return 'OPEN'
80
- else if (this.isClosing) return 'CLOSING'
81
- else if (this.isClosed) return 'CLOSED'
82
- return 'NONE'
83
- }
84
-
85
- doPing() {
86
- if (this.ws) {
87
- this.ws.ping()
88
- this.pingTimeout = setTimeout(this.doPing.bind(this), PING_INTERVAL)
89
- }
90
- }
91
-
92
- doRestart() {
93
- // debug('Restarting WS:')
94
- this.reconnectTimeout = setTimeout(async () => {
95
- try {
96
- debug('reconnecting ws...')
97
- this.start()
98
- await this.reconnectCallback()
99
- } catch (e) {
100
- console.log(`Error in reconnect callback: ${e.message}`)
101
- }
102
- }, this.reconnectDelay)
103
- }
104
-
105
- onMessage(evt) {
106
- try {
107
- const json = JSON.parse(evt.data)
108
- debug('new ws msg:', json)
109
- if (!json.error) {
110
- if (lodash.get(this.rpcQueue, json.id)) {
111
- // json-rpc reply
112
- clearTimeout(this.rpcQueue[json.id].timeout)
113
- this.rpcQueue[json.id].resolve(json.result)
114
- delete this.rpcQueue[json.id]
115
- } else if (json.method) {
116
- const msg = { method: json.method, ...lodash.get(json, 'params.result', json.result) }
117
- debug('pushing msg to queue', msg)
118
- this.messageQueue.push(msg) // sub results
119
- }
120
- this.processMessages()
121
- } else {
122
- if (lodash.get(this.rpcQueue, json.id)) {
123
- this.rpcQueue[json.id].reject(new Error(json.error.message))
124
- clearTimeout(this.rpcQueue[json.id].timeout)
125
- delete this.rpcQueue[json.id]
126
- } else debug('Unsupported WS message:', json.error.message)
127
- }
128
- } catch (e) {
129
- debug(e)
130
- debug('Cannot parse msg:', evt.data)
131
- }
132
- }
133
-
134
- onOpen(evt) {
135
- debug('Opened WS')
136
- // subscribe to each addresses (SOL and ASA addr)
137
-
138
- this.tokensAddresses.concat(this.address).forEach((address) => {
139
- // sub for account state changes
140
- this.ws.send(
141
- JSON.stringify({
142
- jsonrpc: '2.0',
143
- method: 'accountSubscribe',
144
- params: [
145
- address,
146
- {
147
- encoding: 'jsonParsed',
148
- },
149
- ],
150
- id: 1,
151
- })
152
- )
153
- // sub for incoming/outcoming txs
154
- this.ws.send(
155
- JSON.stringify({
156
- jsonrpc: '2.0',
157
- method: 'logsSubscribe',
158
- params: [{ mentions: [address] }, { commitment: 'finalized' }],
159
- id: 2,
160
- })
161
- )
162
- })
163
- // this.doPing()
164
- }
165
-
166
- onError(evt) {
167
- debug('Error on WS:', evt.data)
168
- }
169
-
170
- onClose(evt) {
171
- debug('Closing WS')
172
- clearTimeout(this.pingTimeout)
173
- clearTimeout(this.reconnectTimeout)
174
- if (!this.shutdown) {
175
- this.doRestart()
176
- }
177
- }
178
-
179
- async sendMessage(method, params = []) {
180
- return new Promise((resolve, reject) => {
181
- if (this.isClosed || this.shutdown) return reject(new Error('connection not started'))
182
- const id = Math.floor(Math.random() * 1e7) + 1
183
-
184
- this.rpcQueue[id] = { resolve, reject }
185
- this.rpcQueue[id].timeout = setTimeout(() => {
186
- delete this.rpcQueue[id]
187
- reject(new Error('solana ws: reply timeout'))
188
- }, TIMEOUT)
189
- this.ws.send(JSON.stringify({ jsonrpc: '2.0', method, params, id }))
190
- })
191
- }
192
-
193
- async processMessages() {
194
- if (this.inProcessMessages) return null
195
- this.inProcessMessages = true
196
- try {
197
- while (this.messageQueue.length) {
198
- const items = this.messageQueue.splice(0, this.messageQueue.length)
199
- await this.callback(items)
200
- }
201
- } catch (e) {
202
- console.log(`Solana: error processing streams: ${e.message}`)
203
- } finally {
204
- this.inProcessMessages = false
205
- }
206
- }
207
-
208
- async close() {
209
- clearTimeout(this.reconnectTimeout)
210
- clearTimeout(this.pingTimeout)
211
- if (this.ws && (this.isConnecting || this.isOpen)) {
212
- // this.ws.send(JSON.stringify({ method: 'close' }))
213
- await delay(ms('1s')) // allow for the 'close' round-trip
214
- await this.ws.close()
215
- await this.ws.terminate()
216
- }
217
- }
218
-
219
- async start() {
220
- try {
221
- if (!this.isClosed || this.shutdown) return
222
- this.ws = this.newSocket(this.endpoint)
223
- } catch (e) {
224
- console.log('Solana: error starting WS:', e)
225
- this.doRestart()
226
- }
227
- }
228
-
229
- async stop() {
230
- if (this.shutdown) return
231
- this.shutdown = true
232
- await this.close()
233
- while (this.running) {
234
- await delay(ms('1s'))
235
- }
236
- }
237
- } // Connection