@chainlink/ccip-sdk 0.90.2 → 0.91.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 (202) hide show
  1. package/README.md +35 -26
  2. package/dist/aptos/exec.d.ts +4 -5
  3. package/dist/aptos/exec.d.ts.map +1 -1
  4. package/dist/aptos/exec.js +5 -14
  5. package/dist/aptos/exec.js.map +1 -1
  6. package/dist/aptos/hasher.d.ts +18 -0
  7. package/dist/aptos/hasher.d.ts.map +1 -1
  8. package/dist/aptos/hasher.js +18 -0
  9. package/dist/aptos/hasher.js.map +1 -1
  10. package/dist/aptos/index.d.ts +127 -28
  11. package/dist/aptos/index.d.ts.map +1 -1
  12. package/dist/aptos/index.js +199 -70
  13. package/dist/aptos/index.js.map +1 -1
  14. package/dist/aptos/logs.d.ts +18 -0
  15. package/dist/aptos/logs.d.ts.map +1 -1
  16. package/dist/aptos/logs.js +21 -3
  17. package/dist/aptos/logs.js.map +1 -1
  18. package/dist/aptos/send.d.ts +22 -5
  19. package/dist/aptos/send.d.ts.map +1 -1
  20. package/dist/aptos/send.js +23 -15
  21. package/dist/aptos/send.js.map +1 -1
  22. package/dist/aptos/token.d.ts +6 -0
  23. package/dist/aptos/token.d.ts.map +1 -1
  24. package/dist/aptos/token.js +6 -0
  25. package/dist/aptos/token.js.map +1 -1
  26. package/dist/aptos/types.d.ts +16 -1
  27. package/dist/aptos/types.d.ts.map +1 -1
  28. package/dist/aptos/types.js +13 -0
  29. package/dist/aptos/types.js.map +1 -1
  30. package/dist/aptos/utils.d.ts +1 -1
  31. package/dist/aptos/utils.js +1 -1
  32. package/dist/chain.d.ts +185 -99
  33. package/dist/chain.d.ts.map +1 -1
  34. package/dist/chain.js +38 -15
  35. package/dist/chain.js.map +1 -1
  36. package/dist/commits.d.ts +4 -10
  37. package/dist/commits.d.ts.map +1 -1
  38. package/dist/commits.js +2 -1
  39. package/dist/commits.js.map +1 -1
  40. package/dist/evm/const.d.ts +5 -0
  41. package/dist/evm/const.d.ts.map +1 -1
  42. package/dist/evm/const.js +5 -0
  43. package/dist/evm/const.js.map +1 -1
  44. package/dist/evm/errors.d.ts +5 -0
  45. package/dist/evm/errors.d.ts.map +1 -1
  46. package/dist/evm/errors.js +6 -1
  47. package/dist/evm/errors.js.map +1 -1
  48. package/dist/evm/hasher.d.ts +16 -2
  49. package/dist/evm/hasher.d.ts.map +1 -1
  50. package/dist/evm/hasher.js +17 -3
  51. package/dist/evm/hasher.js.map +1 -1
  52. package/dist/evm/index.d.ts +176 -31
  53. package/dist/evm/index.d.ts.map +1 -1
  54. package/dist/evm/index.js +312 -154
  55. package/dist/evm/index.js.map +1 -1
  56. package/dist/evm/logs.d.ts +20 -0
  57. package/dist/evm/logs.d.ts.map +1 -0
  58. package/dist/evm/logs.js +194 -0
  59. package/dist/evm/logs.js.map +1 -0
  60. package/dist/evm/messages.d.ts +11 -2
  61. package/dist/evm/messages.d.ts.map +1 -1
  62. package/dist/evm/messages.js +4 -2
  63. package/dist/evm/messages.js.map +1 -1
  64. package/dist/evm/offchain.d.ts +7 -2
  65. package/dist/evm/offchain.d.ts.map +1 -1
  66. package/dist/evm/offchain.js +12 -7
  67. package/dist/evm/offchain.js.map +1 -1
  68. package/dist/execution.d.ts +19 -62
  69. package/dist/execution.d.ts.map +1 -1
  70. package/dist/execution.js +28 -31
  71. package/dist/execution.js.map +1 -1
  72. package/dist/extra-args.d.ts +35 -5
  73. package/dist/extra-args.d.ts.map +1 -1
  74. package/dist/extra-args.js +10 -5
  75. package/dist/extra-args.js.map +1 -1
  76. package/dist/gas.d.ts +6 -8
  77. package/dist/gas.d.ts.map +1 -1
  78. package/dist/gas.js +7 -9
  79. package/dist/gas.js.map +1 -1
  80. package/dist/hasher/common.d.ts +3 -2
  81. package/dist/hasher/common.d.ts.map +1 -1
  82. package/dist/hasher/common.js +2 -2
  83. package/dist/hasher/common.js.map +1 -1
  84. package/dist/hasher/hasher.d.ts +8 -2
  85. package/dist/hasher/hasher.d.ts.map +1 -1
  86. package/dist/hasher/hasher.js +8 -3
  87. package/dist/hasher/hasher.js.map +1 -1
  88. package/dist/hasher/merklemulti.d.ts +11 -9
  89. package/dist/hasher/merklemulti.d.ts.map +1 -1
  90. package/dist/hasher/merklemulti.js +17 -16
  91. package/dist/hasher/merklemulti.js.map +1 -1
  92. package/dist/index.d.ts +16 -8
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +17 -7
  95. package/dist/index.js.map +1 -1
  96. package/dist/requests.d.ts +39 -25
  97. package/dist/requests.d.ts.map +1 -1
  98. package/dist/requests.js +42 -35
  99. package/dist/requests.js.map +1 -1
  100. package/dist/selectors.d.ts +1 -1
  101. package/dist/solana/cleanup.d.ts +14 -10
  102. package/dist/solana/cleanup.d.ts.map +1 -1
  103. package/dist/solana/cleanup.js +35 -33
  104. package/dist/solana/cleanup.js.map +1 -1
  105. package/dist/solana/exec.d.ts +19 -11
  106. package/dist/solana/exec.d.ts.map +1 -1
  107. package/dist/solana/exec.js +86 -163
  108. package/dist/solana/exec.js.map +1 -1
  109. package/dist/solana/hasher.d.ts +7 -2
  110. package/dist/solana/hasher.d.ts.map +1 -1
  111. package/dist/solana/hasher.js +7 -2
  112. package/dist/solana/hasher.js.map +1 -1
  113. package/dist/solana/index.d.ts +202 -84
  114. package/dist/solana/index.d.ts.map +1 -1
  115. package/dist/solana/index.js +367 -252
  116. package/dist/solana/index.js.map +1 -1
  117. package/dist/solana/offchain.d.ts +8 -18
  118. package/dist/solana/offchain.d.ts.map +1 -1
  119. package/dist/solana/offchain.js +29 -83
  120. package/dist/solana/offchain.js.map +1 -1
  121. package/dist/solana/patchBorsh.d.ts +5 -1
  122. package/dist/solana/patchBorsh.d.ts.map +1 -1
  123. package/dist/solana/patchBorsh.js +57 -46
  124. package/dist/solana/patchBorsh.js.map +1 -1
  125. package/dist/solana/send.d.ts +28 -10
  126. package/dist/solana/send.d.ts.map +1 -1
  127. package/dist/solana/send.js +44 -77
  128. package/dist/solana/send.js.map +1 -1
  129. package/dist/solana/types.d.ts +22 -1
  130. package/dist/solana/types.d.ts.map +1 -1
  131. package/dist/solana/types.js +12 -1
  132. package/dist/solana/types.js.map +1 -1
  133. package/dist/solana/utils.d.ts +58 -4
  134. package/dist/solana/utils.d.ts.map +1 -1
  135. package/dist/solana/utils.js +110 -7
  136. package/dist/solana/utils.js.map +1 -1
  137. package/dist/sui/hasher.d.ts +18 -0
  138. package/dist/sui/hasher.d.ts.map +1 -1
  139. package/dist/sui/hasher.js +18 -0
  140. package/dist/sui/hasher.js.map +1 -1
  141. package/dist/sui/index.d.ts +99 -12
  142. package/dist/sui/index.d.ts.map +1 -1
  143. package/dist/sui/index.js +108 -19
  144. package/dist/sui/index.js.map +1 -1
  145. package/dist/sui/types.d.ts +6 -0
  146. package/dist/sui/types.d.ts.map +1 -1
  147. package/dist/sui/types.js +5 -0
  148. package/dist/sui/types.js.map +1 -1
  149. package/dist/supported-chains.d.ts +2 -1
  150. package/dist/supported-chains.d.ts.map +1 -1
  151. package/dist/supported-chains.js.map +1 -1
  152. package/dist/types.d.ts +127 -16
  153. package/dist/types.d.ts.map +1 -1
  154. package/dist/types.js +18 -0
  155. package/dist/types.js.map +1 -1
  156. package/dist/utils.d.ts +67 -46
  157. package/dist/utils.d.ts.map +1 -1
  158. package/dist/utils.js +143 -21
  159. package/dist/utils.js.map +1 -1
  160. package/package.json +13 -9
  161. package/src/aptos/exec.ts +7 -18
  162. package/src/aptos/hasher.ts +18 -0
  163. package/src/aptos/index.ts +288 -110
  164. package/src/aptos/logs.ts +21 -3
  165. package/src/aptos/send.ts +25 -22
  166. package/src/aptos/token.ts +6 -0
  167. package/src/aptos/types.ts +26 -2
  168. package/src/aptos/utils.ts +1 -1
  169. package/src/chain.ts +243 -108
  170. package/src/commits.ts +6 -7
  171. package/src/evm/const.ts +5 -0
  172. package/src/evm/errors.ts +6 -1
  173. package/src/evm/hasher.ts +20 -4
  174. package/src/evm/index.ts +416 -214
  175. package/src/evm/logs.ts +255 -0
  176. package/src/evm/messages.ts +11 -5
  177. package/src/evm/offchain.ts +13 -4
  178. package/src/execution.ts +40 -32
  179. package/src/extra-args.ts +38 -6
  180. package/src/gas.ts +7 -9
  181. package/src/hasher/common.ts +3 -2
  182. package/src/hasher/hasher.ts +12 -4
  183. package/src/hasher/merklemulti.ts +17 -16
  184. package/src/index.ts +29 -23
  185. package/src/requests.ts +64 -46
  186. package/src/selectors.ts +1 -1
  187. package/src/solana/cleanup.ts +49 -34
  188. package/src/solana/exec.ts +128 -272
  189. package/src/solana/hasher.ts +13 -4
  190. package/src/solana/index.ts +483 -356
  191. package/src/solana/offchain.ts +32 -102
  192. package/src/solana/patchBorsh.ts +65 -50
  193. package/src/solana/send.ts +52 -111
  194. package/src/solana/types.ts +44 -3
  195. package/src/solana/utils.ts +143 -19
  196. package/src/sui/hasher.ts +18 -0
  197. package/src/sui/index.ts +143 -31
  198. package/src/sui/types.ts +6 -0
  199. package/src/supported-chains.ts +2 -1
  200. package/src/types.ts +130 -18
  201. package/src/utils.ts +168 -26
  202. package/tsconfig.json +2 -1
@@ -1,12 +1,20 @@
1
1
  import { supportedChains } from '../supported-chains.ts'
2
- import type { CCIPVersion, Lane } from '../types.ts'
2
+ import type { CCIPVersion, Lane, WithLogger } from '../types.ts'
3
3
  import { networkInfo } from '../utils.ts'
4
4
  import type { LeafHasher } from './common.ts'
5
5
 
6
- // Factory function that returns the right encoder based on the version of the lane
7
- export function getLeafHasher<V extends CCIPVersion = CCIPVersion>(lane: Lane<V>): LeafHasher<V> {
6
+ /**
7
+ * Factory function that returns the right encoder based on the version of the lane.
8
+ * @param lane - Lane configuration.
9
+ * @param ctx - Context object containing logger.
10
+ * @returns Leaf hasher function for the destination chain.
11
+ */
12
+ export function getLeafHasher<V extends CCIPVersion = CCIPVersion>(
13
+ lane: Lane<V>,
14
+ ctx?: WithLogger,
15
+ ): LeafHasher<V> {
8
16
  const destFamily = networkInfo(lane.destChainSelector).family
9
17
  const chain = supportedChains[destFamily]
10
18
  if (!chain) throw new Error(`Unsupported chain family: ${destFamily}`)
11
- return chain.getDestLeafHasher(lane) as LeafHasher<V>
19
+ return chain.getDestLeafHasher(lane, ctx) as LeafHasher<V>
12
20
  }
@@ -13,12 +13,16 @@ interface SingleLayerProof {
13
13
 
14
14
  /**
15
15
  * Proof represents a proof data structure with hashes and source flags.
16
- * @template Hash The hash type.
17
16
  */
18
17
  export class Proof {
19
18
  hashes: Hash[] = []
20
19
  sourceFlags: boolean[] = []
21
20
 
21
+ /**
22
+ * Creates a new Proof instance.
23
+ * @param hashes - Proof hashes.
24
+ * @param sourceFlags - Source flags indicating leaf vs internal nodes.
25
+ */
22
26
  constructor(hashes: Hash[] = [], sourceFlags: boolean[] = []) {
23
27
  this.hashes = hashes
24
28
  this.sourceFlags = sourceFlags
@@ -26,7 +30,7 @@ export class Proof {
26
30
 
27
31
  /**
28
32
  * Counts the number of source flags that match the given boolean value.
29
- * @param b The boolean value to count.
33
+ * @param b - The boolean value to count.
30
34
  * @returns The count of source flags matching the provided boolean value.
31
35
  */
32
36
  countSourceFlags(b: boolean): number {
@@ -41,9 +45,8 @@ export class Proof {
41
45
  * It processes the `layer` to generate the next layer of hash values, pairing adjacent values
42
46
  * and applying the hashing function provided by the context.
43
47
  *
44
- * @template Hash - Generic type parameter representing the hash type.
45
- * @param {Hash[]} layer - An array of hash values representing the current layer of the binary tree.
46
- * @returns {[Hash[], Hash[]]} A tuple containing two arrays:
48
+ * @param layer - An array of hash values representing the current layer of the binary tree.
49
+ * @returns A tuple containing two arrays:
47
50
  * - The first array contains the original input layer.
48
51
  * - The second array contains the next layer of hash values generated by combining pairs of hashes.
49
52
  */
@@ -65,7 +68,7 @@ function computeNextLayer(layer: Hash[]): readonly [Hash[], Hash[]] {
65
68
 
66
69
  /**
67
70
  * Calculates the parent index of a given index in a binary tree.
68
- * @param idx The index for which to calculate the parent index.
71
+ * @param idx - The index for which to calculate the parent index.
69
72
  * @returns The parent index.
70
73
  */
71
74
  function parentIndex(idx: number): number {
@@ -74,7 +77,7 @@ function parentIndex(idx: number): number {
74
77
 
75
78
  /**
76
79
  * Calculates the sibling index of a given index in a binary tree.
77
- * @param idx The index for which to calculate the sibling index.
80
+ * @param idx - The index for which to calculate the sibling index.
78
81
  * @returns The sibling index.
79
82
  */
80
83
  function siblingIndex(idx: number): number {
@@ -83,8 +86,8 @@ function siblingIndex(idx: number): number {
83
86
 
84
87
  /**
85
88
  * Generates a single-layer Merkle proof for a given set of indices within a layer.
86
- * @param layer The layer of data for which to generate the proof.
87
- * @param indices The indices within the layer for which to generate the proof.
89
+ * @param layer - The layer of data for which to generate the proof.
90
+ * @param indices - The indices within the layer for which to generate the proof.
88
91
  * @returns A single-layer proof object containing nextIndices, subProof, and sourceFlags.
89
92
  */
90
93
  function proveSingleLayer(layer: Hash[], indices: number[]): SingleLayerProof {
@@ -131,14 +134,13 @@ function proveSingleLayer(layer: Hash[], indices: number[]): SingleLayerProof {
131
134
 
132
135
  /**
133
136
  * Represents a Merkle Tree data structure.
134
- * @typeparam Hash The type of hash used in the tree.
135
137
  */
136
138
  export class Tree {
137
139
  layers: Hash[][]
138
140
 
139
141
  /**
140
142
  * Creates a new Merkle Tree using the provided context and leaf hashes.
141
- * @param leafHashes An array of leaf hashes to construct the tree.
143
+ * @param leafHashes - An array of leaf hashes to construct the tree.
142
144
  * @returns A new Merkle Tree instance.
143
145
  * @throws Error if there are no leaf hashes provided.
144
146
  */
@@ -177,7 +179,7 @@ export class Tree {
177
179
 
178
180
  /**
179
181
  * Generates a Merkle proof for a set of indices in the tree.
180
- * @param indices The indices for which to generate the proof.
182
+ * @param indices - The indices for which to generate the proof.
181
183
  * @returns A proof object containing hashes and source flags.
182
184
  */
183
185
  prove(indices: number[]): Proof {
@@ -197,7 +199,7 @@ export class Tree {
197
199
 
198
200
  /**
199
201
  * Converts an array of boolean proof flags to a BigNumber where each flag represents a bit.
200
- * @param proofFlags An array of boolean proof flags.
202
+ * @param proofFlags - An array of boolean proof flags.
201
203
  * @returns A BigNumber representing the encoded flags.
202
204
  */
203
205
  export function proofFlagsToBits(proofFlags: boolean[]): bigint {
@@ -216,9 +218,8 @@ export function proofFlagsToBits(proofFlags: boolean[]): bigint {
216
218
 
217
219
  /**
218
220
  * Verifies and computes the Merkle root hash based on provided leaf hashes and a Merkle proof.
219
- * @param ctx The Merkle context.
220
- * @param leafHashes An array of leaf hashes.
221
- * @param proof The Merkle proof containing hashes and source flags.
221
+ * @param leafHashes - An array of leaf hashes.
222
+ * @param proof - The Merkle proof containing hashes and source flags.
222
223
  * @returns The computed Merkle root hash.
223
224
  */
224
225
  export function verifyComputeRoot(leafHashes: Hash[], proof: Proof): Hash {
package/src/index.ts CHANGED
@@ -1,16 +1,12 @@
1
- export { AptosChain } from './aptos/index.ts'
2
- export {
3
- type Chain,
4
- type ChainGetter,
5
- type ChainStatic,
6
- type ChainTransaction,
7
- type LogFilter,
8
- type RateLimiterState,
9
- type TokenInfo,
10
- type TokenPoolRemote,
11
- ChainFamily,
1
+ export type {
2
+ Chain,
3
+ ChainGetter,
4
+ ChainStatic,
5
+ LogFilter,
6
+ RateLimiterState,
7
+ TokenInfo,
8
+ TokenPoolRemote,
12
9
  } from './chain.ts'
13
- export { EVMChain } from './evm/index.ts'
14
10
  export { calculateManualExecProof, discoverOffRamp } from './execution.ts'
15
11
  export {
16
12
  type EVMExtraArgsV1,
@@ -22,30 +18,40 @@ export {
22
18
  encodeExtraArgs,
23
19
  } from './extra-args.ts'
24
20
  export { estimateExecGasForRequest } from './gas.ts'
25
- export {
26
- decodeMessage,
27
- fetchAllMessagesInBatch,
28
- fetchCCIPMessageById,
29
- fetchCCIPRequestsInTx,
30
- fetchRequestsForSender,
31
- sourceToDestTokenAmounts,
32
- } from './requests.ts'
33
- export { SolanaChain } from './solana/index.ts'
34
- export { SuiChain } from './sui/index.ts'
35
- export { supportedChains } from './supported-chains.ts'
21
+ export { decodeMessage, fetchRequestsForSender, sourceToDestTokenAmounts } from './requests.ts'
36
22
  export {
37
23
  type AnyMessage,
38
24
  type CCIPCommit,
39
25
  type CCIPExecution,
40
26
  type CCIPMessage,
41
27
  type CCIPRequest,
28
+ type ChainTransaction,
42
29
  type CommitReport,
43
30
  type ExecutionReceipt,
44
31
  type ExecutionReport,
45
32
  type Lane,
33
+ type Logger,
46
34
  type NetworkInfo,
47
35
  type OffchainTokenData,
36
+ type WithLogger,
48
37
  CCIPVersion,
49
38
  ExecutionState,
50
39
  } from './types.ts'
51
40
  export { bigIntReplacer, bigIntReviver, decodeAddress, getDataBytes, networkInfo } from './utils.ts'
41
+
42
+ // chains
43
+ import { AptosChain } from './aptos/index.ts'
44
+ import { EVMChain } from './evm/index.ts'
45
+ import { SolanaChain } from './solana/index.ts'
46
+ import { SuiChain } from './sui/index.ts'
47
+ import { ChainFamily } from './types.ts'
48
+ export { AptosChain, ChainFamily, EVMChain, SolanaChain, SuiChain }
49
+ // use `supportedChains` to override/register derived classes, if needed
50
+ export { supportedChains } from './supported-chains.ts'
51
+ // import `allSupportedChains` to get them all registered, in tree-shaken environments
52
+ export const allSupportedChains = {
53
+ [ChainFamily.EVM]: EVMChain,
54
+ [ChainFamily.Solana]: SolanaChain,
55
+ [ChainFamily.Aptos]: AptosChain,
56
+ [ChainFamily.Sui]: SuiChain,
57
+ }
package/src/requests.ts CHANGED
@@ -1,20 +1,20 @@
1
- import util from 'util'
2
-
3
1
  import { isBytesLike, toBigInt } from 'ethers'
2
+ import type { PickDeep } from 'type-fest'
4
3
  import yaml from 'yaml'
5
4
 
6
- import {
7
- type Chain,
8
- type ChainStatic,
9
- type ChainTransaction,
10
- type LogFilter,
11
- ChainFamily,
12
- } from './chain.ts'
5
+ import type { Chain, ChainStatic, LogFilter } from './chain.ts'
13
6
  import type { EVMChain } from './evm/index.ts'
14
7
  import { decodeExtraArgs } from './extra-args.ts'
15
8
  import { supportedChains } from './supported-chains.ts'
16
- import type { CCIPMessage, CCIPRequest, CCIPVersion, Log_ } from './types.ts'
17
- import { convertKeysToCamelCase, decodeAddress, leToBigInt, networkInfo } from './utils.ts'
9
+ import {
10
+ type CCIPMessage,
11
+ type CCIPRequest,
12
+ type CCIPVersion,
13
+ type ChainTransaction,
14
+ type Log_,
15
+ ChainFamily,
16
+ } from './types.ts'
17
+ import { convertKeysToCamelCase, decodeAddress, leToBigInt, networkInfo, util } from './utils.ts'
18
18
 
19
19
  function decodeJsonMessage(data: Record<string, unknown>) {
20
20
  if (!data || typeof data != 'object') throw new Error(`invalid msg: ${util.inspect(data)}`)
@@ -113,13 +113,15 @@ export function decodeMessage(data: string | Uint8Array | Record<string, unknown
113
113
 
114
114
  /**
115
115
  * Fetch all CCIP messages in a transaction
116
- * @param tx - TransactionReceipt to search in
117
- * @returns CCIP messages in the transaction (at least one)
116
+ * @param source - Chain
117
+ * @param tx - ChainTransaction to search in
118
+ * @returns CCIP requests (messages) in the transaction (at least one)
118
119
  **/
119
- export async function fetchCCIPRequestsInTx(tx: ChainTransaction): Promise<CCIPRequest[]> {
120
- const source = tx.chain
120
+ export async function fetchCCIPRequestsInTx(
121
+ source: Chain,
122
+ tx: ChainTransaction,
123
+ ): Promise<CCIPRequest[]> {
121
124
  const txHash = tx.hash
122
- const timestamp = tx.timestamp
123
125
 
124
126
  const requests: CCIPRequest[] = []
125
127
  for (const log of tx.logs) {
@@ -139,7 +141,7 @@ export async function fetchCCIPRequestsInTx(tx: ChainTransaction): Promise<CCIPR
139
141
  } else {
140
142
  lane = await (source as EVMChain).getLaneForOnRamp(log.address)
141
143
  }
142
- requests.push({ lane, message, log, tx, timestamp })
144
+ requests.push({ lane, message, log, tx })
143
145
  }
144
146
  if (!requests.length) {
145
147
  throw new Error(`Could not find any CCIPSendRequested message in tx: ${txHash}`)
@@ -149,23 +151,21 @@ export async function fetchCCIPRequestsInTx(tx: ChainTransaction): Promise<CCIPR
149
151
  }
150
152
 
151
153
  /**
152
- * Fetch a CCIP message by its messageId
153
- * Can be slow due to having to paginate backwards through logs
154
- *
155
- * @param source - Provider to fetch logs from
156
- * @param messageId - messageId to search for
157
- * @param hints - Optional hints for pagination
158
- * @returns CCIPRequest with given messageId
159
- **/
160
- export async function fetchCCIPMessageById(
154
+ * Fetch a CCIP message by its messageId.
155
+ * Can be slow due to having to paginate backwards through logs.
156
+ * @param source - Provider to fetch logs from.
157
+ * @param messageId - MessageId to search for.
158
+ * @param hints - Optional hints for pagination (e.g., `address` for onRamp, `page` for pagination size).
159
+ * @returns CCIPRequest with given messageId.
160
+ */
161
+ export async function fetchCCIPRequestById(
161
162
  source: Chain,
162
163
  messageId: string,
163
- hints?: { page?: number; onRamp?: string },
164
+ hints?: { page?: number; address?: string },
164
165
  ): Promise<CCIPRequest> {
165
166
  for await (const log of source.getLogs({
166
- ...hints,
167
- ...(hints?.onRamp ? { address: hints.onRamp } : {}),
168
167
  topics: ['CCIPSendRequested', 'CCIPMessageSent'],
168
+ ...hints,
169
169
  })) {
170
170
  const message = (source.constructor as ChainStatic).decodeMessage(log)
171
171
  if (message?.header.messageId !== messageId) continue
@@ -173,12 +173,10 @@ export async function fetchCCIPMessageById(
173
173
  if ('destChainSelector' in message.header) {
174
174
  destChainSelector = message.header.destChainSelector
175
175
  ;[, version] = await source.typeAndVersion(log.address)
176
- } else if (source.network.family !== ChainFamily.EVM) {
177
- throw new Error(`Unsupported network family: ${source.network.family}`)
178
176
  } else {
179
177
  ;({ destChainSelector, version } = await (source as EVMChain).getLaneForOnRamp(log.address))
180
178
  }
181
- const tx = await source.getTransaction(log.transactionHash)
179
+ const tx = log.tx ?? (await source.getTransaction(log.transactionHash))
182
180
  return {
183
181
  lane: {
184
182
  sourceChainSelector: source.network.chainSelector,
@@ -189,7 +187,6 @@ export async function fetchCCIPMessageById(
189
187
  message,
190
188
  log,
191
189
  tx,
192
- timestamp: tx.timestamp,
193
190
  }
194
191
  }
195
192
  throw new Error('Could not find a CCIPSendRequested message with messageId: ' + messageId)
@@ -198,19 +195,33 @@ export async function fetchCCIPMessageById(
198
195
  // Number of blocks to expand the search window for logs
199
196
  const BLOCK_LOG_WINDOW_SIZE = 5000
200
197
 
201
- // Helper function to find the sequence number from CCIPSendRequested event logs
202
- export async function fetchAllMessagesInBatch<R extends Omit<CCIPRequest, 'tx' | 'timestamp'>>(
203
- source: Chain,
198
+ /**
199
+ * Fetches all CCIP messages contained in a given commit batch.
200
+ * @param source - The source chain.
201
+ * @param request - The CCIP request containing lane and message info.
202
+ * @param seqNrRange - Object containing minSeqNr and maxSeqNr for the batch range.
203
+ * @param opts - Optional log filtering parameters.
204
+ * @returns Array of messages in the batch.
205
+ */
206
+ export async function fetchAllMessagesInBatch<
207
+ C extends Chain,
208
+ R extends PickDeep<
209
+ CCIPRequest,
210
+ 'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.header.sequenceNumber'
211
+ >,
212
+ >(
213
+ source: C,
204
214
  request: R,
205
215
  { minSeqNr, maxSeqNr }: { minSeqNr: bigint; maxSeqNr: bigint },
206
- { page: eventsBatchSize = BLOCK_LOG_WINDOW_SIZE }: { page?: number } = {},
216
+ opts: Parameters<C['getLogs']>[0] = { page: BLOCK_LOG_WINDOW_SIZE },
207
217
  ): Promise<R['message'][]> {
208
218
  if (minSeqNr === maxSeqNr) return [request.message]
209
219
 
210
- const filter: LogFilter = {
211
- page: eventsBatchSize,
220
+ const filter = {
221
+ page: BLOCK_LOG_WINDOW_SIZE,
212
222
  topics: [request.log.topics[0]],
213
223
  address: request.log.address,
224
+ ...opts,
214
225
  }
215
226
  if (request.message.header.sequenceNumber === maxSeqNr) filter.endBlock = request.log.blockNumber
216
227
  else
@@ -219,7 +230,7 @@ export async function fetchAllMessagesInBatch<R extends Omit<CCIPRequest, 'tx' |
219
230
  request.log.blockNumber -
220
231
  Math.ceil(
221
232
  (Number(request.message.header.sequenceNumber - minSeqNr) / Number(maxSeqNr - minSeqNr)) *
222
- eventsBatchSize,
233
+ filter.page,
223
234
  )
224
235
 
225
236
  const messages: R['message'][] = []
@@ -270,6 +281,13 @@ export async function fetchAllMessagesInBatch<R extends Omit<CCIPRequest, 'tx' |
270
281
  return messages
271
282
  }
272
283
 
284
+ /**
285
+ * Fetches CCIP requests originated by a specific sender.
286
+ * @param source - Source chain instance.
287
+ * @param sender - Sender address.
288
+ * @param filter - Log filter options.
289
+ * @returns Async generator of CCIP requests.
290
+ */
273
291
  export async function* fetchRequestsForSender(
274
292
  source: Chain,
275
293
  sender: string,
@@ -306,12 +324,12 @@ export async function* fetchRequestsForSender(
306
324
  }
307
325
 
308
326
  /**
309
- * Map source `token` to `sourcePoolAddress + destTokenAddress`
310
- * @param source - source chain
311
- * @param destChainSelector - dest network
312
- * @param onRamp - contract address
313
- * @param sourceTokenAmounts - usually `{ token, amount }`
314
- * @returns - { sourcePoolAddress, destTokenAddress, ...rest } objects
327
+ * Map source `token` to `sourcePoolAddress + destTokenAddress`.
328
+ * @param source - Source chain.
329
+ * @param destChainSelector - Destination network selector.
330
+ * @param onRamp - Contract address.
331
+ * @param sourceTokenAmounts - Array of token amounts, usually containing `token` and `amount` properties.
332
+ * @returns Array of objects with `sourcePoolAddress`, `destTokenAddress`, and remaining properties.
315
333
  */
316
334
  export async function sourceToDestTokenAmounts<S extends { token: string }>(
317
335
  source: Chain,
package/src/selectors.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ChainFamily } from './chain.ts'
1
+ import type { ChainFamily } from './types.ts'
2
2
 
3
3
  type Selectors = Record<
4
4
  string,
@@ -1,37 +1,46 @@
1
- import { type AnchorProvider, Program } from '@coral-xyz/anchor'
2
- import { AddressLookupTableProgram, PublicKey, SystemProgram } from '@solana/web3.js'
1
+ import { Buffer } from 'buffer'
2
+
3
+ import { type Wallet as AnchorWallet, AnchorProvider, Program } from '@coral-xyz/anchor'
4
+ import {
5
+ type Connection,
6
+ AddressLookupTableProgram,
7
+ PublicKey,
8
+ SystemProgram,
9
+ } from '@solana/web3.js'
3
10
  import { dataSlice, hexlify } from 'ethers'
4
- import moize from 'moize'
11
+ import { memoize } from 'micro-memoize'
5
12
 
6
13
  import { sleep } from '../utils.ts'
7
14
  import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
8
15
  import type { SolanaChain } from './index.ts'
9
- import { simulateAndSendTxs } from './send.ts'
16
+ import type { Wallet } from './types.ts'
17
+ import { simulateAndSendTxs } from './utils.ts'
18
+ import type { WithLogger } from '../types.ts'
10
19
 
11
20
  /**
12
- * Clean up and recycle buffers and address lookup tables owned by wallet
13
- * CAUTION: this will close ANY lookup table owned by this wallet
14
- * @param provider - AnchorProvider with connection and wallet
15
- * @param getLogs - SolanaChain-compatible getLogs function (to scan for Buffers and ALTs)
16
- * @param opts.dontWait - Whether to skip waiting for lookup table deactivation cool down period
17
- * (513 slots) to pass before closing; by default, we deactivate (if needed) and wait to close
18
- * before returning from this method
21
+ * Clean up and recycle buffers and Address Lookup Tables owned by wallet.
22
+ * @param ctx - Context object containing the Solana connection instance and logger.
23
+ * @param wallet - Wallet instance to sign txs.
24
+ * @param getLogs - SolanaChain-compatible getLogs function (to scan for Buffers and ALTs).
25
+ * @param opts - Optional parameters. Set `waitDeactivation` to wait for lookup table deactivation
26
+ * cool down period (513 slots) to pass before closing; by default, we deactivate (if needed)
27
+ * and leave close to be done in the future.
19
28
  */
20
29
  export async function cleanUpBuffers(
21
- provider: AnchorProvider,
30
+ ctx: { connection: Connection } & WithLogger,
31
+ wallet: Wallet,
22
32
  getLogs: SolanaChain['getLogs'],
23
- opts?: { dontWait?: boolean },
33
+ opts?: { waitDeactivation?: boolean },
24
34
  ): Promise<void> {
25
- const connection = provider.connection
26
- const wallet = provider.wallet
27
- console.debug(
35
+ const { connection, logger = console } = ctx
36
+ logger.debug(
28
37
  'Starting cleaning up buffers and lookup tables for account',
29
38
  wallet.publicKey.toString(),
30
39
  )
31
40
 
32
41
  const seenAccs = new Set<string>()
33
42
  const pendingPromises = []
34
- const getCurrentSlot = moize.default(
43
+ const getCurrentSlot = memoize(
35
44
  async () => {
36
45
  let lastErr
37
46
  for (let i = 0; i < 10; i++) {
@@ -39,13 +48,13 @@ export async function cleanUpBuffers(
39
48
  return await connection.getSlot()
40
49
  } catch (err) {
41
50
  lastErr = err
42
- console.warn('Failed to get current slot', i, err)
51
+ logger.warn('Failed to get current slot', i, err)
43
52
  await sleep(500)
44
53
  }
45
54
  }
46
55
  throw lastErr
47
56
  },
48
- { maxAge: 1000, isPromise: true },
57
+ { maxAge: 1000, async: true },
49
58
  )
50
59
 
51
60
  const closeAlt = async (lookupTable: PublicKey, deactivationSlot: number) => {
@@ -54,8 +63,8 @@ export async function cleanUpBuffers(
54
63
  while (!sig) {
55
64
  const delta = deactivationSlot + 513 - (await getCurrentSlot())
56
65
  if (delta > 0) {
57
- if (opts?.dontWait) {
58
- console.warn(
66
+ if (!opts?.waitDeactivation) {
67
+ logger.warn(
59
68
  'Skipping: lookup table',
60
69
  altAddr,
61
70
  'not yet ready for close until',
@@ -64,7 +73,7 @@ export async function cleanUpBuffers(
64
73
  )
65
74
  return
66
75
  }
67
- console.debug(
76
+ logger.debug(
68
77
  'Waiting for slot',
69
78
  deactivationSlot + 513,
70
79
  'to be reached in',
@@ -81,14 +90,14 @@ export async function cleanUpBuffers(
81
90
  lookupTable,
82
91
  })
83
92
  try {
84
- sig = await simulateAndSendTxs(connection, wallet, [closeIx])
85
- console.info('🗑️ Closed lookup table', altAddr, ': tx =>', sig)
93
+ sig = await simulateAndSendTxs(ctx, wallet, { instructions: [closeIx] })
94
+ logger.info('🗑️ Closed lookup table', altAddr, ': tx =>', sig)
86
95
  } catch (err) {
87
96
  const info = await connection.getAddressLookupTable(lookupTable)
88
97
  if (!info?.value) break
89
98
  else if (info.value.state.deactivationSlot < 2n ** 63n)
90
99
  deactivationSlot = Number(info.value.state.deactivationSlot)
91
- console.warn('Failed to close lookup table', altAddr, err)
100
+ logger.warn('Failed to close lookup table', altAddr, err)
92
101
  }
93
102
  }
94
103
  }
@@ -114,7 +123,11 @@ export async function cleanUpBuffers(
114
123
  .map(({ data }) => Buffer.from(data.subarray(8 + 4, 8 + 4 + 32)))
115
124
 
116
125
  for (const bufferId of bufferIds) {
117
- const offrampProgram = new Program(CCIP_OFFRAMP_IDL, new PublicKey(log.address), provider)
126
+ const offrampProgram = new Program(
127
+ CCIP_OFFRAMP_IDL,
128
+ new PublicKey(log.address),
129
+ new AnchorProvider(connection, wallet as AnchorWallet, { commitment: 'confirmed' }),
130
+ )
118
131
 
119
132
  const [executionReportBuffer] = PublicKey.findProgramAddressSync(
120
133
  [Buffer.from('execution_report_buffer'), bufferId, wallet.publicKey.toBuffer()],
@@ -125,7 +138,7 @@ export async function cleanUpBuffers(
125
138
 
126
139
  const accInfo = await connection.getAccountInfo(executionReportBuffer)
127
140
  if (!accInfo) {
128
- console.debug(
141
+ logger.debug(
129
142
  'Buffer with bufferId',
130
143
  hexlify(bufferId),
131
144
  'at',
@@ -148,7 +161,7 @@ export async function cleanUpBuffers(
148
161
  .closeExecutionReportBuffer(bufferId)
149
162
  .accounts(bufferingAccounts)
150
163
  .rpc()
151
- console.info(
164
+ logger.info(
152
165
  '🗑️ Closed bufferId',
153
166
  hexlify(bufferId),
154
167
  'at',
@@ -157,7 +170,7 @@ export async function cleanUpBuffers(
157
170
  sig,
158
171
  )
159
172
  } catch (err) {
160
- console.warn(
173
+ logger.warn(
161
174
  'Failed to close bufferId',
162
175
  hexlify(bufferId),
163
176
  'at',
@@ -177,9 +190,9 @@ export async function cleanUpBuffers(
177
190
  const info = await connection.getAddressLookupTable(lookupTable)
178
191
  if (!info?.value) {
179
192
  alreadyClosed++ // assume we're done when we hit Nth closed ALT; maybe add an option to keep going?
180
- console.debug('Lookup table', lookupTable.toBase58(), 'already closed')
193
+ logger.debug('Lookup table', lookupTable.toBase58(), 'already closed')
181
194
  } else if (info.value.state.authority?.toBase58() !== wallet.publicKey.toBase58()) {
182
- console.debug(
195
+ logger.debug(
183
196
  'Lookup table',
184
197
  lookupTable.toBase58(),
185
198
  'not owned by us, but by',
@@ -199,11 +212,13 @@ export async function cleanUpBuffers(
199
212
  })
200
213
 
201
214
  try {
202
- const sig = await simulateAndSendTxs(connection, wallet, [deactivateIx])
203
- console.info('⤵️ Deactivated lookup table', lookupTable.toBase58(), ': tx =>', sig)
215
+ const sig = await simulateAndSendTxs(ctx, wallet, {
216
+ instructions: [deactivateIx],
217
+ })
218
+ logger.info('⤵️ Deactivated lookup table', lookupTable.toBase58(), ': tx =>', sig)
204
219
  pendingPromises.push(closeAlt(lookupTable, await getCurrentSlot()))
205
220
  } catch (err) {
206
- console.warn('Failed to deactivate lookup table', lookupTable.toBase58(), err)
221
+ logger.warn('Failed to deactivate lookup table', lookupTable.toBase58(), err)
207
222
  }
208
223
  }
209
224
  break // case