@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.
- package/package.json +4 -8
- 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
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
|
3
|
-
import fetchival from 'fetchival'
|
|
2
|
+
import { Connection, PublicKey } from '@exodus/solana-web3.js'
|
|
4
3
|
|
|
5
|
-
// Doc: https://
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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)
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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.
|
|
154
|
-
const to = txDetails.transaction.
|
|
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.
|
|
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
|
-
|
|
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
|
-
}
|