@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.
- package/package.json +4 -8
- 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
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
|
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,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
|
-
|
|
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
|
-
|
|
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.
|
|
154
|
-
const to = txDetails.transaction.
|
|
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.
|
|
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
|
-
|
|
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
|
-
}
|