@exodus/solana-api 1.4.7 → 1.4.8
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 +2 -2
- package/src/index.js +68 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/solana-api",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.8",
|
|
4
4
|
"description": "Exodus internal Solana asset API wrapper",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"node-fetch": "~1.6.3"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "90293962539f80a74060b3010cbfa4ab4570baa7"
|
|
26
26
|
}
|
package/src/index.js
CHANGED
|
@@ -120,7 +120,10 @@ class Api {
|
|
|
120
120
|
/**
|
|
121
121
|
* Get transactions from an address
|
|
122
122
|
*/
|
|
123
|
-
async getTransactions(
|
|
123
|
+
async getTransactions(
|
|
124
|
+
address: string,
|
|
125
|
+
{ cursor, before, limit, includeUnparsed = false } = {}
|
|
126
|
+
): any {
|
|
124
127
|
let transactions = []
|
|
125
128
|
// cursor is a txHash
|
|
126
129
|
|
|
@@ -151,8 +154,10 @@ class Api {
|
|
|
151
154
|
if (txDetail === null) return
|
|
152
155
|
|
|
153
156
|
const timestamp = txDetail.blockTime * 1000
|
|
154
|
-
const parsedTx = this.parseTransaction(address, txDetail, tokenAccountsByOwner
|
|
155
|
-
|
|
157
|
+
const parsedTx = this.parseTransaction(address, txDetail, tokenAccountsByOwner, {
|
|
158
|
+
includeUnparsed,
|
|
159
|
+
})
|
|
160
|
+
if (!parsedTx.from && !includeUnparsed) return // cannot parse it
|
|
156
161
|
|
|
157
162
|
// split dexTx in separate txs
|
|
158
163
|
if (parsedTx.dexTxs) {
|
|
@@ -184,12 +189,39 @@ class Api {
|
|
|
184
189
|
return { transactions, newCursor }
|
|
185
190
|
}
|
|
186
191
|
|
|
187
|
-
parseTransaction(
|
|
188
|
-
|
|
192
|
+
parseTransaction(
|
|
193
|
+
ownerAddress: string,
|
|
194
|
+
txDetails: Object,
|
|
195
|
+
tokenAccountsByOwner: ?Array,
|
|
196
|
+
{ includeUnparsed = false } = {}
|
|
197
|
+
): Object {
|
|
198
|
+
let {
|
|
199
|
+
fee,
|
|
200
|
+
preBalances,
|
|
201
|
+
postBalances,
|
|
202
|
+
preTokenBalances,
|
|
203
|
+
postTokenBalances,
|
|
204
|
+
innerInstructions,
|
|
205
|
+
} = txDetails.meta
|
|
206
|
+
preBalances = preBalances || []
|
|
207
|
+
postBalances = postBalances || []
|
|
189
208
|
preTokenBalances = preTokenBalances || []
|
|
190
209
|
postTokenBalances = postTokenBalances || []
|
|
191
210
|
innerInstructions = innerInstructions || []
|
|
211
|
+
|
|
192
212
|
let { instructions, accountKeys } = txDetails.transaction.message
|
|
213
|
+
|
|
214
|
+
const getUnparsedTx = () => {
|
|
215
|
+
const ownerIndex = accountKeys.findIndex((accountKey) => accountKey.pubkey === ownerAddress)
|
|
216
|
+
const feePaid = ownerIndex === 0 ? fee : 0
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
unparsed: true,
|
|
220
|
+
amount: postBalances[ownerIndex] - preBalances[ownerIndex] + feePaid,
|
|
221
|
+
fee: feePaid,
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
193
225
|
instructions = instructions
|
|
194
226
|
.filter((ix) => ix.parsed) // only known instructions
|
|
195
227
|
.map((ix) => ({
|
|
@@ -368,30 +400,45 @@ class Api {
|
|
|
368
400
|
if (preBalances.length || postBalances.length) {
|
|
369
401
|
tx = {}
|
|
370
402
|
|
|
371
|
-
if (
|
|
372
|
-
//
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
403
|
+
if (includeUnparsed && innerInstructions.length) {
|
|
404
|
+
// when using includeUnparsed for DEX tx we want to keep SOL tx as "unparsed"
|
|
405
|
+
// 1. we want to treat all SOL dex transactions as "Contract transaction", not "Sent SOL"
|
|
406
|
+
// 2. default behavior is not perfect. For example it doesn't see SOL-side tx in
|
|
407
|
+
// SOL->SPL swaps on Raydium and Orca.
|
|
408
|
+
tx = getUnparsedTx(tx)
|
|
409
|
+
tx.dexTxs = innerInstructions.map((i) => ({ ...i, fee: 0 }))
|
|
410
|
+
} else {
|
|
411
|
+
if (solanaTx) {
|
|
412
|
+
// the base tx will be the one that moved solana.
|
|
413
|
+
tx = {
|
|
414
|
+
owner: solanaTx.source,
|
|
415
|
+
from: solanaTx.source,
|
|
416
|
+
to: solanaTx.destination,
|
|
417
|
+
amount: solanaTx.lamports, // number
|
|
418
|
+
fee: ownerAddress === solanaTx.source ? fee : 0,
|
|
419
|
+
}
|
|
379
420
|
}
|
|
380
|
-
}
|
|
381
421
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
422
|
+
// If it has inner instructions then it's a DEX tx that moved SPL -> SPL
|
|
423
|
+
if (innerInstructions.length) {
|
|
424
|
+
tx.dexTxs = innerInstructions
|
|
425
|
+
// if tx involves only SPL swaps. Expand DEX ix (first element as tx base and the other kept there)
|
|
426
|
+
if (!tx.from && !solanaTx) {
|
|
427
|
+
tx = tx.dexTxs[0]
|
|
428
|
+
tx.dexTxs = innerInstructions.slice(1)
|
|
429
|
+
}
|
|
389
430
|
}
|
|
390
431
|
}
|
|
391
432
|
}
|
|
392
433
|
}
|
|
393
434
|
}
|
|
394
435
|
|
|
436
|
+
const unparsed = Object.keys(tx).length === 0
|
|
437
|
+
|
|
438
|
+
if (unparsed && includeUnparsed) {
|
|
439
|
+
tx = getUnparsedTx(tx)
|
|
440
|
+
}
|
|
441
|
+
|
|
395
442
|
// How tokens tx are parsed:
|
|
396
443
|
// 0. compute incoming or outgoing tx: it's outgoing if spl-token:transfer has source/destination included in tokenAccountsByOwner
|
|
397
444
|
// 1. if it's a sent tx: sum all instructions amount (spl-token:transfer)
|