@exodus/solana-api 1.0.2 → 1.1.0

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.
Files changed (2) hide show
  1. package/package.json +4 -8
  2. package/src/index.js +27 -154
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-api",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Exodus internal Solana asset API wrapper",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -13,12 +13,8 @@
13
13
  "access": "restricted"
14
14
  },
15
15
  "dependencies": {
16
- "fetchival": "~0.3.2",
17
- "lodash": "^4.17.11",
18
- "ms": "~0.7.1"
16
+ "@exodus/solana-web3.js": "0.87.1-exodus1",
17
+ "lodash": "^4.17.11"
19
18
  },
20
- "devDependencies": {
21
- "node-fetch": "~1.6.3"
22
- },
23
- "gitHead": "946e63be238d27a4e69b657c9979788e04bccea0"
19
+ "gitHead": "f18544ae45db87c7efec7d8139e1e04c51e0fc32"
24
20
  }
package/src/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  // @flow
2
- import ms from 'ms'
3
- import fetchival from 'fetchival'
2
+ import { Connection, PublicKey } from '@exodus/solana-web3.js'
4
3
 
5
- // Doc: https://docs.solana.com/apps/jsonrpc-api
4
+ // Doc: https://solana-labs.github.io/solana-web3.js/
6
5
 
7
6
  const RPC_URL = 'https://api.mainnet-beta.solana.com' // https://solana-api.projectserum.com
8
7
 
@@ -13,117 +12,41 @@ class Api {
13
12
 
14
13
  setServer(rpcUrl) {
15
14
  this.rpcUrl = rpcUrl || RPC_URL
15
+ this.connection = new Connection(this.rpcUrl)
16
16
  }
17
17
 
18
- request(path) {
19
- return fetchival(this.rpcUrl, {
20
- timeout: ms('15s'),
21
- headers: { 'Content-Type': 'application/json' },
22
- })(path)
23
- }
24
-
25
- async getRecentBlockHash() {
26
- try {
27
- const { result, error } = await this.request('').post({
28
- jsonrpc: '2.0',
29
- id: getCurrentTime(),
30
- method: 'getRecentBlockhash',
31
- params: [],
32
- })
33
- if (error) throw new Error(error.message)
34
- return result.value.blockhash
35
- } catch (err) {
36
- console.log(err)
37
- if (err.response) err = new Error(JSON.stringify(await concatStream(err.response)))
38
- throw err
39
- }
18
+ async getRecentBlockHash(): string {
19
+ const { blockhash } = await this.connection.getRecentBlockhash()
20
+ return blockhash
40
21
  }
41
22
 
42
23
  // Transaction structure: https://docs.solana.com/apps/jsonrpc-api#transaction-structure
43
24
  async getTransactionById(id: string) {
44
- try {
45
- const { result, error } = await this.request('').post({
46
- jsonrpc: '2.0',
47
- id: getCurrentTime(),
48
- method: 'getConfirmedTransaction',
49
- params: [id, 'json'],
50
- })
51
- if (error) throw new Error(error.message)
52
- return result
53
- } catch (err) {
54
- console.log(err)
55
- if (err.response) err = new Error(JSON.stringify(await concatStream(err.response)))
56
- throw err
57
- }
25
+ return this.connection.getConfirmedTransaction(id)
58
26
  }
59
27
 
60
28
  async getFee(): number {
61
- try {
62
- const { result, error } = await this.request('').post({
63
- jsonrpc: '2.0',
64
- id: getCurrentTime(),
65
- method: 'getFees',
66
- params: [],
67
- })
68
- if (error) throw new Error(error.message)
69
- return result.value.feeCalculator.lamportsPerSignature
70
- } catch (err) {
71
- if (err.response) err = new Error(JSON.stringify(await concatStream(err.response)))
72
- throw err
73
- }
29
+ const {
30
+ feeCalculator: { lamportsPerSignature },
31
+ } = await this.connection.getRecentBlockhash()
32
+ return lamportsPerSignature
74
33
  }
75
34
 
76
35
  async getBalance(address: string): number {
77
- try {
78
- const { result, error } = await this.request('').post({
79
- jsonrpc: '2.0',
80
- id: getCurrentTime(),
81
- method: 'getBalance',
82
- params: [address],
83
- })
84
- if (error) throw new Error(error.message)
85
- return result.value || 0
86
- } catch (err) {
87
- console.log(err)
88
- if (err.response) err = new Error(JSON.stringify(await concatStream(err.response)))
89
- throw err
90
- }
36
+ return this.connection.getBalance(new PublicKey(address))
91
37
  }
92
38
 
93
- async getBlockTime(slot: number): any {
94
- try {
95
- const { result, error } = await this.request('').post({
96
- jsonrpc: '2.0',
97
- id: getCurrentTime(),
98
- method: 'getBlockTime',
99
- params: [slot],
100
- })
101
- // might result in error if executed on a validator with partial ledger (https://github.com/solana-labs/solana/issues/12413)
102
- if (error) console.log(error.message)
103
- return result
104
- } catch (err) {
105
- console.log(err)
106
- if (err.response) err = new Error(JSON.stringify(await concatStream(err.response)))
107
- throw err
108
- }
39
+ async getBlockTime(slot: number) {
40
+ // might result in error if executed on a validator with partial ledger (https://github.com/solana-labs/solana/issues/12413)
41
+ return this.connection.getBlockTime(slot)
109
42
  }
110
43
 
111
- async getConfirmedSignaturesForAddress(address: string, { before, until, limit }): any {
112
- try {
113
- until = until || undefined
114
- const { result, error } = await this.request('').post({
115
- jsonrpc: '2.0',
116
- id: getCurrentTime(),
117
- method: 'getConfirmedSignaturesForAddress2',
118
- params: [address, { before, until, limit }],
119
- })
120
- if (error) throw new Error(error.message)
121
- return result
122
- } catch (err) {
123
- console.log(err)
124
- if (err.response) err = new Error(JSON.stringify(await concatStream(err.response)))
125
- throw err
126
- }
44
+ async getConfirmedSignaturesForAddress(address: string, { before, until, limit } = {}): any {
45
+ return this.connection.getConfirmedSignaturesForAddress2(new PublicKey(address), {
46
+ before,
47
+ until,
48
+ limit,
49
+ })
127
50
  }
128
51
 
129
52
  /**
@@ -150,8 +73,8 @@ class Api {
150
73
  if (txDetails === null) continue
151
74
 
152
75
  const timestamp = blockTime * 1000
153
- const from = txDetails.transaction.message.accountKeys[0]
154
- const to = txDetails.transaction.message.accountKeys[1]
76
+ const from = txDetails.transaction.keys[0].toString()
77
+ const to = txDetails.transaction.keys[1].toString()
155
78
  let { preBalances, postBalances, fee } = txDetails.meta
156
79
  const isSending = address === from
157
80
  fee = !isSending ? 0 : fee
@@ -169,17 +92,11 @@ class Api {
169
92
  from,
170
93
  to,
171
94
  amount, // lamports
172
- error: !(txDetails.meta.status.Ok === null),
95
+ error: !(txDetails.meta.err === null),
173
96
  })
174
97
  }
175
98
  } catch (err) {
176
99
  console.warn('Solana error:', err)
177
- if (err.response) {
178
- const error = new Error(JSON.stringify(await concatStream(err.response)))
179
- error.status = err.response.status
180
- error.statusText = err.response.statusText
181
- throw error
182
- }
183
100
  throw err
184
101
  }
185
102
 
@@ -192,20 +109,10 @@ class Api {
192
109
  * Broadcast a signed transaction
193
110
  */
194
111
  broadcastTransaction = async (signedTx: string): string => {
195
- console.log('Solana broadcasting TX:', signedTx)
196
-
197
- const { result, error } = await this.request('')
198
- .post({
199
- jsonrpc: '2.0',
200
- id: getCurrentTime(),
201
- method: 'sendTransaction',
202
- params: [signedTx],
203
- })
204
- .catch(async (err) => {
205
- throw new Error(JSON.stringify(await concatStream(err.response)))
206
- })
112
+ console.log('Solana broadcasting TX:', signedTx) // base64
207
113
 
208
- if (error) throw new Error(error.message)
114
+ const { message, ...result } = await this.connection.sendEncodedTransaction(signedTx)
115
+ if (message) throw new Error(message)
209
116
 
210
117
  console.log(`tx ${result} sent!`)
211
118
  return result || null
@@ -213,37 +120,3 @@ class Api {
213
120
  }
214
121
 
215
122
  export default new Api()
216
-
217
- function getCurrentTime() {
218
- const date = new Date()
219
- return date.getTime()
220
- }
221
-
222
- function concatStream(response) {
223
- const stream = response.body
224
- if (typeof stream !== 'object')
225
- throw new Error(`${response.status} - ${response.statusText || 'Server Error'}`)
226
- if ('locked' in stream) {
227
- // fetch browser
228
- try {
229
- return response.json()
230
- } catch (e) {
231
- return response.text()
232
- }
233
- }
234
- return new Promise((resolve, reject) => {
235
- let result = ''
236
- stream.on('data', (chunk) => {
237
- result += chunk.toString()
238
- })
239
- stream.on('end', () => {
240
- try {
241
- const parsed = JSON.parse(result)
242
- resolve(parsed)
243
- } catch (e) {
244
- resolve(result) // plain text
245
- }
246
- })
247
- stream.on('error', (err) => reject(err))
248
- })
249
- }