@lifi/sdk 3.3.1 → 3.4.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.
Files changed (43) hide show
  1. package/package.json +4 -4
  2. package/src/_cjs/config.js +6 -5
  3. package/src/_cjs/config.js.map +1 -1
  4. package/src/_cjs/core/Solana/SolanaStepExecutor.js +12 -47
  5. package/src/_cjs/core/Solana/SolanaStepExecutor.js.map +1 -1
  6. package/src/_cjs/core/Solana/connection.js +30 -9
  7. package/src/_cjs/core/Solana/connection.js.map +1 -1
  8. package/src/_cjs/core/Solana/getSolanaBalance.js +5 -5
  9. package/src/_cjs/core/Solana/getSolanaBalance.js.map +1 -1
  10. package/src/_cjs/core/Solana/sendAndConfirmTransaction.js +68 -0
  11. package/src/_cjs/core/Solana/sendAndConfirmTransaction.js.map +1 -0
  12. package/src/_cjs/utils/withDedupe.js.map +1 -1
  13. package/src/_cjs/version.js +1 -1
  14. package/src/_esm/config.js +6 -5
  15. package/src/_esm/config.js.map +1 -1
  16. package/src/_esm/core/Solana/SolanaStepExecutor.js +14 -65
  17. package/src/_esm/core/Solana/SolanaStepExecutor.js.map +1 -1
  18. package/src/_esm/core/Solana/connection.js +40 -10
  19. package/src/_esm/core/Solana/connection.js.map +1 -1
  20. package/src/_esm/core/Solana/getSolanaBalance.js +6 -6
  21. package/src/_esm/core/Solana/getSolanaBalance.js.map +1 -1
  22. package/src/_esm/core/Solana/sendAndConfirmTransaction.js +76 -0
  23. package/src/_esm/core/Solana/sendAndConfirmTransaction.js.map +1 -0
  24. package/src/_esm/utils/withDedupe.js.map +1 -1
  25. package/src/_esm/version.js +1 -1
  26. package/src/_types/config.d.ts +2 -2
  27. package/src/_types/config.d.ts.map +1 -1
  28. package/src/_types/core/Solana/SolanaStepExecutor.d.ts.map +1 -1
  29. package/src/_types/core/Solana/connection.d.ts +14 -3
  30. package/src/_types/core/Solana/connection.d.ts.map +1 -1
  31. package/src/_types/core/Solana/getSolanaBalance.d.ts.map +1 -1
  32. package/src/_types/core/Solana/sendAndConfirmTransaction.d.ts +13 -0
  33. package/src/_types/core/Solana/sendAndConfirmTransaction.d.ts.map +1 -0
  34. package/src/_types/utils/withDedupe.d.ts +1 -1
  35. package/src/_types/utils/withDedupe.d.ts.map +1 -1
  36. package/src/_types/version.d.ts +1 -1
  37. package/src/config.ts +6 -6
  38. package/src/core/Solana/SolanaStepExecutor.ts +15 -86
  39. package/src/core/Solana/connection.ts +43 -10
  40. package/src/core/Solana/getSolanaBalance.ts +27 -7
  41. package/src/core/Solana/sendAndConfirmTransaction.ts +111 -0
  42. package/src/utils/withDedupe.ts +3 -3
  43. package/src/version.ts +1 -1
@@ -1,7 +1,8 @@
1
1
  import type { ChainId, Token, TokenAmount } from '@lifi/types'
2
2
  import { PublicKey } from '@solana/web3.js'
3
3
  import { SolSystemProgram } from '../../constants.js'
4
- import { getSolanaConnection } from './connection.js'
4
+ import { withDedupe } from '../../utils/withDedupe.js'
5
+ import { callSolanaWithRetry } from './connection.js'
5
6
  import { TokenProgramAddress } from './types.js'
6
7
 
7
8
  export const getSolanaBalance = async (
@@ -26,15 +27,34 @@ const getSolanaBalanceDefault = async (
26
27
  tokens: Token[],
27
28
  walletAddress: string
28
29
  ): Promise<TokenAmount[]> => {
29
- const connection = await getSolanaConnection()
30
30
  const accountPublicKey = new PublicKey(walletAddress)
31
31
  const tokenProgramPublicKey = new PublicKey(TokenProgramAddress)
32
32
  const [slot, balance, tokenAccountsByOwner] = await Promise.allSettled([
33
- connection.getSlot(),
34
- connection.getBalance(accountPublicKey),
35
- connection.getParsedTokenAccountsByOwner(accountPublicKey, {
36
- programId: tokenProgramPublicKey,
37
- }),
33
+ withDedupe(
34
+ () =>
35
+ callSolanaWithRetry((connection) => connection.getSlot('confirmed')),
36
+ { id: `${getSolanaBalanceDefault.name}.getSlot` }
37
+ ),
38
+ withDedupe(
39
+ () =>
40
+ callSolanaWithRetry((connection) =>
41
+ connection.getBalance(accountPublicKey, 'confirmed')
42
+ ),
43
+ { id: `${getSolanaBalanceDefault.name}.getBalance` }
44
+ ),
45
+ withDedupe(
46
+ () =>
47
+ callSolanaWithRetry((connection) =>
48
+ connection.getParsedTokenAccountsByOwner(
49
+ accountPublicKey,
50
+ {
51
+ programId: tokenProgramPublicKey,
52
+ },
53
+ 'confirmed'
54
+ )
55
+ ),
56
+ { id: `${getSolanaBalanceDefault.name}.getParsedTokenAccountsByOwner` }
57
+ ),
38
58
  ])
39
59
  const blockNumber = slot.status === 'fulfilled' ? BigInt(slot.value) : 0n
40
60
  const solBalance = balance.status === 'fulfilled' ? BigInt(balance.value) : 0n
@@ -0,0 +1,111 @@
1
+ import type {
2
+ SendOptions,
3
+ SignatureResult,
4
+ VersionedTransaction,
5
+ } from '@solana/web3.js'
6
+ import bs58 from 'bs58'
7
+ import { sleep } from '../../utils/sleep.js'
8
+ import { getSolanaConnections } from './connection.js'
9
+
10
+ export type ConfirmedTransactionResult = {
11
+ signatureResult: SignatureResult | null
12
+ txSignature: string
13
+ }
14
+
15
+ /**
16
+ * Sends a Solana transaction to multiple RPC endpoints and returns the confirmation
17
+ * as soon as any of them confirm the transaction.
18
+ * @param signedTx - The signed transaction to send.
19
+ * @returns - The confirmation result of the transaction.
20
+ */
21
+ export async function sendAndConfirmTransaction(
22
+ signedTx: VersionedTransaction
23
+ ): Promise<ConfirmedTransactionResult> {
24
+ const connections = await getSolanaConnections()
25
+
26
+ const signedTxSerialized = signedTx.serialize()
27
+ // Create transaction hash (signature)
28
+ const txSignature = bs58.encode(signedTx.signatures[0])
29
+
30
+ if (!txSignature) {
31
+ throw new Error('Transaction signature is missing.')
32
+ }
33
+
34
+ const rawTransactionOptions: SendOptions = {
35
+ // We can skip preflight check after the first transaction has been sent
36
+ // https://solana.com/docs/advanced/retry#the-cost-of-skipping-preflight
37
+ skipPreflight: true,
38
+ // Setting max retries to 0 as we are handling retries manually
39
+ maxRetries: 0,
40
+ // https://solana.com/docs/advanced/confirmation#use-an-appropriate-preflight-commitment-level
41
+ preflightCommitment: 'confirmed',
42
+ }
43
+
44
+ for (const connection of connections) {
45
+ connection
46
+ .sendRawTransaction(signedTxSerialized, rawTransactionOptions)
47
+ .catch()
48
+ }
49
+
50
+ const abortControllers: AbortController[] = []
51
+
52
+ const confirmPromises = connections.map(async (connection) => {
53
+ const abortController = new AbortController()
54
+ abortControllers.push(abortController)
55
+ try {
56
+ const blockhashResult = await connection.getLatestBlockhash('confirmed')
57
+
58
+ const confirmTransactionPromise = connection
59
+ .confirmTransaction(
60
+ {
61
+ signature: txSignature,
62
+ blockhash: blockhashResult.blockhash,
63
+ lastValidBlockHeight: blockhashResult.lastValidBlockHeight,
64
+ abortSignal: abortController.signal,
65
+ },
66
+ 'confirmed'
67
+ )
68
+ .then((result) => result.value)
69
+
70
+ let signatureResult: SignatureResult | null = null
71
+ let blockHeight = await connection.getBlockHeight('confirmed')
72
+
73
+ while (
74
+ !signatureResult &&
75
+ blockHeight < blockhashResult.lastValidBlockHeight
76
+ ) {
77
+ await connection.sendRawTransaction(
78
+ signedTxSerialized,
79
+ rawTransactionOptions
80
+ )
81
+ signatureResult = await Promise.race([
82
+ confirmTransactionPromise,
83
+ sleep(1000),
84
+ ])
85
+
86
+ if (signatureResult || abortController.signal.aborted) {
87
+ break
88
+ }
89
+
90
+ blockHeight = await connection.getBlockHeight('confirmed')
91
+ }
92
+
93
+ abortController.abort()
94
+
95
+ return signatureResult
96
+ } catch (error) {
97
+ if (abortController.signal.aborted) {
98
+ return Promise.reject(new Error('Confirmation aborted.'))
99
+ }
100
+ throw error
101
+ }
102
+ })
103
+
104
+ const signatureResult = await Promise.any(confirmPromises).catch(() => null)
105
+
106
+ for (const abortController of abortControllers) {
107
+ abortController.abort()
108
+ }
109
+
110
+ return { signatureResult, txSignature }
111
+ }
@@ -29,10 +29,10 @@ type WithDedupeOptions = {
29
29
  }
30
30
 
31
31
  /** Deduplicates in-flight promises. */
32
- export function withDedupe<data>(
33
- fn: () => Promise<data>,
32
+ export function withDedupe<T>(
33
+ fn: () => Promise<T>,
34
34
  { enabled = true, id }: WithDedupeOptions
35
- ): Promise<data> {
35
+ ): Promise<T> {
36
36
  if (!enabled || !id) {
37
37
  return fn()
38
38
  }
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/sdk'
2
- export const version = '3.3.1'
2
+ export const version = '3.4.0'