@exodus/solana-api 3.3.1 → 3.3.2

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 +3 -3
  2. package/src/api.js +64 -23
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-api",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "Exodus internal Solana asset API wrapper",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -29,7 +29,7 @@
29
29
  "@exodus/models": "^10.1.0",
30
30
  "@exodus/nfts-core": "^0.5.0",
31
31
  "@exodus/simple-retry": "^0.0.6",
32
- "@exodus/solana-lib": "^3.0.0",
32
+ "@exodus/solana-lib": "^3.0.1",
33
33
  "@exodus/solana-meta": "^1.0.7",
34
34
  "bn.js": "^4.11.0",
35
35
  "debug": "^4.1.1",
@@ -44,5 +44,5 @@
44
44
  "devDependencies": {
45
45
  "@exodus/assets-testing": "^1.0.0"
46
46
  },
47
- "gitHead": "30fdc2a936b6776866467baf926c899e9a236beb"
47
+ "gitHead": "44ecb6d313061bd62306a4171c0f61e40be5daaf"
48
48
  }
package/src/api.js CHANGED
@@ -26,6 +26,7 @@ import { Connection } from './connection'
26
26
  const RPC_URL = 'https://solana.a.exodus.io' // https://vip-api.mainnet-beta.solana.com/, https://api.mainnet-beta.solana.com
27
27
  const WS_ENDPOINT = 'wss://solana.a.exodus.io/ws' // not standard across all node providers (we're compatible only with Quicknode)
28
28
  const FORCE_HTTP = true // use https over ws
29
+ const WRAPPED_SOLANA_TOKEN_MINT_ADDRESS = `So11111111111111111111111111111111111111112`
29
30
 
30
31
  // Tokens + SOL api support
31
32
  export class Api {
@@ -342,6 +343,20 @@ export class Api {
342
343
  type: ix.parsed.type, // transfer, createAccount, initializeAccount
343
344
  ...ix.parsed.info,
344
345
  }))
346
+
347
+ let solanaTransferTx = lodash.find(instructions, (ix) => {
348
+ if (![ix.source, ix.destination].includes(ownerAddress)) return false
349
+ return ix.program === 'system' && ix.type === 'transfer'
350
+ }) // get SOL transfer
351
+
352
+ // check if there is a temp account created & closed within the instructions when there is no direct solana transfer
353
+ const accountToRedeemToOwner = solanaTransferTx
354
+ ? undefined
355
+ : instructions.find(
356
+ ({ type, owner, destination }) =>
357
+ type === 'closeAccount' && owner === ownerAddress && destination === ownerAddress
358
+ )?.account
359
+
345
360
  innerInstructions = innerInstructions
346
361
  .reduce((acc, val) => {
347
362
  return [...acc, ...val.instructions]
@@ -352,23 +367,47 @@ export class Api {
352
367
  ix.parsed &&
353
368
  ix.program === 'spl-token' &&
354
369
  ['transfer', 'transferChecked', 'transferCheckedWithFee'].includes(type)
370
+
371
+ if (!isTransferTx) return null
372
+
355
373
  const source = lodash.get(ix, 'parsed.info.source')
356
374
  const destination = lodash.get(ix, 'parsed.info.destination')
375
+ const mint = lodash.get(ix, 'parsed.info.mint')
357
376
  const amount = Number(
358
377
  lodash.get(ix, 'parsed.info.amount', 0) ||
359
378
  lodash.get(ix, 'parsed.info.tokenAmount.amount', 0)
360
379
  )
380
+ const txId = txDetails.transaction.signatures[0]
381
+ if (
382
+ accountToRedeemToOwner &&
383
+ [source, destination].includes(accountToRedeemToOwner) &&
384
+ mint === WRAPPED_SOLANA_TOKEN_MINT_ADDRESS
385
+ ) {
386
+ const ownerOrAccount = (account) =>
387
+ account && account === accountToRedeemToOwner ? ownerAddress : account
388
+
389
+ solanaTransferTx = {
390
+ id: txId,
391
+ from: ownerOrAccount(source),
392
+ to: ownerOrAccount(destination),
393
+ amount,
394
+ fee,
395
+ }
396
+ return
397
+ }
361
398
 
362
399
  const tokenAccount = tokenAccountsByOwner.find(({ tokenAccountAddress }) => {
363
400
  return [source, destination].includes(tokenAccountAddress)
364
401
  })
402
+ if (!tokenAccount) return
403
+
365
404
  const isSending = tokenAccountsByOwner.some(({ tokenAccountAddress }) => {
366
405
  return [source].includes(tokenAccountAddress)
367
406
  })
368
407
 
369
408
  // owner if it's a send tx
370
409
  const instruction = {
371
- id: txDetails.transaction.signatures[0],
410
+ id: txId,
372
411
  slot: txDetails.slot,
373
412
  owner: isSending ? ownerAddress : null,
374
413
  from: source,
@@ -377,29 +416,27 @@ export class Api {
377
416
  token: tokenAccount,
378
417
  fee: isSending ? fee : 0,
379
418
  }
380
- return isTransferTx && tokenAccount ? instruction : null
419
+ return tokenAccount ? instruction : null
381
420
  })
382
421
  .filter((ix) => !!ix)
383
422
 
384
423
  // program:type tells us if it's a SOL or Token transfer
385
- const solanaTx = lodash.find(instructions, (ix) => {
386
- if (![ix.source, ix.destination].includes(ownerAddress)) return false
387
- return ix.program === 'system' && ix.type === 'transfer'
388
- }) // get SOL transfer
424
+
389
425
  const stakeTx = lodash.find(instructions, { program: 'system', type: 'createAccountWithSeed' })
390
426
  const stakeWithdraw = lodash.find(instructions, { program: 'stake', type: 'withdraw' })
391
427
  const stakeUndelegate = lodash.find(instructions, { program: 'stake', type: 'deactivate' })
392
- const hasSolanaTx = solanaTx && preTokenBalances.length === 0 && postTokenBalances.length === 0 // only SOL moved and no tokens movements
428
+ const hasOnlySolanaTx =
429
+ solanaTransferTx && preTokenBalances.length === 0 && postTokenBalances.length === 0 // only SOL moved and no tokens movements
393
430
 
394
431
  let tx = {}
395
- if (hasSolanaTx) {
432
+ if (hasOnlySolanaTx) {
396
433
  // Solana tx
397
- const isSending = ownerAddress === solanaTx.source
434
+ const isSending = ownerAddress === solanaTransferTx.source
398
435
  tx = {
399
- owner: solanaTx.source,
400
- from: solanaTx.source,
401
- to: solanaTx.destination,
402
- amount: solanaTx.lamports, // number
436
+ owner: solanaTransferTx.source,
437
+ from: solanaTransferTx.source,
438
+ to: solanaTransferTx.destination,
439
+ amount: solanaTransferTx.lamports, // number
403
440
  fee: isSending ? fee : 0,
404
441
  }
405
442
  } else if (stakeTx) {
@@ -456,6 +493,7 @@ export class Api {
456
493
  Array.isArray(tokenAccountsByOwner),
457
494
  'tokenAccountsByOwner is required when parsing token tx'
458
495
  )
496
+
459
497
  const tokenTxs = lodash
460
498
  .filter(instructions, ({ program, type }) => {
461
499
  return (
@@ -521,7 +559,7 @@ export class Api {
521
559
  )
522
560
  })
523
561
 
524
- if (preBalances.length > 0 || postBalances.length > 0) {
562
+ if (preBalances.length > 0 || postBalances.length > 0 || solanaTransferTx) {
525
563
  tx = {}
526
564
 
527
565
  if (includeUnparsed && innerInstructions.length > 0) {
@@ -532,22 +570,25 @@ export class Api {
532
570
  tx = getUnparsedTx()
533
571
  tx.dexTxs = getInnerTxsFromBalanceChanges()
534
572
  } else {
535
- if (solanaTx) {
573
+ if (solanaTransferTx) {
536
574
  // the base tx will be the one that moved solana.
537
- tx = {
538
- owner: solanaTx.source,
539
- from: solanaTx.source,
540
- to: solanaTx.destination,
541
- amount: solanaTx.lamports, // number
542
- fee: ownerAddress === solanaTx.source ? fee : 0,
543
- }
575
+ tx =
576
+ solanaTransferTx.from && solanaTransferTx.to
577
+ ? solanaTransferTx
578
+ : {
579
+ owner: solanaTransferTx.source,
580
+ from: solanaTransferTx.source,
581
+ to: solanaTransferTx.destination,
582
+ amount: solanaTransferTx.lamports, // number
583
+ fee: ownerAddress === solanaTransferTx.source ? fee : 0,
584
+ }
544
585
  }
545
586
 
546
587
  // If it has inner instructions then it's a DEX tx that moved SPL -> SPL
547
588
  if (innerInstructions.length > 0) {
548
589
  tx.dexTxs = innerInstructions
549
590
  // if tx involves only SPL swaps. Expand DEX ix (first element as tx base and the other kept there)
550
- if (!tx.from && !solanaTx) {
591
+ if (!tx.from && !solanaTransferTx) {
551
592
  tx = tx.dexTxs[0]
552
593
  tx.dexTxs = innerInstructions.slice(1)
553
594
  }