@chainlink/ccip-sdk 0.97.0 → 1.1.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 (166) hide show
  1. package/README.md +12 -9
  2. package/dist/api/index.d.ts +7 -3
  3. package/dist/api/index.d.ts.map +1 -1
  4. package/dist/api/index.js +124 -13
  5. package/dist/api/index.js.map +1 -1
  6. package/dist/api/types.d.ts +34 -0
  7. package/dist/api/types.d.ts.map +1 -1
  8. package/dist/aptos/index.d.ts +4 -6
  9. package/dist/aptos/index.d.ts.map +1 -1
  10. package/dist/aptos/index.js +0 -5
  11. package/dist/aptos/index.js.map +1 -1
  12. package/dist/aptos/logs.d.ts +2 -2
  13. package/dist/aptos/logs.d.ts.map +1 -1
  14. package/dist/chain.d.ts +104 -16
  15. package/dist/chain.d.ts.map +1 -1
  16. package/dist/chain.js +97 -9
  17. package/dist/chain.js.map +1 -1
  18. package/dist/errors/codes.d.ts +1 -1
  19. package/dist/errors/codes.d.ts.map +1 -1
  20. package/dist/errors/codes.js +2 -1
  21. package/dist/errors/codes.js.map +1 -1
  22. package/dist/errors/index.d.ts +5 -5
  23. package/dist/errors/index.d.ts.map +1 -1
  24. package/dist/errors/index.js +5 -5
  25. package/dist/errors/index.js.map +1 -1
  26. package/dist/errors/recovery.js +1 -1
  27. package/dist/errors/recovery.js.map +1 -1
  28. package/dist/errors/specialized.d.ts +22 -19
  29. package/dist/errors/specialized.d.ts.map +1 -1
  30. package/dist/errors/specialized.js +30 -25
  31. package/dist/errors/specialized.js.map +1 -1
  32. package/dist/evm/abi/OffRamp_2_0.d.ts +24 -12
  33. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -1
  34. package/dist/evm/abi/OffRamp_2_0.js +16 -8
  35. package/dist/evm/abi/OffRamp_2_0.js.map +1 -1
  36. package/dist/evm/abi/OnRamp_2_0.d.ts +1 -1
  37. package/dist/evm/abi/OnRamp_2_0.js +1 -1
  38. package/dist/evm/abi/OnRamp_2_0.js.map +1 -1
  39. package/dist/evm/abi/TokenPool_2_0.d.ts +1552 -0
  40. package/dist/evm/abi/TokenPool_2_0.d.ts.map +1 -0
  41. package/dist/evm/abi/TokenPool_2_0.js +1637 -0
  42. package/dist/evm/abi/TokenPool_2_0.js.map +1 -0
  43. package/dist/evm/const.d.ts +1 -0
  44. package/dist/evm/const.d.ts.map +1 -1
  45. package/dist/evm/const.js +2 -0
  46. package/dist/evm/const.js.map +1 -1
  47. package/dist/evm/index.d.ts +11 -7
  48. package/dist/evm/index.d.ts.map +1 -1
  49. package/dist/evm/index.js +139 -46
  50. package/dist/evm/index.js.map +1 -1
  51. package/dist/evm/logs.d.ts +1 -1
  52. package/dist/evm/logs.js +1 -1
  53. package/dist/evm/messages.d.ts +2 -33
  54. package/dist/evm/messages.d.ts.map +1 -1
  55. package/dist/evm/messages.js +0 -210
  56. package/dist/evm/messages.js.map +1 -1
  57. package/dist/evm/offchain.d.ts +1 -14
  58. package/dist/evm/offchain.d.ts.map +1 -1
  59. package/dist/evm/offchain.js +1 -133
  60. package/dist/evm/offchain.js.map +1 -1
  61. package/dist/gas.d.ts +4 -0
  62. package/dist/gas.d.ts.map +1 -1
  63. package/dist/gas.js +27 -21
  64. package/dist/gas.js.map +1 -1
  65. package/dist/index.d.ts +5 -4
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +3 -2
  68. package/dist/index.js.map +1 -1
  69. package/dist/messages.d.ts +34 -0
  70. package/dist/messages.d.ts.map +1 -0
  71. package/dist/messages.js +211 -0
  72. package/dist/messages.js.map +1 -0
  73. package/dist/offchain.d.ts +23 -6
  74. package/dist/offchain.d.ts.map +1 -1
  75. package/dist/offchain.js +92 -17
  76. package/dist/offchain.js.map +1 -1
  77. package/dist/requests.d.ts.map +1 -1
  78. package/dist/requests.js +0 -1
  79. package/dist/requests.js.map +1 -1
  80. package/dist/solana/cleanup.js +2 -2
  81. package/dist/solana/cleanup.js.map +1 -1
  82. package/dist/solana/exec.js +1 -1
  83. package/dist/solana/exec.js.map +1 -1
  84. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts +1 -1
  85. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js +1 -1
  86. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts +1 -1
  87. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js +1 -1
  88. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts +1 -1
  89. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js +1 -1
  90. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts +16 -1
  91. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts.map +1 -1
  92. package/dist/solana/idl/1.6.0/CCIP_COMMON.js +16 -1
  93. package/dist/solana/idl/1.6.0/CCIP_COMMON.js.map +1 -1
  94. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts +1 -1
  95. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js +1 -1
  96. package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts +1 -1
  97. package/dist/solana/idl/1.6.0/CCIP_ROUTER.js +1 -1
  98. package/dist/solana/index.d.ts +25 -27
  99. package/dist/solana/index.d.ts.map +1 -1
  100. package/dist/solana/index.js +16 -7
  101. package/dist/solana/index.js.map +1 -1
  102. package/dist/solana/offchain.d.ts +1 -13
  103. package/dist/solana/offchain.d.ts.map +1 -1
  104. package/dist/solana/offchain.js +1 -66
  105. package/dist/solana/offchain.js.map +1 -1
  106. package/dist/solana/utils.d.ts +4 -4
  107. package/dist/solana/utils.d.ts.map +1 -1
  108. package/dist/solana/utils.js +1 -1
  109. package/dist/solana/utils.js.map +1 -1
  110. package/dist/sui/index.d.ts +4 -6
  111. package/dist/sui/index.d.ts.map +1 -1
  112. package/dist/sui/index.js +14 -6
  113. package/dist/sui/index.js.map +1 -1
  114. package/dist/ton/exec.d.ts +2 -2
  115. package/dist/ton/exec.d.ts.map +1 -1
  116. package/dist/ton/exec.js +1 -1
  117. package/dist/ton/exec.js.map +1 -1
  118. package/dist/ton/index.d.ts +5 -6
  119. package/dist/ton/index.d.ts.map +1 -1
  120. package/dist/ton/index.js +3 -5
  121. package/dist/ton/index.js.map +1 -1
  122. package/dist/ton/types.d.ts +3 -5
  123. package/dist/ton/types.d.ts.map +1 -1
  124. package/dist/ton/types.js.map +1 -1
  125. package/dist/types.d.ts +10 -10
  126. package/dist/types.d.ts.map +1 -1
  127. package/dist/types.js.map +1 -1
  128. package/package.json +11 -7
  129. package/src/api/index.ts +145 -17
  130. package/src/api/types.ts +43 -0
  131. package/src/aptos/index.ts +4 -11
  132. package/src/aptos/logs.ts +2 -2
  133. package/src/chain.ts +148 -23
  134. package/src/errors/codes.ts +2 -1
  135. package/src/errors/index.ts +4 -1
  136. package/src/errors/recovery.ts +1 -1
  137. package/src/errors/specialized.ts +35 -30
  138. package/src/evm/abi/OffRamp_2_0.ts +16 -8
  139. package/src/evm/abi/OnRamp_2_0.ts +1 -1
  140. package/src/evm/abi/TokenPool_2_0.ts +1636 -0
  141. package/src/evm/const.ts +2 -0
  142. package/src/evm/index.ts +234 -85
  143. package/src/evm/logs.ts +1 -1
  144. package/src/evm/messages.ts +3 -285
  145. package/src/evm/offchain.ts +2 -191
  146. package/src/gas.ts +27 -19
  147. package/src/index.ts +10 -2
  148. package/src/messages.ts +278 -0
  149. package/src/offchain.ts +125 -28
  150. package/src/requests.ts +2 -3
  151. package/src/solana/cleanup.ts +2 -2
  152. package/src/solana/exec.ts +1 -1
  153. package/src/solana/idl/1.6.0/BASE_TOKEN_POOL.ts +2 -2
  154. package/src/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.ts +2 -2
  155. package/src/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts +2 -2
  156. package/src/solana/idl/1.6.0/CCIP_COMMON.ts +32 -2
  157. package/src/solana/idl/1.6.0/CCIP_OFFRAMP.ts +2 -2
  158. package/src/solana/idl/1.6.0/CCIP_ROUTER.ts +2 -2
  159. package/src/solana/index.ts +27 -17
  160. package/src/solana/offchain.ts +3 -100
  161. package/src/solana/utils.ts +8 -5
  162. package/src/sui/index.ts +22 -12
  163. package/src/ton/exec.ts +3 -6
  164. package/src/ton/index.ts +15 -16
  165. package/src/ton/types.ts +3 -6
  166. package/src/types.ts +13 -10
@@ -3,25 +3,16 @@ import type {
3
3
  AbiParametersToPrimitiveTypes,
4
4
  ExtractAbiEvent,
5
5
  } from 'abitype'
6
- import {
7
- type Addressable,
8
- type BytesLike,
9
- type Result,
10
- dataSlice,
11
- hexlify,
12
- toBigInt,
13
- toNumber,
14
- } from 'ethers'
6
+ import type { Addressable, Result } from 'ethers'
15
7
  import type { Simplify } from 'type-fest'
16
8
 
17
- import { CCIPMessageDecodeError } from '../errors/index.ts'
18
9
  import type { EVMExtraArgsV2 } from '../extra-args.ts'
19
- import type { CCIPVersion, ChainFamily, MergeArrayElements } from '../types.ts'
20
- import { decodeAddress, getDataBytes, networkInfo } from '../utils.ts'
10
+ import type { CCIPVersion, MergeArrayElements } from '../types.ts'
21
11
  import type EVM2EVMOnRamp_1_5_ABI from './abi/OnRamp_1_5.ts'
22
12
  import type OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
23
13
  import type OnRamp_2_0_ABI from './abi/OnRamp_2_0.ts'
24
14
  import { defaultAbiCoder } from './const.ts'
15
+ import type { MessageV1 } from '../messages.ts'
25
16
 
26
17
  /** Utility type that cleans up address types to just `string`. */
27
18
  export type CleanAddressable<T> = T extends string | Addressable
@@ -32,279 +23,6 @@ export type CleanAddressable<T> = T extends string | Addressable
32
23
  ? { readonly [K in keyof T]: CleanAddressable<T[K]> }
33
24
  : T
34
25
 
35
- /** Token transfer in MessageV1 format. */
36
- export type TokenTransferV1 = {
37
- amount: bigint
38
- sourcePoolAddress: string
39
- sourceTokenAddress: string
40
- destTokenAddress: string
41
- tokenReceiver: string
42
- extraData: string
43
- }
44
-
45
- /** MessageV1 struct matching the Solidity MessageV1Codec format. */
46
- export type MessageV1 = {
47
- sourceChainSelector: bigint
48
- destChainSelector: bigint
49
- messageNumber: bigint
50
- executionGasLimit: number
51
- ccipReceiveGasLimit: number
52
- finality: number
53
- ccvAndExecutorHash: string
54
- onRampAddress: string
55
- offRampAddress: string
56
- sender: string
57
- receiver: string
58
- destBlob: string
59
- tokenTransfer: readonly TokenTransferV1[]
60
- data: string
61
- }
62
-
63
- /**
64
- * Decodes a TokenTransferV1 from bytes.
65
- * @param encoded - The encoded bytes.
66
- * @param offset - The starting offset.
67
- * @param sourceFamily - The source chain family for source addresses.
68
- * @param destFamily - The destination chain family for dest addresses.
69
- * @returns The decoded token transfer and the new offset.
70
- */
71
- function decodeTokenTransferV1(
72
- encoded: Uint8Array,
73
- offset: number,
74
- sourceFamily: ChainFamily,
75
- destFamily: ChainFamily,
76
- ): { tokenTransfer: TokenTransferV1; newOffset: number } {
77
- // version (1 byte)
78
- if (offset >= encoded.length) throw new CCIPMessageDecodeError('TOKEN_TRANSFER_VERSION')
79
- const version = encoded[offset++]!
80
- if (version !== 1) throw new CCIPMessageDecodeError(`Invalid encoding version: ${version}`)
81
-
82
- // amount (32 bytes)
83
- if (offset + 32 > encoded.length) throw new CCIPMessageDecodeError('TOKEN_TRANSFER_AMOUNT')
84
- const amount = toBigInt(dataSlice(encoded, offset, offset + 32))
85
- offset += 32
86
-
87
- // sourcePoolAddressLength and sourcePoolAddress
88
- if (offset >= encoded.length) {
89
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_POOL_LENGTH')
90
- }
91
- const sourcePoolAddressLength = encoded[offset++]!
92
- if (offset + sourcePoolAddressLength > encoded.length) {
93
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_POOL_CONTENT')
94
- }
95
- const sourcePoolAddress = decodeAddress(
96
- dataSlice(encoded, offset, offset + sourcePoolAddressLength),
97
- sourceFamily,
98
- )
99
- offset += sourcePoolAddressLength
100
-
101
- // sourceTokenAddressLength and sourceTokenAddress
102
- if (offset >= encoded.length) {
103
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_TOKEN_LENGTH')
104
- }
105
- const sourceTokenAddressLength = encoded[offset++]!
106
- if (offset + sourceTokenAddressLength > encoded.length) {
107
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_TOKEN_CONTENT')
108
- }
109
- const sourceTokenAddress = decodeAddress(
110
- dataSlice(encoded, offset, offset + sourceTokenAddressLength),
111
- sourceFamily,
112
- )
113
- offset += sourceTokenAddressLength
114
-
115
- // destTokenAddressLength and destTokenAddress
116
- if (offset >= encoded.length) {
117
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_DEST_TOKEN_LENGTH')
118
- }
119
- const destTokenAddressLength = encoded[offset++]!
120
- if (offset + destTokenAddressLength > encoded.length) {
121
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_DEST_TOKEN_CONTENT')
122
- }
123
- const destTokenAddress = decodeAddress(
124
- dataSlice(encoded, offset, offset + destTokenAddressLength),
125
- destFamily,
126
- )
127
- offset += destTokenAddressLength
128
-
129
- // tokenReceiverLength and tokenReceiver
130
- if (offset >= encoded.length) {
131
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_TOKEN_RECEIVER_LENGTH')
132
- }
133
- const tokenReceiverLength = encoded[offset++]!
134
- if (offset + tokenReceiverLength > encoded.length) {
135
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_TOKEN_RECEIVER_CONTENT')
136
- }
137
- const tokenReceiver = decodeAddress(
138
- dataSlice(encoded, offset, offset + tokenReceiverLength),
139
- destFamily,
140
- )
141
- offset += tokenReceiverLength
142
-
143
- // extraDataLength and extraData
144
- if (offset + 2 > encoded.length) {
145
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_EXTRA_DATA_LENGTH')
146
- }
147
- const extraDataLength = toNumber(dataSlice(encoded, offset, offset + 2))
148
- offset += 2
149
- if (offset + extraDataLength > encoded.length) {
150
- throw new CCIPMessageDecodeError('TOKEN_TRANSFER_EXTRA_DATA_CONTENT')
151
- }
152
- const extraData = hexlify(dataSlice(encoded, offset, offset + extraDataLength))
153
- offset += extraDataLength
154
-
155
- return {
156
- tokenTransfer: {
157
- amount,
158
- sourcePoolAddress,
159
- sourceTokenAddress,
160
- destTokenAddress,
161
- tokenReceiver,
162
- extraData,
163
- },
164
- newOffset: offset,
165
- }
166
- }
167
-
168
- /**
169
- * Decodes a MessageV1 from bytes following the v1 protocol format.
170
- * @param encodedMessage - The encoded message bytes to decode.
171
- * @returns The decoded MessageV1 struct.
172
- */
173
- export function decodeMessageV1(encodedMessage: BytesLike): MessageV1 {
174
- const MESSAGE_V1_BASE_SIZE = 77
175
- const encoded = getDataBytes(encodedMessage)
176
-
177
- if (encoded.length < MESSAGE_V1_BASE_SIZE) throw new CCIPMessageDecodeError('MESSAGE_MIN_SIZE')
178
-
179
- const version = encoded[0]!
180
- if (version !== 1) throw new CCIPMessageDecodeError(`Invalid encoding version: ${version}`)
181
-
182
- // sourceChainSelector (8 bytes, big endian)
183
- const sourceChainSelector = toBigInt(dataSlice(encoded, 1, 9))
184
-
185
- // destChainSelector (8 bytes, big endian)
186
- const destChainSelector = toBigInt(dataSlice(encoded, 9, 17))
187
-
188
- // Get chain families for address decoding
189
- const sourceNetworkInfo = networkInfo(sourceChainSelector)
190
- const destNetworkInfo = networkInfo(destChainSelector)
191
- const sourceFamily = sourceNetworkInfo.family
192
- const destFamily = destNetworkInfo.family
193
-
194
- // messageNumber (8 bytes, big endian)
195
- const messageNumber = toBigInt(dataSlice(encoded, 17, 25))
196
-
197
- // executionGasLimit (4 bytes, big endian)
198
- const executionGasLimit = toNumber(dataSlice(encoded, 25, 29))
199
-
200
- // ccipReceiveGasLimit (4 bytes, big endian)
201
- const ccipReceiveGasLimit = toNumber(dataSlice(encoded, 29, 33))
202
-
203
- // finality (2 bytes, big endian)
204
- const finality = toNumber(dataSlice(encoded, 33, 35))
205
-
206
- // ccvAndExecutorHash (32 bytes)
207
- const ccvAndExecutorHash = hexlify(dataSlice(encoded, 35, 67))
208
-
209
- // onRampAddressLength and onRampAddress
210
- let offset = 67
211
- if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_ONRAMP_ADDRESS_LENGTH')
212
- const onRampAddressLength = encoded[offset++]!
213
- if (offset + onRampAddressLength > encoded.length) {
214
- throw new CCIPMessageDecodeError('MESSAGE_ONRAMP_ADDRESS_CONTENT')
215
- }
216
- const onRampAddress = decodeAddress(
217
- dataSlice(encoded, offset, offset + onRampAddressLength),
218
- sourceFamily,
219
- )
220
- offset += onRampAddressLength
221
-
222
- // offRampAddressLength and offRampAddress
223
- if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_OFFRAMP_ADDRESS_LENGTH')
224
- const offRampAddressLength = encoded[offset++]!
225
- if (offset + offRampAddressLength > encoded.length) {
226
- throw new CCIPMessageDecodeError('MESSAGE_OFFRAMP_ADDRESS_CONTENT')
227
- }
228
- const offRampAddress = decodeAddress(
229
- dataSlice(encoded, offset, offset + offRampAddressLength),
230
- destFamily,
231
- )
232
- offset += offRampAddressLength
233
-
234
- // senderLength and sender
235
- if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_SENDER_LENGTH')
236
- const senderLength = encoded[offset++]!
237
- if (offset + senderLength > encoded.length) {
238
- throw new CCIPMessageDecodeError('MESSAGE_SENDER_CONTENT')
239
- }
240
- const sender = decodeAddress(dataSlice(encoded, offset, offset + senderLength), sourceFamily)
241
- offset += senderLength
242
-
243
- // receiverLength and receiver
244
- if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_RECEIVER_LENGTH')
245
- const receiverLength = encoded[offset++]!
246
- if (offset + receiverLength > encoded.length) {
247
- throw new CCIPMessageDecodeError('MESSAGE_RECEIVER_CONTENT')
248
- }
249
- const receiver = decodeAddress(dataSlice(encoded, offset, offset + receiverLength), destFamily)
250
- offset += receiverLength
251
-
252
- // destBlobLength and destBlob
253
- if (offset + 2 > encoded.length) throw new CCIPMessageDecodeError('MESSAGE_DEST_BLOB_LENGTH')
254
- const destBlobLength = toNumber(dataSlice(encoded, offset, offset + 2))
255
- offset += 2
256
- if (offset + destBlobLength > encoded.length) {
257
- throw new CCIPMessageDecodeError('MESSAGE_DEST_BLOB_CONTENT')
258
- }
259
- const destBlob = hexlify(dataSlice(encoded, offset, offset + destBlobLength))
260
- offset += destBlobLength
261
-
262
- // tokenTransferLength and tokenTransfer
263
- if (offset + 2 > encoded.length) throw new CCIPMessageDecodeError('MESSAGE_TOKEN_TRANSFER_LENGTH')
264
- const tokenTransferLength = toNumber(dataSlice(encoded, offset, offset + 2))
265
- offset += 2
266
-
267
- // Decode token transfer, which is either 0 or 1
268
- const tokenTransfer: TokenTransferV1[] = []
269
- if (tokenTransferLength > 0) {
270
- const expectedEnd = offset + tokenTransferLength
271
- const result = decodeTokenTransferV1(encoded, offset, sourceFamily, destFamily)
272
- tokenTransfer.push(result.tokenTransfer)
273
- offset = result.newOffset
274
- if (offset !== expectedEnd) throw new CCIPMessageDecodeError('MESSAGE_TOKEN_TRANSFER_CONTENT')
275
- }
276
-
277
- // dataLength and data
278
- if (offset + 2 > encoded.length) throw new CCIPMessageDecodeError('MESSAGE_DATA_LENGTH')
279
- const dataLength = toNumber(dataSlice(encoded, offset, offset + 2))
280
- offset += 2
281
- if (offset + dataLength > encoded.length) {
282
- throw new CCIPMessageDecodeError('MESSAGE_DATA_CONTENT')
283
- }
284
- const data = hexlify(dataSlice(encoded, offset, offset + dataLength))
285
- offset += dataLength
286
-
287
- // Ensure we've consumed all bytes
288
- if (offset !== encoded.length) throw new CCIPMessageDecodeError('MESSAGE_FINAL_OFFSET')
289
-
290
- return {
291
- sourceChainSelector,
292
- destChainSelector,
293
- messageNumber,
294
- executionGasLimit,
295
- ccipReceiveGasLimit,
296
- finality,
297
- ccvAndExecutorHash,
298
- onRampAddress,
299
- offRampAddress,
300
- sender,
301
- receiver,
302
- destBlob,
303
- tokenTransfer,
304
- data,
305
- }
306
- }
307
-
308
26
  // v1.2-v1.5 Message ()
309
27
  type EVM2AnyMessageRequested = CleanAddressable<
310
28
  AbiParametersToPrimitiveTypes<
@@ -1,90 +1,5 @@
1
- import { type Addressable, type Log, EventFragment } from 'ethers'
2
-
3
- import { getLbtcAttestation, getUsdcAttestation } from '../offchain.ts'
4
- import type {
5
- CCIPMessage,
6
- CCIPRequest,
7
- NetworkType,
8
- OffchainTokenData,
9
- WithLogger,
10
- } from '../types.ts'
11
- import { networkInfo } from '../utils.ts'
12
- import { defaultAbiCoder, interfaces, requestsFragments } from './const.ts'
13
- import { type SourceTokenData, parseSourceTokenData } from './messages.ts'
14
-
15
- const BURNED_EVENT_1_5 = interfaces.TokenPool_v1_5.getEvent('Burned')!
16
- const BURNED_EVENT_1_6 = interfaces.TokenPool_v1_6.getEvent('LockedOrBurned')!
17
- const BURNED_EVENT_TOPIC_HASHES = new Set([BURNED_EVENT_1_5.topicHash, BURNED_EVENT_1_6.topicHash])
18
-
19
- const USDC_EVENT = EventFragment.from('MessageSent(bytes message)')
20
- const TRANSFER_EVENT = EventFragment.from('Transfer(address from, address to, uint256 value)')
21
-
22
- export const LBTC_EVENT = EventFragment.from(
23
- 'DepositToBridge(address fromAddress, bytes32 toAddress, bytes32 payloadHash, bytes payload)',
24
- )
25
- export const LBTC_EVENT_V2 = EventFragment.from(
26
- 'DepositToBridge(address fromAddress, bytes32 toAddress, bytes32 payloadHash)',
27
- )
28
- const LBTC_EVENTS_HASHES = new Set([LBTC_EVENT.topicHash, LBTC_EVENT_V2.topicHash])
29
-
30
- /**
31
- * Fetch offchain token data for all transfers in request
32
- *
33
- * @param request - Request (or subset of) to fetch offchainTokenData for
34
- * @returns Array of byte arrays, one per transfer in request
35
- */
36
- export async function fetchEVMOffchainTokenData(
37
- request: Pick<CCIPRequest, 'tx'> & {
38
- message: CCIPMessage
39
- log: Pick<CCIPRequest['log'], 'index'>
40
- },
41
- ctx: WithLogger,
42
- ): Promise<OffchainTokenData[]> {
43
- const { networkType } = networkInfo(request.message.sourceChainSelector)
44
- // there's a chance there are other CCIPSendRequested in same tx,
45
- // and they may contain USDC transfers as well, so we select
46
- // any USDC logs after that and before our CCIPSendRequested
47
- const prevCcipRequestIdx =
48
- request.tx.logs.find(
49
- ({ topics, index }) => topics[0]! in requestsFragments && index < request.log.index,
50
- )?.index ?? -1
51
- const usdcRequestLogs = request.tx.logs.filter(
52
- ({ index }) => prevCcipRequestIdx < index && index < request.log.index,
53
- ) as Log[]
54
-
55
- const offchainTokenData: OffchainTokenData[] = request.message.tokenAmounts.map(
56
- () => undefined, // default tokenData
57
- )
58
- const usdcTokenData = await getUsdcTokenData(
59
- request.message.tokenAmounts,
60
- usdcRequestLogs,
61
- networkType,
62
- ctx,
63
- )
64
- let lbtcTokenData: OffchainTokenData[] = []
65
- try {
66
- let tokenAmounts
67
- if ('sourceTokenData' in request.message) {
68
- tokenAmounts = request.message.sourceTokenData.map(parseSourceTokenData)
69
- } else {
70
- tokenAmounts = request.message.tokenAmounts
71
- }
72
- //for lbtc we distinguish logs by hash in event, so we can pass all of them
73
- lbtcTokenData = await getLbtcTokenData(tokenAmounts, request.tx.logs as Log[], networkType, ctx)
74
- } catch (_) {
75
- // pass
76
- }
77
-
78
- for (let i = 0; i < offchainTokenData.length; i++) {
79
- if (usdcTokenData[i]) {
80
- offchainTokenData[i] = usdcTokenData[i]
81
- } else if (lbtcTokenData[i]) {
82
- offchainTokenData[i] = lbtcTokenData[i]
83
- }
84
- }
85
-
86
- return offchainTokenData
87
- }
1
+ import type { OffchainTokenData } from '../types.ts'
2
+ import { defaultAbiCoder } from './const.ts'
88
3
 
89
4
  /**
90
5
  * Encodes offchain token data for EVM execution.
@@ -99,107 +14,3 @@ export function encodeEVMOffchainTokenData(data: OffchainTokenData): string {
99
14
  }
100
15
  return '0x'
101
16
  }
102
-
103
- /**
104
- * Try to fetch USDC attestations for transfers, return undefined in position if can't
105
- *
106
- * @param tokenAmounts - all tokenAmounts to try
107
- * @param allLogsInRequest - all other logs in same tx as CCIPSendRequested
108
- * @param networkType - network type (mainnet or testnet)
109
- * @returns array where each position is either the attestation for that transfer or undefined
110
- **/
111
- async function getUsdcTokenData(
112
- tokenAmounts: CCIPMessage['tokenAmounts'],
113
- allLogsInRequest: Pick<Log, 'topics' | 'address' | 'data'>[],
114
- networkType: NetworkType,
115
- { logger = console }: WithLogger = {},
116
- ): Promise<OffchainTokenData[]> {
117
- const attestations: OffchainTokenData[] = []
118
-
119
- const messageSentPerTokenAndPool = allLogsInRequest.reduce((acc, log, i, arr) => {
120
- // for our MessageSent of interest (USDC-like), the token is the contract
121
- // which emitted a (burn) Transfer immediately before this event, and the pool emitted a Burned
122
- // event 2 events after
123
- const transferLog = arr[i - 1]
124
- const poolLog = arr[i + 2]
125
- if (
126
- log.topics[0] !== USDC_EVENT.topicHash ||
127
- transferLog?.topics[0] !== TRANSFER_EVENT.topicHash ||
128
- !poolLog?.topics.length ||
129
- !BURNED_EVENT_TOPIC_HASHES.has(poolLog.topics[0]!)
130
- ) {
131
- return acc
132
- }
133
- const token = transferLog.address
134
- const pool = poolLog.address
135
- acc.set(token, [...(acc.get(token) ?? []), log])
136
- acc.set(pool, [...(acc.get(pool) ?? []), log])
137
- return acc
138
- }, new Map<string | Addressable, (typeof allLogsInRequest)[number][]>())
139
-
140
- for (const [i, tokenAmount] of tokenAmounts.entries()) {
141
- const tokenOrPool = 'token' in tokenAmount ? tokenAmount.token : tokenAmount.sourcePoolAddress
142
-
143
- // what if there are more USDC transfers of this same token after this one?
144
- const tokenTransfersCountAfter = tokenAmounts.filter(
145
- (ta, j) => ('token' in ta ? ta.token : ta.sourcePoolAddress) === tokenOrPool && j > i,
146
- ).length
147
-
148
- let messageSentLog: (typeof allLogsInRequest)[number] | undefined
149
- const messageSents = messageSentPerTokenAndPool.get(tokenOrPool)
150
- if (messageSents) {
151
- // look from the end (near our request), but skip MessageSents for further transfers
152
- messageSentLog = messageSents[messageSents.length - 1 - tokenTransfersCountAfter]
153
- }
154
-
155
- let tokenData: OffchainTokenData
156
- if (messageSentLog) {
157
- let message
158
- try {
159
- message = defaultAbiCoder.decode(USDC_EVENT.inputs, messageSentLog.data)[0] as string
160
- const attestation = await getUsdcAttestation(message, networkType)
161
- tokenData = {
162
- _tag: 'usdc',
163
- message,
164
- attestation,
165
- }
166
- // encoding of OffchainTokenData to be done as part of Chain.executeReceipt
167
- } catch (err) {
168
- // maybe not a USDC transfer, or not ready
169
- logger.warn(`❌ EVM CCTP: Failed to fetch attestation for message:`, message, err)
170
- }
171
- }
172
- attestations.push(tokenData)
173
- }
174
-
175
- return attestations
176
- }
177
-
178
- /**
179
- * Try to fetch LBTC attestations for transfers, return undefined in position if can't or not required
180
- **/
181
- async function getLbtcTokenData(
182
- tokenAmounts: readonly Pick<SourceTokenData, 'extraData'>[],
183
- allLogsInRequest: readonly Pick<Log, 'topics' | 'address' | 'data'>[],
184
- networkType: NetworkType,
185
- { logger = console }: WithLogger = {},
186
- ): Promise<OffchainTokenData[]> {
187
- const lbtcDepositHashes = new Set(
188
- allLogsInRequest
189
- .filter(({ topics }) => LBTC_EVENTS_HASHES.has(topics[0]!))
190
- .map(({ topics }) => topics[3]),
191
- )
192
- return Promise.all(
193
- tokenAmounts.map(async ({ extraData }) => {
194
- // Attestation is required when SourceTokenData.extraData is 32 bytes long ('0x' + 64 hex chars)
195
- // otherwise attestation is not required
196
- if (lbtcDepositHashes.has(extraData)) {
197
- try {
198
- return { _tag: 'lbtc', extraData, ...(await getLbtcAttestation(extraData, networkType)) }
199
- } catch (err) {
200
- logger.warn(`❌ EVM LBTC: Failed to fetch attestation for message:`, extraData, err)
201
- }
202
- }
203
- }),
204
- )
205
- }
package/src/gas.ts CHANGED
@@ -20,6 +20,10 @@ export type EstimateMessageInput = {
20
20
  messageId?: string
21
21
  /** optional sender: zero address will be used if omitted */
22
22
  sender?: string
23
+ /** optional onRampAddress */
24
+ onRampAddress?: string
25
+ /** optional offRampAddress */
26
+ offRampAddress?: string
23
27
  /** optional data: zero bytes will be used if omitted */
24
28
  data?: BytesLike
25
29
  /**
@@ -89,26 +93,29 @@ export async function estimateReceiveExecution({
89
93
  if (!dest.estimateReceiveExecution)
90
94
  throw new CCIPMethodUnsupportedError(dest.constructor.name, 'estimateReceiveExecution')
91
95
 
92
- let onRamp, offRamp: string
93
- try {
94
- const tnv = await source.typeAndVersion(routerOrRamp)
95
- if (!tnv[0].includes('OnRamp'))
96
- onRamp = await source.getOnRampForRouter(routerOrRamp, dest.network.chainSelector)
97
- else onRamp = routerOrRamp
98
- offRamp = await discoverOffRamp(source, dest, onRamp, source)
99
- } catch (sourceErr) {
96
+ let onRamp: string, offRamp: string
97
+ if (message.onRampAddress) onRamp = message.onRampAddress
98
+ if (message.offRampAddress) offRamp = message.offRampAddress
99
+ if (!onRamp! || !offRamp!)
100
100
  try {
101
- const tnv = await dest.typeAndVersion(routerOrRamp)
102
- if (!tnv[0].includes('OffRamp'))
103
- throw new CCIPContractTypeInvalidError(routerOrRamp, tnv[2], ['OffRamp'])
104
- offRamp = routerOrRamp
105
- const onRamps = await dest.getOnRampsForOffRamp(offRamp, source.network.chainSelector)
106
- if (!onRamps.length) throw new CCIPOnRampRequiredError()
107
- onRamp = onRamps[onRamps.length - 1]!
108
- } catch {
109
- throw sourceErr // re-throw original error
101
+ const tnv = await source.typeAndVersion(routerOrRamp)
102
+ if (!tnv[0].includes('OnRamp'))
103
+ onRamp = await source.getOnRampForRouter(routerOrRamp, dest.network.chainSelector)
104
+ else onRamp = routerOrRamp
105
+ offRamp = await discoverOffRamp(source, dest, onRamp, source)
106
+ } catch (sourceErr) {
107
+ try {
108
+ const tnv = await dest.typeAndVersion(routerOrRamp)
109
+ if (!tnv[0].includes('OffRamp'))
110
+ throw new CCIPContractTypeInvalidError(routerOrRamp, tnv[2], ['OffRamp'])
111
+ offRamp = routerOrRamp
112
+ const onRamps = await dest.getOnRampsForOffRamp(offRamp, source.network.chainSelector)
113
+ if (!onRamps.length) throw new CCIPOnRampRequiredError()
114
+ onRamp = onRamps[onRamps.length - 1]!
115
+ } catch {
116
+ throw sourceErr // re-throw original error
117
+ }
110
118
  }
111
- }
112
119
 
113
120
  const destTokenAmounts = await Promise.all(
114
121
  (message.tokenAmounts ?? []).map(async (ta) => {
@@ -127,7 +134,8 @@ export async function estimateReceiveExecution({
127
134
  dest.getTokenInfo(tokenAmount.destTokenAddress),
128
135
  ])
129
136
  const destAmount =
130
- (tokenAmount.amount * 10n ** BigInt(destDecimals)) / 10n ** BigInt(sourceDecimals)
137
+ (tokenAmount.amount * BigInt(10) ** BigInt(destDecimals)) /
138
+ BigInt(10) ** BigInt(sourceDecimals)
131
139
  if (destAmount === 0n)
132
140
  throw new CCIPTokenDecimalsInsufficientError(
133
141
  tokenAmount.destTokenAddress,
package/src/index.ts CHANGED
@@ -13,7 +13,12 @@ export type {
13
13
  CCIPAPIClientContext,
14
14
  LaneLatencyResponse,
15
15
  } from './api/index.ts'
16
- export { CCIPAPIClient, DEFAULT_API_BASE_URL } from './api/index.ts'
16
+ export {
17
+ CCIPAPIClient,
18
+ DEFAULT_API_BASE_URL,
19
+ SDK_VERSION,
20
+ SDK_VERSION_HEADER,
21
+ } from './api/index.ts'
17
22
 
18
23
  export type {
19
24
  ApiRetryConfig,
@@ -22,6 +27,7 @@ export type {
22
27
  ChainGetter,
23
28
  ChainStatic,
24
29
  GetBalanceOpts,
30
+ LaneFeatures,
25
31
  LogFilter,
26
32
  RateLimiterState,
27
33
  RegistryTokenConfig,
@@ -29,7 +35,7 @@ export type {
29
35
  TokenPoolConfig,
30
36
  TokenPoolRemote,
31
37
  } from './chain.ts'
32
- export { DEFAULT_API_RETRY_CONFIG } from './chain.ts'
38
+ export { DEFAULT_API_RETRY_CONFIG, LaneFeature } from './chain.ts'
33
39
  export { calculateManualExecProof, discoverOffRamp } from './execution.ts'
34
40
  export {
35
41
  type EVMExtraArgsV1,
@@ -41,12 +47,14 @@ export {
41
47
  encodeExtraArgs,
42
48
  } from './extra-args.ts'
43
49
  export { estimateReceiveExecution } from './gas.ts'
50
+ export { getOffchainTokenData } from './offchain.ts'
44
51
  export { decodeMessage, getMessagesForSender, sourceToDestTokenAddresses } from './requests.ts'
45
52
  export {
46
53
  type CCIPExecution,
47
54
  type CCIPMessage,
48
55
  type CCIPRequest,
49
56
  type CCIPVerifications,
57
+ type ChainLog,
50
58
  type ChainTransaction,
51
59
  type CommitReport,
52
60
  type ExecutionInput,