@exodus/solana-api 3.25.3 → 3.26.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/src/api.js CHANGED
@@ -20,22 +20,14 @@ import lodash from 'lodash'
20
20
  import ms from 'ms'
21
21
  import urljoin from 'url-join'
22
22
 
23
- import { Connection } from './connection.js'
24
23
  import { getStakeActivation } from './get-stake-activation/index.js'
25
- import {
26
- isSolTransferInstruction,
27
- isSplMintInstruction,
28
- isSplTransferInstruction,
29
- } from './txs-utils.js'
24
+ import { parseTransaction } from './tx-parser.js'
30
25
 
31
26
  const createApi = createApiCJS.default || createApiCJS
32
27
 
33
28
  // Doc: https://docs.solana.com/apps/jsonrpc-api
34
29
 
35
30
  const RPC_URL = 'https://solana.a.exodus.io' // https://vip-api.mainnet-beta.solana.com/, https://api.mainnet-beta.solana.com
36
- const WS_ENDPOINT = 'wss://solana.a.exodus.io/ws' // not standard across all node providers (we're compatible only with Quicknode)
37
- const FORCE_HTTP = true // use https over ws
38
- const ZERO = BigInt(0)
39
31
 
40
32
  const errorMessagesToRetry = [
41
33
  'Blockhash not found',
@@ -44,14 +36,11 @@ const errorMessagesToRetry = [
44
36
 
45
37
  // Tokens + SOL api support
46
38
  export class Api {
47
- constructor({ rpcUrl, wsUrl, assets, txsLimit, tokenAssetType = 'SOLANA_TOKEN' }) {
48
- this.tokenAssetType = tokenAssetType
39
+ constructor({ rpcUrl, wsUrl, assets, txsLimit }) {
49
40
  this.setServer(rpcUrl)
50
- this.setWsEndpoint(wsUrl)
51
41
  this.setTokens(assets)
52
42
  this.tokensToSkip = {}
53
43
  this.txsLimit = txsLimit
54
- this.connections = {}
55
44
  this.getSupply = memoize(async (mintAddress) => {
56
45
  // cached getSupply
57
46
  const result = await this.rpcCall('getTokenSupply', [mintAddress])
@@ -76,12 +65,8 @@ export class Api {
76
65
  this.api = createApi(this.rpcUrl)
77
66
  }
78
67
 
79
- setWsEndpoint(wsUrl) {
80
- this.wsUrl = wsUrl || WS_ENDPOINT
81
- }
82
-
83
68
  setTokens(assets = {}) {
84
- const solTokens = pickBy(assets, (asset) => asset.assetType === this.tokenAssetType)
69
+ const solTokens = pickBy(assets, (asset) => asset.name !== asset.baseAsset.name)
85
70
  this.tokens = new Map(Object.values(solTokens).map((v) => [v.mintAddress, v]))
86
71
  }
87
72
 
@@ -91,51 +76,7 @@ export class Api {
91
76
  })
92
77
  }
93
78
 
94
- async watchAddress({
95
- address,
96
- tokensAddresses = [],
97
- onMessage,
98
- handleAccounts,
99
- handleTransfers,
100
- handleReconnect,
101
- reconnectDelay,
102
- }) {
103
- if (this.connections[address]) return // already subscribed
104
- const conn = new Connection({
105
- endpoint: this.wsUrl,
106
- address,
107
- tokensAddresses,
108
- onMsg: (json) => onMessage(json),
109
- callback: (updates) =>
110
- this.handleUpdates({ updates, address, handleAccounts, handleTransfers }),
111
- reconnectCallback: handleReconnect,
112
- reconnectDelay,
113
- })
114
-
115
- this.connections[address] = conn
116
- return conn.start()
117
- }
118
-
119
- async unwatchAddress({ address }) {
120
- if (this.connections[address]) {
121
- await this.connections[address].stop()
122
- delete this.connections[address]
123
- }
124
- }
125
-
126
- async handleUpdates({ updates, address, handleAccounts, handleTransfers }) {
127
- // console.log(`got ws updates from ${address}:`, updates)
128
- if (handleTransfers) return handleTransfers(updates)
129
- }
130
-
131
- async rpcCall(method, params = [], { address = '', forceHttp = FORCE_HTTP } = {}) {
132
- // ws request
133
- const connection = this.connections[address] || lodash.sample(Object.values(this.connections)) // pick random connection
134
- if (lodash.get(connection, 'isOpen') && !lodash.get(connection, 'shutdown') && !forceHttp) {
135
- return connection.sendMessage(method, params)
136
- }
137
-
138
- // http fallback
79
+ async rpcCall(method, params = []) {
139
80
  return this.api.post({ method, params })
140
81
  }
141
82
 
@@ -172,11 +113,9 @@ export class Api {
172
113
  }
173
114
 
174
115
  async getRecentBlockHash(commitment) {
175
- const result = await this.rpcCall(
176
- 'getLatestBlockhash',
177
- [{ commitment: commitment || 'confirmed', encoding: 'jsonParsed' }],
178
- { forceHttp: true }
179
- )
116
+ const result = await this.rpcCall('getLatestBlockhash', [
117
+ { commitment: commitment || 'confirmed', encoding: 'jsonParsed' },
118
+ ])
180
119
  return lodash.get(result, 'value.blockhash')
181
120
  }
182
121
 
@@ -197,9 +136,7 @@ export class Api {
197
136
  }
198
137
 
199
138
  async getBalance(address) {
200
- const result = await this.rpcCall('getBalance', [address, { encoding: 'jsonParsed' }], {
201
- address,
202
- })
139
+ const result = await this.rpcCall('getBalance', [address, { encoding: 'jsonParsed' }])
203
140
  return lodash.get(result, 'value', 0)
204
141
  }
205
142
 
@@ -240,13 +177,7 @@ export class Api {
240
177
  const fetchRetry = retry(
241
178
  async () => {
242
179
  try {
243
- return await this.rpcCall(
244
- 'getSignaturesForAddress',
245
- [address, { until, before, limit }],
246
- {
247
- address,
248
- }
249
- )
180
+ return await this.rpcCall('getSignaturesForAddress', [address, { until, before, limit }])
250
181
  } catch (error) {
251
182
  if (
252
183
  error.message &&
@@ -353,532 +284,8 @@ export class Api {
353
284
  return { transactions, newCursor }
354
285
  }
355
286
 
356
- parseTransaction(
357
- ownerAddress,
358
- txDetails,
359
- tokenAccountsByOwner,
360
- { includeUnparsed = false } = {}
361
- ) {
362
- let { fee, preBalances, postBalances, preTokenBalances, postTokenBalances, innerInstructions } =
363
- txDetails.meta
364
- preBalances = preBalances || []
365
- postBalances = postBalances || []
366
- preTokenBalances = preTokenBalances || []
367
- postTokenBalances = postTokenBalances || []
368
- innerInstructions = innerInstructions || []
369
-
370
- let { instructions, accountKeys } = txDetails.transaction.message
371
- const txId = txDetails.transaction.signatures[0]
372
-
373
- const getUnparsedTx = () => {
374
- const ownerIndex = accountKeys.findIndex((accountKey) => accountKey.pubkey === ownerAddress)
375
- const feePaid = ownerIndex === 0 ? fee : 0
376
-
377
- return {
378
- unparsed: true,
379
- amount:
380
- ownerIndex === -1 ? 0 : postBalances[ownerIndex] - preBalances[ownerIndex] + feePaid,
381
- fee: feePaid,
382
- data: {
383
- meta: txDetails.meta,
384
- },
385
- }
386
- }
387
-
388
- const getInnerTxsFromBalanceChanges = () => {
389
- const ownPreTokenBalances = preTokenBalances.filter(
390
- (balance) => balance.owner === ownerAddress
391
- )
392
- const ownPostTokenBalances = postTokenBalances.filter(
393
- (balance) => balance.owner === ownerAddress
394
- )
395
-
396
- return ownPostTokenBalances
397
- .map((postBalance) => {
398
- const tokenAccount = tokenAccountsByOwner.find(
399
- (tokenAccount) => tokenAccount.mintAddress === postBalance.mint
400
- )
401
-
402
- const preBalance = ownPreTokenBalances.find(
403
- (balance) => balance.accountIndex === postBalance.accountIndex
404
- )
405
-
406
- const preAmount = BigInt(preBalance?.uiTokenAmount?.amount ?? '0')
407
- const postAmount = BigInt(postBalance?.uiTokenAmount?.amount ?? '0')
408
-
409
- const amount = postAmount - preAmount
410
-
411
- if (!tokenAccount || amount === ZERO) return null
412
-
413
- // This is not perfect as there could be multiple same-token transfers in single
414
- // transaction, but our wallet only supports one transaction with single txId
415
- // so we are picking first that matches (correct token + type - send or receive)
416
- const match = innerInstructions.find((inner) => {
417
- const targetOwner = amount < ZERO ? ownerAddress : null
418
- return (
419
- inner.token.mintAddress === tokenAccount.mintAddress && targetOwner === inner.owner
420
- )
421
- })
422
-
423
- // It's possible we won't find a match, because our innerInstructions only contain
424
- // spl-token transfers, but balances of SPL tokens can change in different ways too.
425
- // for now, we are ignoring this to simplify as those cases are not that common, but
426
- // they should be handled eventually. It was already a scretch to add unparsed txs logic
427
- // to existing parser, expanding it further is not going to end well.
428
- // this probably should be refactored from ground to handle all those transactions
429
- // as a core part of it in the future
430
- if (!match) return null
431
-
432
- const { from, to, owner } = match
433
-
434
- return {
435
- id: txId,
436
- slot: txDetails.slot,
437
- owner,
438
- from,
439
- to,
440
- amount: (amount < ZERO ? -amount : amount).toString(), // inconsistent with the rest, but it can and did overflow
441
- fee: 0,
442
- token: tokenAccount,
443
- data: {
444
- inner: true,
445
- },
446
- }
447
- })
448
- .filter((ix) => !!ix)
449
- }
450
-
451
- instructions = instructions
452
- .filter((ix) => ix.parsed) // only known instructions
453
- .map((ix) => ({
454
- program: ix.program, // system or spl-token
455
- type: ix.parsed.type, // transfer, createAccount, initializeAccount
456
- ...ix.parsed.info,
457
- }))
458
-
459
- let solanaTransferTx = lodash.find(instructions, (ix) => {
460
- if (![ix.source, ix.destination].includes(ownerAddress)) return false
461
- return ix.program === 'system' && ix.type === 'transfer'
462
- }) // get SOL transfer
463
-
464
- // check if there is a temp account created & closed within the instructions when there is no direct solana transfer
465
- const accountToRedeemToOwner = solanaTransferTx
466
- ? undefined
467
- : instructions.find(
468
- ({ type, owner, destination }) =>
469
- type === 'closeAccount' && owner === ownerAddress && destination === ownerAddress
470
- )?.account
471
-
472
- innerInstructions = innerInstructions
473
- .reduce((acc, val) => {
474
- return [...acc, ...val.instructions]
475
- }, [])
476
- .filter(
477
- (ix) =>
478
- ix.parsed &&
479
- (isSplTransferInstruction({ program: ix.program, type: ix.parsed.type }) ||
480
- isSplMintInstruction({ program: ix.program, type: ix.parsed.type }) ||
481
- (!includeUnparsed &&
482
- isSolTransferInstruction({ program: ix.program, type: ix.parsed.type })))
483
- )
484
- .map((ix) => {
485
- let source = lodash.get(ix, 'parsed.info.source')
486
- const destination = isSplMintInstruction({ program: ix.program, type: ix.parsed.type })
487
- ? lodash.get(ix, 'parsed.info.account') // only for minting
488
- : lodash.get(ix, 'parsed.info.destination')
489
- const amount = Number(
490
- lodash.get(ix, 'parsed.info.amount', 0) ||
491
- lodash.get(ix, 'parsed.info.tokenAmount.amount', 0)
492
- )
493
- const authority = lodash.get(ix, 'parsed.info.authority')
494
-
495
- if (accountToRedeemToOwner && destination === accountToRedeemToOwner) {
496
- solanaTransferTx = {
497
- from: authority || source,
498
- to: ownerAddress,
499
- amount,
500
- fee,
501
- }
502
- return
503
- }
504
-
505
- if (
506
- source === ownerAddress &&
507
- isSolTransferInstruction({ program: ix.program, type: ix.parsed.type })
508
- ) {
509
- const lamports = Number(lodash.get(ix, 'parsed.info.lamports', 0))
510
- if (solanaTransferTx) {
511
- solanaTransferTx.lamports += lamports
512
- solanaTransferTx.amount = solanaTransferTx.lamports
513
- if (!Array.isArray(solanaTransferTx.to)) {
514
- solanaTransferTx.data = {
515
- sent: [
516
- {
517
- address: solanaTransferTx.to,
518
- amount: lamports,
519
- },
520
- ],
521
- }
522
- solanaTransferTx.to = [solanaTransferTx.to]
523
- }
524
-
525
- solanaTransferTx.to.push(destination)
526
- solanaTransferTx.data.sent.push({ address: destination, amount: lamports })
527
- } else {
528
- solanaTransferTx = {
529
- source,
530
- owner: source,
531
- from: source,
532
- to: [destination],
533
- lamports,
534
- amount: lamports,
535
- data: {
536
- sent: [
537
- {
538
- address: destination,
539
- amount: lamports,
540
- },
541
- ],
542
- },
543
- fee,
544
- }
545
- }
546
-
547
- return
548
- }
549
-
550
- const tokenAccount = tokenAccountsByOwner.find(({ tokenAccountAddress }) => {
551
- return [source, destination].includes(tokenAccountAddress)
552
- })
553
- if (!tokenAccount) return
554
-
555
- if (isSplMintInstruction({ program: ix.program, type: ix.parsed.type })) {
556
- source = lodash.get(ix, 'parsed.info.mintAuthority')
557
- }
558
-
559
- const isSending = tokenAccountsByOwner.some(({ tokenAccountAddress }) => {
560
- return [source].includes(tokenAccountAddress)
561
- })
562
-
563
- // owner if it's a send tx
564
- return {
565
- id: txId,
566
- program: ix.program,
567
- type: ix.parsed.type,
568
- slot: txDetails.slot,
569
- owner: isSending ? ownerAddress : null,
570
- from: isSending ? ownerAddress : source,
571
- to: isSending ? destination : ownerAddress,
572
- amount,
573
- token: tokenAccount,
574
- fee: isSending ? fee : 0,
575
- }
576
- })
577
- .filter((ix) => !!ix)
578
-
579
- // Collect inner instructions into batch sends
580
- for (let i = 0; i < innerInstructions.length - 1; i++) {
581
- const tx = innerInstructions[i]
582
-
583
- for (let j = i + 1; j < innerInstructions.length; j++) {
584
- const next = innerInstructions[j]
585
- if (
586
- tx.id === next.id &&
587
- tx.token === next.token &&
588
- tx.owner === ownerAddress &&
589
- tx.from === next.from
590
- ) {
591
- if (!tx.data) {
592
- tx.data = { sent: [{ address: tx.to, amount: tx.amount }] }
593
- tx.to = [tx.to]
594
- tx.fee = 0
595
- }
596
-
597
- tx.data.sent.push({
598
- address: next.to,
599
- amount: next.amount,
600
- })
601
- tx.to.push(next.to)
602
-
603
- tx.amount += next.amount
604
-
605
- innerInstructions.splice(j, 1)
606
- j--
607
- }
608
- }
609
- }
610
-
611
- // program:type tells us if it's a SOL or Token transfer
612
-
613
- const stakeTx = lodash.find(instructions, { program: 'system', type: 'createAccountWithSeed' })
614
- const stakeWithdraw = lodash.find(instructions, { program: 'stake', type: 'withdraw' })
615
- const stakeUndelegate = lodash.find(instructions, { program: 'stake', type: 'deactivate' })
616
-
617
- let tx = {}
618
- if (stakeTx) {
619
- // start staking
620
- tx = {
621
- owner: stakeTx.base,
622
- from: stakeTx.base,
623
- to: stakeTx.base,
624
- amount: stakeTx.lamports,
625
- fee,
626
- staking: {
627
- method: 'createAccountWithSeed',
628
- seed: stakeTx.seed,
629
- stakeAddresses: [stakeTx.newAccount],
630
- stake: stakeTx.lamports,
631
- },
632
- }
633
- } else if (stakeWithdraw) {
634
- const stakeAccounts = lodash.map(
635
- lodash.filter(instructions, { program: 'stake', type: 'withdraw' }),
636
- 'stakeAccount'
637
- )
638
- tx = {
639
- owner: stakeWithdraw.withdrawAuthority,
640
- from: stakeWithdraw.stakeAccount,
641
- to: stakeWithdraw.destination,
642
- amount: stakeWithdraw.lamports,
643
- fee,
644
- staking: {
645
- method: 'withdraw',
646
- stakeAddresses: stakeAccounts,
647
- stake: stakeWithdraw.lamports,
648
- },
649
- }
650
- } else if (stakeUndelegate) {
651
- const stakeAccounts = lodash.map(
652
- lodash.filter(instructions, { program: 'stake', type: 'deactivate' }),
653
- 'stakeAccount'
654
- )
655
- tx = {
656
- owner: stakeUndelegate.stakeAuthority,
657
- from: stakeUndelegate.stakeAuthority,
658
- to: stakeUndelegate.stakeAccount, // obsolete
659
- amount: 0,
660
- fee,
661
- staking: {
662
- method: 'undelegate',
663
- stakeAddresses: stakeAccounts,
664
- },
665
- }
666
- } else {
667
- if (solanaTransferTx) {
668
- const isSending = ownerAddress === solanaTransferTx.source
669
- tx = {
670
- owner: solanaTransferTx.source,
671
- from: solanaTransferTx.source,
672
- to: solanaTransferTx.destination,
673
- amount: solanaTransferTx.lamports, // number
674
- fee: isSending ? fee : 0,
675
- data: solanaTransferTx.data,
676
- }
677
- }
678
-
679
- const accountIndexes = accountKeys.reduce((acc, key, i) => {
680
- const hasKnownOwner = tokenAccountsByOwner.some(
681
- (tokenAccount) => tokenAccount.tokenAccountAddress === key.pubkey
682
- )
683
-
684
- acc[i] = {
685
- ...key,
686
- owner: hasKnownOwner ? ownerAddress : null, // not know (like in an outgoing tx)
687
- }
688
-
689
- return acc
690
- }, Object.create(null)) // { 0: { pubkey, owner }, 1: { ... }, ... }
691
-
692
- // Parse Token txs
693
- const tokenTxs = this._parseTokenTransfers({
694
- instructions,
695
- innerInstructions,
696
- tokenAccountsByOwner,
697
- ownerAddress,
698
- fee,
699
- accountIndexes,
700
- preTokenBalances,
701
- postTokenBalances,
702
- })
703
-
704
- if (tokenTxs.length > 0) {
705
- // found spl-token simple transfer/transferChecked instruction
706
- tx.tokenTxs = tokenTxs.map((tx) => ({
707
- id: txId,
708
- slot: txDetails.slot,
709
- ...tx,
710
- }))
711
- } else if (preTokenBalances && postTokenBalances) {
712
- // probably a DEX program is involved (multiple instructions), compute balance changes
713
- // group by owner and supported token
714
- const preBalances = preTokenBalances.filter((t) => {
715
- return (
716
- accountIndexes[t.accountIndex].owner === ownerAddress && this.isTokenSupported(t.mint)
717
- )
718
- })
719
- const postBalances = postTokenBalances.filter((t) => {
720
- return (
721
- accountIndexes[t.accountIndex].owner === ownerAddress && this.isTokenSupported(t.mint)
722
- )
723
- })
724
-
725
- if (preBalances.length > 0 || postBalances.length > 0 || solanaTransferTx) {
726
- tx = {}
727
-
728
- if (includeUnparsed && innerInstructions.length > 0) {
729
- // when using includeUnparsed for DEX tx we want to keep SOL tx as "unparsed"
730
- // 1. we want to treat all SOL dex transactions as "Contract transaction", not "Sent SOL"
731
- // 2. default behavior is not perfect. For example it doesn't see SOL-side tx in
732
- // SOL->SPL swaps on Raydium and Orca.
733
- tx = getUnparsedTx()
734
- tx.dexTxs = getInnerTxsFromBalanceChanges()
735
- } else {
736
- if (solanaTransferTx) {
737
- // the base tx will be the one that moved solana.
738
- tx =
739
- solanaTransferTx.from && solanaTransferTx.to
740
- ? solanaTransferTx
741
- : {
742
- owner: solanaTransferTx.source,
743
- from: solanaTransferTx.source,
744
- to: solanaTransferTx.destination,
745
- amount: solanaTransferTx.lamports, // number
746
- fee: ownerAddress === solanaTransferTx.source ? fee : 0,
747
- }
748
- }
749
-
750
- // If it has inner instructions then it's a DEX tx that moved SPL -> SPL
751
- if (innerInstructions.length > 0) {
752
- tx.dexTxs = innerInstructions
753
- // if tx involves only SPL swaps. Expand DEX ix (first element as tx base and the other kept there)
754
- if (!tx.from && !solanaTransferTx) {
755
- tx = tx.dexTxs[0]
756
- tx.dexTxs = innerInstructions.slice(1)
757
- }
758
- }
759
- }
760
- }
761
- }
762
- }
763
-
764
- const unparsed = Object.keys(tx).length === 0
765
-
766
- if (unparsed && includeUnparsed) {
767
- tx = getUnparsedTx()
768
- }
769
-
770
- // How tokens tx are parsed:
771
- // 0. compute incoming or outgoing tx: it's outgoing if spl-token:transfer has source/destination included in tokenAccountsByOwner
772
- // 1. if it's a sent tx: sum all instructions amount (spl-token:transfer)
773
- // 2. if it's an incoming tx: sum all the amounts with destination included in tokenAccountsByOwner (aggregating by ticker)
774
- // QUESTION: How do I know what are my tokens addresses deterministically? It's not possible, gotta use tokenAccountsByOwner
775
-
776
- return {
777
- id: txDetails.transaction.signatures[0],
778
- slot: txDetails.slot,
779
- error: !(txDetails.meta.err === null),
780
- ...tx,
781
- }
782
- }
783
-
784
- _parseTokenTransfers({
785
- instructions,
786
- innerInstructions = [],
787
- tokenAccountsByOwner,
788
- ownerAddress,
789
- fee,
790
- accountIndexes = {},
791
- preTokenBalances,
792
- postTokenBalances,
793
- }) {
794
- if (
795
- preTokenBalances.length === 0 &&
796
- postTokenBalances.length === 0 &&
797
- !Array.isArray(tokenAccountsByOwner)
798
- ) {
799
- return []
800
- }
801
-
802
- const tokenTxs = []
803
-
804
- instructions.forEach((instruction) => {
805
- const { type, program, source, destination, amount, tokenAmount } = instruction
806
-
807
- if (isSplTransferInstruction({ program, type })) {
808
- let tokenAccount = lodash.find(tokenAccountsByOwner, { tokenAccountAddress: source })
809
- const isSending = !!tokenAccount
810
- if (!isSending) {
811
- // receiving
812
- tokenAccount = lodash.find(tokenAccountsByOwner, {
813
- tokenAccountAddress: destination,
814
- })
815
- }
816
-
817
- if (!tokenAccount) return // no transfers with our addresses involved
818
-
819
- const owner = isSending ? ownerAddress : null
820
-
821
- delete tokenAccount.balance
822
- delete tokenAccount.owner
823
-
824
- // If it's a sending tx we want to have the destination's owner as "to" address
825
- let to = ownerAddress
826
- let from = ownerAddress
827
- if (isSending) {
828
- to = destination // token account address (trying to get the owner below, we don't always have postTokenBalances...)
829
- postTokenBalances.forEach((t) => {
830
- if (accountIndexes[t.accountIndex].pubkey === destination) to = t.owner
831
- })
832
- } else {
833
- // is receiving tx
834
- from = source // token account address
835
- preTokenBalances.forEach((t) => {
836
- if (accountIndexes[t.accountIndex].pubkey === source) from = t.owner
837
- })
838
- }
839
-
840
- tokenTxs.push({
841
- owner,
842
- token: tokenAccount,
843
- from,
844
- to,
845
- amount: Number(amount || tokenAmount?.amount || 0), // supporting types: transfer, transferChecked, transferCheckedWithFee
846
- fee: isSending ? fee : 0, // in lamports
847
- })
848
- }
849
- })
850
-
851
- innerInstructions.forEach((parsedIx) => {
852
- const { type, program, amount, from, to } = parsedIx
853
-
854
- // Handle token minting (mintTo, mintToChecked)
855
- if (isSplMintInstruction({ program, type })) {
856
- const {
857
- token: { tokenAccountAddress },
858
- } = parsedIx
859
-
860
- // Check if the destination token account belongs to our owner
861
- const tokenAccount = lodash.find(tokenAccountsByOwner, {
862
- tokenAccountAddress,
863
- })
864
-
865
- if (!tokenAccount) return // not our token account
866
-
867
- delete tokenAccount.balance
868
- delete tokenAccount.owner
869
-
870
- tokenTxs.push({
871
- owner: null, // no owner for minting (it's created from thin air)
872
- token: tokenAccount,
873
- from, // mint address as the source
874
- to, // our address as recipient
875
- amount: Number(amount || 0),
876
- fee: 0, // no fee for receiving minted tokens
877
- })
878
- }
879
- })
880
-
881
- return tokenTxs
287
+ parseTransaction(...args) {
288
+ return parseTransaction(...args)
882
289
  }
883
290
 
884
291
  async getWalletTokensList({ tokenAccounts }) {
@@ -908,16 +315,16 @@ export class Api {
908
315
 
909
316
  async getTokenAccountsByOwner(address, tokenTicker) {
910
317
  const [{ value: standardTokenAccounts }, { value: token2022Accounts }] = await Promise.all([
911
- this.rpcCall(
912
- 'getTokenAccountsByOwner',
913
- [address, { programId: TOKEN_PROGRAM_ID.toBase58() }, { encoding: 'jsonParsed' }],
914
- { address }
915
- ),
916
- this.rpcCall(
917
- 'getTokenAccountsByOwner',
918
- [address, { programId: TOKEN_2022_PROGRAM_ID.toBase58() }, { encoding: 'jsonParsed' }],
919
- { address }
920
- ),
318
+ this.rpcCall('getTokenAccountsByOwner', [
319
+ address,
320
+ { programId: TOKEN_PROGRAM_ID.toBase58() },
321
+ { encoding: 'jsonParsed' },
322
+ ]),
323
+ this.rpcCall('getTokenAccountsByOwner', [
324
+ address,
325
+ { programId: TOKEN_2022_PROGRAM_ID.toBase58() },
326
+ { encoding: 'jsonParsed' },
327
+ ]),
921
328
  ])
922
329
 
923
330
  // merge regular token and token2022 program tokens
@@ -1030,11 +437,10 @@ export class Api {
1030
437
  }
1031
438
 
1032
439
  async getAccountInfo(address, encoding = 'jsonParsed') {
1033
- const { value } = await this.rpcCall(
1034
- 'getAccountInfo',
1035
- [address, { encoding, commitment: 'confirmed' }],
1036
- { address }
1037
- )
440
+ const { value } = await this.rpcCall('getAccountInfo', [
441
+ address,
442
+ { encoding, commitment: 'confirmed' },
443
+ ])
1038
444
  return value
1039
445
  }
1040
446
 
@@ -1127,7 +533,7 @@ export class Api {
1127
533
  encoding: 'jsonParsed',
1128
534
  },
1129
535
  ]
1130
- const res = await this.rpcCall('getProgramAccounts', params, { address })
536
+ const res = await this.rpcCall('getProgramAccounts', params)
1131
537
 
1132
538
  const accounts = {}
1133
539
  let totalStake = 0
@@ -1203,7 +609,7 @@ export class Api {
1203
609
  const broadcastTxWithRetry = retry(
1204
610
  async () => {
1205
611
  try {
1206
- const result = await this.rpcCall('sendTransaction', params, { forceHttp: true })
612
+ const result = await this.rpcCall('sendTransaction', params)
1207
613
  console.log(`tx ${JSON.stringify(result)} sent!`)
1208
614
 
1209
615
  return result || null