@exodus/solana-api 1.0.2 → 1.2.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 +28 -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.2.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-exodus3",
17
+ "lodash": "^4.17.11"
19
18
  },
20
- "devDependencies": {
21
- "node-fetch": "~1.6.3"
22
- },
23
- "gitHead": "946e63be238d27a4e69b657c9979788e04bccea0"
19
+ "gitHead": "912e3574f02b1886ed0c6616a7d35f20de533dbd"
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,42 @@ 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
+ until = until || undefined
46
+ return this.connection.getConfirmedSignaturesForAddress2(new PublicKey(address), {
47
+ before,
48
+ until,
49
+ limit,
50
+ })
127
51
  }
128
52
 
129
53
  /**
@@ -150,8 +74,8 @@ class Api {
150
74
  if (txDetails === null) continue
151
75
 
152
76
  const timestamp = blockTime * 1000
153
- const from = txDetails.transaction.message.accountKeys[0]
154
- const to = txDetails.transaction.message.accountKeys[1]
77
+ const from = txDetails.transaction.keys[0].toString()
78
+ const to = txDetails.transaction.keys[1].toString()
155
79
  let { preBalances, postBalances, fee } = txDetails.meta
156
80
  const isSending = address === from
157
81
  fee = !isSending ? 0 : fee
@@ -169,17 +93,11 @@ class Api {
169
93
  from,
170
94
  to,
171
95
  amount, // lamports
172
- error: !(txDetails.meta.status.Ok === null),
96
+ error: !(txDetails.meta.err === null),
173
97
  })
174
98
  }
175
99
  } catch (err) {
176
100
  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
101
  throw err
184
102
  }
185
103
 
@@ -192,20 +110,10 @@ class Api {
192
110
  * Broadcast a signed transaction
193
111
  */
194
112
  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
- })
113
+ console.log('Solana broadcasting TX:', signedTx) // base64
207
114
 
208
- if (error) throw new Error(error.message)
115
+ const { message, ...result } = await this.connection.sendEncodedTransaction(signedTx)
116
+ if (message) throw new Error(message)
209
117
 
210
118
  console.log(`tx ${result} sent!`)
211
119
  return result || null
@@ -213,37 +121,3 @@ class Api {
213
121
  }
214
122
 
215
123
  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
- }