@chainlink/ccip-sdk 0.96.0 → 1.0.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 (247) hide show
  1. package/README.md +12 -9
  2. package/dist/api/index.d.ts +21 -8
  3. package/dist/api/index.d.ts.map +1 -1
  4. package/dist/api/index.js +42 -13
  5. package/dist/api/index.js.map +1 -1
  6. package/dist/api/types.d.ts +0 -2
  7. package/dist/api/types.d.ts.map +1 -1
  8. package/dist/aptos/exec.d.ts +2 -2
  9. package/dist/aptos/exec.d.ts.map +1 -1
  10. package/dist/aptos/exec.js.map +1 -1
  11. package/dist/aptos/hasher.d.ts.map +1 -1
  12. package/dist/aptos/hasher.js +1 -1
  13. package/dist/aptos/hasher.js.map +1 -1
  14. package/dist/aptos/index.d.ts +17 -16
  15. package/dist/aptos/index.d.ts.map +1 -1
  16. package/dist/aptos/index.js +42 -73
  17. package/dist/aptos/index.js.map +1 -1
  18. package/dist/aptos/logs.d.ts +2 -2
  19. package/dist/aptos/logs.d.ts.map +1 -1
  20. package/dist/aptos/types.d.ts +2 -19
  21. package/dist/aptos/types.d.ts.map +1 -1
  22. package/dist/aptos/types.js +0 -11
  23. package/dist/aptos/types.js.map +1 -1
  24. package/dist/chain.d.ts +538 -158
  25. package/dist/chain.d.ts.map +1 -1
  26. package/dist/chain.js +132 -19
  27. package/dist/chain.js.map +1 -1
  28. package/dist/commits.d.ts +4 -6
  29. package/dist/commits.d.ts.map +1 -1
  30. package/dist/commits.js +4 -4
  31. package/dist/commits.js.map +1 -1
  32. package/dist/errors/CCIPError.d.ts +33 -4
  33. package/dist/errors/CCIPError.d.ts.map +1 -1
  34. package/dist/errors/CCIPError.js +33 -4
  35. package/dist/errors/CCIPError.js.map +1 -1
  36. package/dist/errors/codes.d.ts +3 -0
  37. package/dist/errors/codes.d.ts.map +1 -1
  38. package/dist/errors/codes.js +3 -1
  39. package/dist/errors/codes.js.map +1 -1
  40. package/dist/errors/index.d.ts +4 -4
  41. package/dist/errors/index.d.ts.map +1 -1
  42. package/dist/errors/index.js +4 -4
  43. package/dist/errors/index.js.map +1 -1
  44. package/dist/errors/recovery.d.ts.map +1 -1
  45. package/dist/errors/recovery.js +4 -1
  46. package/dist/errors/recovery.js.map +1 -1
  47. package/dist/errors/specialized.d.ts +1695 -120
  48. package/dist/errors/specialized.d.ts.map +1 -1
  49. package/dist/errors/specialized.js +1715 -123
  50. package/dist/errors/specialized.js.map +1 -1
  51. package/dist/errors/utils.d.ts.map +1 -1
  52. package/dist/errors/utils.js +0 -1
  53. package/dist/errors/utils.js.map +1 -1
  54. package/dist/evm/abi/OffRamp_2_0.d.ts +764 -0
  55. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -0
  56. package/dist/evm/abi/OffRamp_2_0.js +744 -0
  57. package/dist/evm/abi/OffRamp_2_0.js.map +1 -0
  58. package/dist/evm/abi/OnRamp_2_0.d.ts +925 -0
  59. package/dist/evm/abi/OnRamp_2_0.d.ts.map +1 -0
  60. package/dist/evm/abi/OnRamp_2_0.js +992 -0
  61. package/dist/evm/abi/OnRamp_2_0.js.map +1 -0
  62. package/dist/evm/const.d.ts +12 -2
  63. package/dist/evm/const.d.ts.map +1 -1
  64. package/dist/evm/const.js +8 -2
  65. package/dist/evm/const.js.map +1 -1
  66. package/dist/evm/errors.d.ts.map +1 -1
  67. package/dist/evm/errors.js +7 -2
  68. package/dist/evm/errors.js.map +1 -1
  69. package/dist/evm/extra-args.d.ts.map +1 -1
  70. package/dist/evm/extra-args.js +5 -24
  71. package/dist/evm/extra-args.js.map +1 -1
  72. package/dist/evm/hasher.d.ts.map +1 -1
  73. package/dist/evm/hasher.js +23 -13
  74. package/dist/evm/hasher.js.map +1 -1
  75. package/dist/evm/index.d.ts +73 -16
  76. package/dist/evm/index.d.ts.map +1 -1
  77. package/dist/evm/index.js +241 -146
  78. package/dist/evm/index.js.map +1 -1
  79. package/dist/evm/logs.d.ts +1 -1
  80. package/dist/evm/logs.js +1 -1
  81. package/dist/evm/messages.d.ts +59 -5
  82. package/dist/evm/messages.d.ts.map +1 -1
  83. package/dist/evm/messages.js +210 -0
  84. package/dist/evm/messages.js.map +1 -1
  85. package/dist/evm/offchain.d.ts +1 -14
  86. package/dist/evm/offchain.d.ts.map +1 -1
  87. package/dist/evm/offchain.js +1 -133
  88. package/dist/evm/offchain.js.map +1 -1
  89. package/dist/evm/types.d.ts +7 -2
  90. package/dist/evm/types.d.ts.map +1 -1
  91. package/dist/evm/types.js +22 -1
  92. package/dist/evm/types.js.map +1 -1
  93. package/dist/execution.d.ts +62 -22
  94. package/dist/execution.d.ts.map +1 -1
  95. package/dist/execution.js +98 -61
  96. package/dist/execution.js.map +1 -1
  97. package/dist/extra-args.d.ts +13 -3
  98. package/dist/extra-args.d.ts.map +1 -1
  99. package/dist/extra-args.js +13 -3
  100. package/dist/extra-args.js.map +1 -1
  101. package/dist/gas.d.ts +25 -2
  102. package/dist/gas.d.ts.map +1 -1
  103. package/dist/gas.js +30 -4
  104. package/dist/gas.js.map +1 -1
  105. package/dist/index.d.ts +3 -2
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +2 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/offchain.d.ts +23 -6
  110. package/dist/offchain.d.ts.map +1 -1
  111. package/dist/offchain.js +92 -17
  112. package/dist/offchain.js.map +1 -1
  113. package/dist/requests.d.ts +85 -14
  114. package/dist/requests.d.ts.map +1 -1
  115. package/dist/requests.js +99 -17
  116. package/dist/requests.js.map +1 -1
  117. package/dist/selectors.d.ts.map +1 -1
  118. package/dist/selectors.js +12 -0
  119. package/dist/selectors.js.map +1 -1
  120. package/dist/shared/bcs-codecs.d.ts +61 -0
  121. package/dist/shared/bcs-codecs.d.ts.map +1 -0
  122. package/dist/shared/bcs-codecs.js +102 -0
  123. package/dist/shared/bcs-codecs.js.map +1 -0
  124. package/dist/shared/constants.d.ts +3 -0
  125. package/dist/shared/constants.d.ts.map +1 -0
  126. package/dist/shared/constants.js +3 -0
  127. package/dist/shared/constants.js.map +1 -0
  128. package/dist/solana/exec.d.ts +2 -2
  129. package/dist/solana/exec.d.ts.map +1 -1
  130. package/dist/solana/exec.js.map +1 -1
  131. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.d.ts +1 -1
  132. package/dist/solana/idl/1.6.0/BASE_TOKEN_POOL.js +1 -1
  133. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.d.ts +1 -1
  134. package/dist/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.js +1 -1
  135. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.d.ts +1 -1
  136. package/dist/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.js +1 -1
  137. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts +16 -1
  138. package/dist/solana/idl/1.6.0/CCIP_COMMON.d.ts.map +1 -1
  139. package/dist/solana/idl/1.6.0/CCIP_COMMON.js +16 -1
  140. package/dist/solana/idl/1.6.0/CCIP_COMMON.js.map +1 -1
  141. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.d.ts +1 -1
  142. package/dist/solana/idl/1.6.0/CCIP_OFFRAMP.js +1 -1
  143. package/dist/solana/idl/1.6.0/CCIP_ROUTER.d.ts +1 -1
  144. package/dist/solana/idl/1.6.0/CCIP_ROUTER.js +1 -1
  145. package/dist/solana/index.d.ts +85 -24
  146. package/dist/solana/index.d.ts.map +1 -1
  147. package/dist/solana/index.js +69 -37
  148. package/dist/solana/index.js.map +1 -1
  149. package/dist/solana/offchain.d.ts +1 -13
  150. package/dist/solana/offchain.d.ts.map +1 -1
  151. package/dist/solana/offchain.js +1 -66
  152. package/dist/solana/offchain.js.map +1 -1
  153. package/dist/solana/utils.d.ts +4 -4
  154. package/dist/solana/utils.d.ts.map +1 -1
  155. package/dist/solana/utils.js +1 -1
  156. package/dist/solana/utils.js.map +1 -1
  157. package/dist/sui/hasher.d.ts.map +1 -1
  158. package/dist/sui/hasher.js +1 -1
  159. package/dist/sui/hasher.js.map +1 -1
  160. package/dist/sui/index.d.ts +18 -18
  161. package/dist/sui/index.d.ts.map +1 -1
  162. package/dist/sui/index.js +38 -39
  163. package/dist/sui/index.js.map +1 -1
  164. package/dist/sui/manuallyExec/encoder.d.ts +2 -2
  165. package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
  166. package/dist/sui/manuallyExec/encoder.js.map +1 -1
  167. package/dist/sui/manuallyExec/index.d.ts +2 -2
  168. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  169. package/dist/ton/exec.d.ts +3 -3
  170. package/dist/ton/exec.d.ts.map +1 -1
  171. package/dist/ton/exec.js +1 -1
  172. package/dist/ton/exec.js.map +1 -1
  173. package/dist/ton/index.d.ts +14 -22
  174. package/dist/ton/index.d.ts.map +1 -1
  175. package/dist/ton/index.js +26 -35
  176. package/dist/ton/index.js.map +1 -1
  177. package/dist/ton/types.d.ts +3 -5
  178. package/dist/ton/types.d.ts.map +1 -1
  179. package/dist/ton/types.js.map +1 -1
  180. package/dist/types.d.ts +55 -20
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/types.js +6 -1
  183. package/dist/types.js.map +1 -1
  184. package/dist/utils.d.ts +65 -2
  185. package/dist/utils.d.ts.map +1 -1
  186. package/dist/utils.js +74 -2
  187. package/dist/utils.js.map +1 -1
  188. package/package.json +14 -10
  189. package/src/api/index.ts +53 -17
  190. package/src/api/types.ts +0 -2
  191. package/src/aptos/exec.ts +2 -2
  192. package/src/aptos/hasher.ts +1 -1
  193. package/src/aptos/index.ts +55 -100
  194. package/src/aptos/logs.ts +2 -2
  195. package/src/aptos/types.ts +2 -15
  196. package/src/chain.ts +594 -171
  197. package/src/commits.ts +9 -9
  198. package/src/errors/CCIPError.ts +33 -4
  199. package/src/errors/codes.ts +3 -1
  200. package/src/errors/index.ts +4 -0
  201. package/src/errors/recovery.ts +7 -1
  202. package/src/errors/specialized.ts +1726 -130
  203. package/src/errors/utils.ts +0 -1
  204. package/src/evm/abi/OffRamp_2_0.ts +743 -0
  205. package/src/evm/abi/OnRamp_2_0.ts +991 -0
  206. package/src/evm/const.ts +10 -3
  207. package/src/evm/errors.ts +6 -2
  208. package/src/evm/extra-args.ts +4 -21
  209. package/src/evm/hasher.ts +30 -18
  210. package/src/evm/index.ts +314 -176
  211. package/src/evm/logs.ts +1 -1
  212. package/src/evm/messages.ts +323 -11
  213. package/src/evm/offchain.ts +2 -191
  214. package/src/evm/types.ts +20 -2
  215. package/src/execution.ts +125 -86
  216. package/src/extra-args.ts +13 -3
  217. package/src/gas.ts +29 -3
  218. package/src/index.ts +10 -3
  219. package/src/offchain.ts +125 -28
  220. package/src/requests.ts +114 -19
  221. package/src/selectors.ts +12 -0
  222. package/src/shared/bcs-codecs.ts +132 -0
  223. package/src/shared/constants.ts +2 -0
  224. package/src/solana/exec.ts +4 -4
  225. package/src/solana/idl/1.6.0/BASE_TOKEN_POOL.ts +2 -2
  226. package/src/solana/idl/1.6.0/BURN_MINT_TOKEN_POOL.ts +2 -2
  227. package/src/solana/idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts +2 -2
  228. package/src/solana/idl/1.6.0/CCIP_COMMON.ts +32 -2
  229. package/src/solana/idl/1.6.0/CCIP_OFFRAMP.ts +2 -2
  230. package/src/solana/idl/1.6.0/CCIP_ROUTER.ts +2 -2
  231. package/src/solana/index.ts +110 -85
  232. package/src/solana/offchain.ts +3 -100
  233. package/src/solana/utils.ts +8 -5
  234. package/src/sui/hasher.ts +1 -1
  235. package/src/sui/index.ts +55 -59
  236. package/src/sui/manuallyExec/encoder.ts +2 -2
  237. package/src/sui/manuallyExec/index.ts +2 -2
  238. package/src/ton/exec.ts +4 -7
  239. package/src/ton/index.ts +45 -53
  240. package/src/ton/types.ts +4 -7
  241. package/src/types.ts +81 -37
  242. package/src/utils.ts +73 -2
  243. package/dist/aptos/utils.d.ts +0 -12
  244. package/dist/aptos/utils.d.ts.map +0 -1
  245. package/dist/aptos/utils.js +0 -15
  246. package/dist/aptos/utils.js.map +0 -1
  247. package/src/aptos/utils.ts +0 -24
package/dist/evm/index.js CHANGED
@@ -1,44 +1,27 @@
1
- import { parseAbi } from 'abitype';
2
- import { Contract, JsonRpcProvider, Result, WebSocketProvider, ZeroAddress, getAddress, hexlify, isBytesLike, isHexString, toBeHex, toBigInt, zeroPadValue, } from 'ethers';
1
+ import { Contract, JsonRpcProvider, WebSocketProvider, ZeroAddress, getAddress, hexlify, isBytesLike, isHexString, keccak256, toBeHex, zeroPadValue, } from 'ethers';
3
2
  import { memoize } from 'micro-memoize';
4
3
  import { Chain, } from "../chain.js";
5
- import { CCIPAddressInvalidEvmError, CCIPBlockNotFoundError, CCIPContractNotRouterError, CCIPContractTypeInvalidError, CCIPDataFormatUnsupportedError, CCIPExecTxNotConfirmedError, CCIPExecTxRevertedError, CCIPExtraArgsParseError, CCIPHasherVersionUnsupportedError, CCIPLogDataInvalidError, CCIPMessageDecodeError, CCIPSourceChainUnsupportedError, CCIPTokenNotConfiguredError, CCIPTokenPoolChainConfigNotFoundError, CCIPTransactionNotFoundError, CCIPVersionFeatureUnavailableError, CCIPVersionRequiresLaneError, CCIPVersionUnsupportedError, CCIPWalletInvalidError, } from "../errors/index.js";
4
+ import { CCIPAddressInvalidEvmError, CCIPApiClientNotAvailableError, CCIPBlockNotFoundError, CCIPContractNotRouterError, CCIPContractTypeInvalidError, CCIPDataFormatUnsupportedError, CCIPExecTxNotConfirmedError, CCIPExecTxRevertedError, CCIPHasherVersionUnsupportedError, CCIPLogDataInvalidError, CCIPNotImplementedError, CCIPSourceChainUnsupportedError, CCIPTokenNotConfiguredError, CCIPTokenPoolChainConfigNotFoundError, CCIPTransactionNotFoundError, CCIPVersionFeatureUnavailableError, CCIPVersionRequiresLaneError, CCIPVersionUnsupportedError, CCIPWalletInvalidError, } from "../errors/index.js";
6
5
  import { supportedChains } from "../supported-chains.js";
7
6
  import { CCIPVersion, ChainFamily, NetworkType, } from "../types.js";
8
7
  import { decodeAddress, decodeOnRampAddress, getAddressBytes, getDataBytes, networkInfo, parseTypeAndVersion, } from "../utils.js";
9
8
  import EVM2EVMOffRamp_1_2_ABI from "./abi/OffRamp_1_2.js";
10
9
  import EVM2EVMOffRamp_1_5_ABI from "./abi/OffRamp_1_5.js";
11
10
  import OffRamp_1_6_ABI from "./abi/OffRamp_1_6.js";
11
+ import OffRamp_2_0_ABI from "./abi/OffRamp_2_0.js";
12
12
  import EVM2EVMOnRamp_1_2_ABI from "./abi/OnRamp_1_2.js";
13
13
  import EVM2EVMOnRamp_1_5_ABI from "./abi/OnRamp_1_5.js";
14
- import OnRamp_1_6_ABI from "./abi/OnRamp_1_6.js";
15
- import { commitsFragments, interfaces, receiptsFragments, requestsFragments } from "./const.js";
14
+ import { CCV_INDEXER_URL, VersionedContractABI, commitsFragments, interfaces, receiptsFragments, requestsFragments, } from "./const.js";
16
15
  import { parseData } from "./errors.js";
17
16
  import { decodeExtraArgs as decodeExtraArgs_, encodeExtraArgs as encodeExtraArgs_, } from "./extra-args.js";
18
17
  import { estimateExecGas } from "./gas.js";
19
18
  import { getV12LeafHasher, getV16LeafHasher } from "./hasher.js";
20
19
  import { getEvmLogs } from "./logs.js";
21
- import { parseSourceTokenData, } from "./messages.js";
22
- import { encodeEVMOffchainTokenData, fetchEVMOffchainTokenData } from "./offchain.js";
23
- import { buildMessageForDest, getMessagesInBatch } from "../requests.js";
24
- const VersionedContractABI = parseAbi(['function typeAndVersion() view returns (string)']);
25
- function resultToObject(o) {
26
- if (o instanceof Promise)
27
- return o.then(resultToObject);
28
- if (!(o instanceof Result))
29
- return o;
30
- if (o.length === 0)
31
- return o.toArray();
32
- try {
33
- const obj = o.toObject();
34
- if (!Object.keys(obj).every((k) => /^_+\d*$/.test(k)))
35
- return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, resultToObject(v)]));
36
- }
37
- catch (_) {
38
- // fallthrough
39
- }
40
- return o.toArray().map(resultToObject);
41
- }
20
+ import { decodeMessageV1, } from "./messages.js";
21
+ export { decodeMessageV1 };
22
+ import { encodeEVMOffchainTokenData } from "./offchain.js";
23
+ import { buildMessageForDest, decodeMessage, getMessagesInBatch } from "../requests.js";
24
+ import { resultToObject } from "./types.js";
42
25
  /** typeguard for ethers Signer interface (used for `wallet`s) */
43
26
  function isSigner(wallet) {
44
27
  return (typeof wallet === 'object' &&
@@ -62,6 +45,26 @@ async function submitTransaction(wallet, tx, provider) {
62
45
  }
63
46
  /**
64
47
  * EVM chain implementation supporting Ethereum-compatible networks.
48
+ *
49
+ * Provides methods for sending CCIP cross-chain messages, querying message
50
+ * status, fetching fee quotes, and manually executing pending messages on
51
+ * Ethereum Virtual Machine compatible chains.
52
+ *
53
+ * @example Create from RPC URL
54
+ * ```typescript
55
+ * import { EVMChain } from '@chainlink/ccip-sdk'
56
+ *
57
+ * const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
58
+ * console.log(`Connected to: ${chain.network.name}`)
59
+ * ```
60
+ *
61
+ * @example Query messages in a transaction
62
+ * ```typescript
63
+ * const requests = await chain.getMessagesInTx('0xabc123...')
64
+ * for (const req of requests) {
65
+ * console.log(`Message ID: ${req.message.messageId}`)
66
+ * }
67
+ * ```
65
68
  */
66
69
  export class EVMChain extends Chain {
67
70
  static {
@@ -71,6 +74,13 @@ export class EVMChain extends Chain {
71
74
  static decimals = 18;
72
75
  provider;
73
76
  destroy$;
77
+ noncesPromises;
78
+ /**
79
+ * Cache of current nonces per wallet address.
80
+ * Used internally by {@link sendMessage} and {@link execute} to manage transaction ordering.
81
+ * Can be inspected for debugging or manually adjusted if needed.
82
+ */
83
+ nonces;
74
84
  /**
75
85
  * Creates a new EVMChain instance.
76
86
  * @param provider - JSON-RPC provider for the EVM network.
@@ -78,6 +88,8 @@ export class EVMChain extends Chain {
78
88
  */
79
89
  constructor(provider, network, ctx) {
80
90
  super(network, ctx);
91
+ this.noncesPromises = {};
92
+ this.nonces = {};
81
93
  this.provider = provider;
82
94
  this.destroy$ = new Promise((resolve) => (this.destroy = resolve));
83
95
  void this.destroy$.finally(() => provider.destroy());
@@ -112,6 +124,21 @@ export class EVMChain extends Chain {
112
124
  async listAccounts() {
113
125
  return (await this.provider.listAccounts()).map(({ address }) => address);
114
126
  }
127
+ /**
128
+ * Get the next nonce for a wallet address and increment the internal counter.
129
+ * Fetches from the network on first call, then uses cached value.
130
+ * @param address - Wallet address to get nonce for
131
+ * @returns The next available nonce
132
+ */
133
+ async nextNonce(address) {
134
+ await (this.noncesPromises[address] ??= this.provider
135
+ .getTransactionCount(address)
136
+ .then((nonce) => {
137
+ this.nonces[address] = nonce;
138
+ return nonce;
139
+ }));
140
+ return this.nonces[address]++;
141
+ }
115
142
  /**
116
143
  * Creates a JSON-RPC provider from a URL.
117
144
  * @param url - WebSocket (wss://) or HTTP (https://) endpoint URL.
@@ -157,9 +184,20 @@ export class EVMChain extends Chain {
157
184
  }
158
185
  /**
159
186
  * Creates an EVMChain instance from an RPC URL.
187
+ *
160
188
  * @param url - WebSocket (wss://) or HTTP (https://) endpoint URL.
161
- * @param ctx - context containing logger.
162
- * @returns A new EVMChain instance.
189
+ * @param ctx - Optional context containing logger and API client configuration.
190
+ * @returns A new EVMChain instance connected to the specified network.
191
+ * @throws {@link CCIPChainNotFoundError} if chain cannot be identified from chainId
192
+ *
193
+ * @example
194
+ * ```typescript
195
+ * // HTTP connection
196
+ * const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
197
+ *
198
+ * // With custom logger
199
+ * const chain = await EVMChain.fromUrl(url, { logger: customLogger })
200
+ * ```
163
201
  */
164
202
  static async fromUrl(url, ctx) {
165
203
  return this.fromProvider(await this._getProvider(url), ctx);
@@ -193,7 +231,7 @@ export class EVMChain extends Chain {
193
231
  yield* getEvmLogs(filter, this);
194
232
  }
195
233
  /** {@inheritDoc Chain.getMessagesInBatch} */
196
- getMessagesInBatch(request, commit, opts) {
234
+ getMessagesInBatch(request, range, opts) {
197
235
  let opts_;
198
236
  if (request.lane.version >= CCIPVersion.V1_6) {
199
237
  // specialized getLogs filter for v1.6 CCIPMessageSent events, to filter by dest
@@ -202,12 +240,15 @@ export class EVMChain extends Chain {
202
240
  topics: [[request.log.topics[0]], [toBeHex(request.lane.destChainSelector, 32)]],
203
241
  };
204
242
  }
205
- return getMessagesInBatch(this, request, commit, opts_);
243
+ return getMessagesInBatch(this, request, range, opts_);
206
244
  }
207
245
  /** {@inheritDoc Chain.typeAndVersion} */
208
246
  async typeAndVersion(address) {
209
247
  const contract = new Contract(address, VersionedContractABI, this.provider);
210
- return parseTypeAndVersion(await contract.typeAndVersion());
248
+ const res = parseTypeAndVersion(await contract.typeAndVersion());
249
+ if (res[1].startsWith('1.7.'))
250
+ res[1] = CCIPVersion.V2_0;
251
+ return res;
211
252
  }
212
253
  /**
213
254
  * Decodes a CCIP message from a log event.
@@ -237,6 +278,9 @@ export class EVMChain extends Chain {
237
278
  message = resultToObject(result);
238
279
  if (message.message)
239
280
  message = message.message;
281
+ else if (message.encodedMessage) {
282
+ Object.assign(message, decodeMessageV1(message.encodedMessage));
283
+ }
240
284
  if (message)
241
285
  break;
242
286
  }
@@ -246,63 +290,7 @@ export class EVMChain extends Chain {
246
290
  }
247
291
  if (!message)
248
292
  return;
249
- if (!isHexString(message.sender, 20))
250
- throw new CCIPMessageDecodeError('invalid sender');
251
- if (message.header) {
252
- // CCIPMessage_V1_6
253
- Object.assign(message, message.header);
254
- delete message.header;
255
- }
256
- const sourceFamily = networkInfo(message.sourceChainSelector).family;
257
- let destFamily = ChainFamily.EVM;
258
- if (message.destChainSelector) {
259
- destFamily = networkInfo(message.destChainSelector).family;
260
- }
261
- // conversions to make any message version be compatible with latest v1.6
262
- message.tokenAmounts = message.tokenAmounts.map((tokenAmount, i) => {
263
- if ('sourceTokenData' in message) {
264
- // CCIPMessage_V1_2_EVM
265
- try {
266
- tokenAmount = {
267
- ...parseSourceTokenData(message.sourceTokenData[i]),
268
- ...tokenAmount,
269
- };
270
- }
271
- catch (_) {
272
- // legacy sourceTokenData
273
- }
274
- }
275
- if (typeof tokenAmount.destExecData === 'string' && tokenAmount.destGasAmount == null) {
276
- // CCIPMessage_V1_6_EVM
277
- tokenAmount.destGasAmount = toBigInt(getDataBytes(tokenAmount.destExecData));
278
- }
279
- // Can be undefined if the message is from before v1.5 and failed to parse sourceTokenData
280
- if (tokenAmount.sourcePoolAddress) {
281
- tokenAmount.sourcePoolAddress = decodeAddress(tokenAmount.sourcePoolAddress, sourceFamily);
282
- }
283
- if (tokenAmount.destTokenAddress) {
284
- tokenAmount.destTokenAddress = decodeAddress(tokenAmount.destTokenAddress, destFamily);
285
- }
286
- return tokenAmount;
287
- });
288
- message.sender = decodeAddress(message.sender, sourceFamily);
289
- message.feeToken = decodeAddress(message.feeToken, sourceFamily);
290
- message.receiver = decodeAddress(message.receiver, destFamily);
291
- if (message.extraArgs) {
292
- // v1.6+
293
- const parsed = this.decodeExtraArgs(message.extraArgs);
294
- if (!parsed)
295
- throw new CCIPExtraArgsParseError(message.extraArgs);
296
- const { _tag, ...rest } = parsed;
297
- // merge parsed extraArgs to any family in message root object
298
- Object.assign(message, rest);
299
- }
300
- else if (message.nonce === 0n) {
301
- // v1.2..v1.5 targets EVM only; extraArgs is not explicit, gasLimit is already in
302
- // message body, allowOutOfOrderExecution (in v1.5) was present only as nonce=0
303
- message.allowOutOfOrderExecution = true;
304
- }
305
- return message;
293
+ return decodeMessage(message);
306
294
  }
307
295
  /**
308
296
  * Decodes commit reports from a log event.
@@ -481,11 +469,15 @@ export class EVMChain extends Chain {
481
469
  return router;
482
470
  }
483
471
  case CCIPVersion.V1_6: {
484
- onRampABI = OnRamp_1_6_ABI;
485
- const contract = new Contract(onRamp, onRampABI, this.provider);
472
+ const contract = new Contract(onRamp, interfaces.OnRamp_v1_6, this.provider);
486
473
  const [, , router] = await contract.getDestChainConfig(destChainSelector);
487
474
  return router;
488
475
  }
476
+ case CCIPVersion.V2_0: {
477
+ const contract = new Contract(onRamp, interfaces.OnRamp_v2_0, this.provider);
478
+ const { router } = await contract.getDestChainConfig(destChainSelector);
479
+ return router;
480
+ }
489
481
  default:
490
482
  throw new CCIPVersionUnsupportedError(version);
491
483
  }
@@ -507,8 +499,11 @@ export class EVMChain extends Chain {
507
499
  ({ router } = await contract.getDynamicConfig());
508
500
  break;
509
501
  }
510
- case CCIPVersion.V1_6: {
502
+ case CCIPVersion.V1_6:
511
503
  offRampABI = OffRamp_1_6_ABI;
504
+ // falls through
505
+ case CCIPVersion.V2_0: {
506
+ offRampABI = OffRamp_2_0_ABI;
512
507
  const contract = new Contract(offRamp, offRampABI, this.provider);
513
508
  ({ router } = await contract.getSourceChainConfig(sourceChainSelector));
514
509
  break;
@@ -537,10 +532,10 @@ export class EVMChain extends Chain {
537
532
  return contract.getOnRamp(destChainSelector);
538
533
  }
539
534
  /**
540
- * {@inheritDoc Chain.getOnRampForOffRamp}
535
+ * {@inheritDoc Chain.getOnRampsForOffRamp}
541
536
  * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
542
537
  */
543
- async getOnRampForOffRamp(offRamp, sourceChainSelector) {
538
+ async getOnRampsForOffRamp(offRamp, sourceChainSelector) {
544
539
  const [, version] = await this.typeAndVersion(offRamp);
545
540
  let offRampABI;
546
541
  switch (version) {
@@ -551,21 +546,41 @@ export class EVMChain extends Chain {
551
546
  offRampABI ??= EVM2EVMOffRamp_1_5_ABI;
552
547
  const contract = new Contract(offRamp, offRampABI, this.provider);
553
548
  const { onRamp } = await contract.getStaticConfig();
554
- return onRamp;
549
+ return [onRamp];
555
550
  }
556
551
  case CCIPVersion.V1_6: {
557
552
  offRampABI = OffRamp_1_6_ABI;
558
553
  const contract = new Contract(offRamp, offRampABI, this.provider);
559
554
  const { onRamp } = await contract.getSourceChainConfig(sourceChainSelector);
560
- return decodeOnRampAddress(onRamp, networkInfo(sourceChainSelector).family);
555
+ if (!onRamp || onRamp.match(/^(0x)?0*$/i))
556
+ return [];
557
+ return [decodeOnRampAddress(onRamp, networkInfo(sourceChainSelector).family)];
558
+ }
559
+ case CCIPVersion.V2_0: {
560
+ offRampABI = OffRamp_2_0_ABI;
561
+ const contract = new Contract(offRamp, offRampABI, this.provider);
562
+ const { onRamps } = await contract.getSourceChainConfig(sourceChainSelector);
563
+ const sourceFamily = networkInfo(sourceChainSelector).family;
564
+ return onRamps.map((onRamp) => decodeOnRampAddress(onRamp, sourceFamily));
561
565
  }
562
566
  default:
563
567
  throw new CCIPVersionUnsupportedError(version);
564
568
  }
565
569
  }
566
570
  /**
567
- * {@inheritDoc Chain.getCommitStoreForOffRamp}
571
+ * Fetch the CommitStore set in OffRamp config (CCIP v1.5 and earlier).
572
+ * For CCIP v1.6 and later, it should return the offRamp address.
573
+ *
574
+ * @param offRamp - OffRamp contract address
575
+ * @returns Promise resolving to CommitStore address
576
+ *
577
+ * @example Get commit store
578
+ * ```typescript
579
+ * const commitStore = await dest.getCommitStoreForOffRamp(offRampAddress)
580
+ * // For v1.6+, commitStore === offRampAddress
581
+ * ```
568
582
  * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
583
+ * @internal
569
584
  */
570
585
  async getCommitStoreForOffRamp(offRamp) {
571
586
  const [, version] = await this.typeAndVersion(offRamp);
@@ -580,11 +595,8 @@ export class EVMChain extends Chain {
580
595
  const { commitStore } = await contract.getStaticConfig();
581
596
  return commitStore;
582
597
  }
583
- case CCIPVersion.V1_6: {
584
- return offRamp;
585
- }
586
598
  default:
587
- throw new CCIPVersionUnsupportedError(version);
599
+ return offRamp;
588
600
  }
589
601
  }
590
602
  /** {@inheritDoc Chain.getTokenForTokenPool} */
@@ -771,85 +783,121 @@ export class EVMChain extends Chain {
771
783
  const approveTxs = txs.transactions.slice(0, txs.transactions.length - 1);
772
784
  let sendTx = txs.transactions[txs.transactions.length - 1];
773
785
  // approve all tokens (including feeToken, if needed) in parallel
774
- let nonce = await this.provider.getTransactionCount(sender);
775
786
  const responses = await Promise.all(approveTxs.map(async (tx) => {
776
- tx.nonce = nonce++;
777
- tx = await wallet.populateTransaction(tx);
778
- tx.from = undefined;
779
- const response = await submitTransaction(wallet, tx, this.provider);
780
- this.logger.debug('approve =>', response.hash);
781
- return response;
787
+ tx.nonce = await this.nextNonce(sender);
788
+ try {
789
+ tx = await wallet.populateTransaction(tx);
790
+ tx.from = undefined;
791
+ const response = await submitTransaction(wallet, tx, this.provider);
792
+ this.logger.debug('approve =>', response.hash);
793
+ return response;
794
+ }
795
+ catch (err) {
796
+ this.nonces[sender]--;
797
+ throw err;
798
+ }
782
799
  }));
783
800
  if (responses.length)
784
801
  await responses[responses.length - 1].wait(1, 60_000); // wait last tx nonce to be mined
785
- sendTx.nonce = nonce++;
786
- // sendTx.gasLimit = await this.provider.estimateGas(sendTx)
787
- sendTx = await wallet.populateTransaction(sendTx);
788
- sendTx.from = undefined; // some signers don't like receiving pre-populated `from`
789
- const response = await submitTransaction(wallet, sendTx, this.provider);
802
+ sendTx.nonce = await this.nextNonce(sender);
803
+ let response;
804
+ try {
805
+ // sendTx.gasLimit = await this.provider.estimateGas(sendTx)
806
+ sendTx = await wallet.populateTransaction(sendTx);
807
+ sendTx.from = undefined; // some signers don't like receiving pre-populated `from`
808
+ response = await submitTransaction(wallet, sendTx, this.provider);
809
+ }
810
+ catch (err) {
811
+ this.nonces[sender]--;
812
+ throw err;
813
+ }
790
814
  this.logger.debug('ccipSend =>', response.hash);
791
- await response.wait(1, 60_000);
792
- return (await this.getMessagesInTx(await this.getTransaction(response.hash)))[0];
793
- }
794
- /** {@inheritDoc Chain.getOffchainTokenData} */
795
- getOffchainTokenData(request) {
796
- return fetchEVMOffchainTokenData(request, this);
815
+ const tx = (await response.wait(1, 60_000));
816
+ return (await this.getMessagesInTx(await this.getTransaction(tx)))[0];
797
817
  }
798
818
  /**
799
- * {@inheritDoc Chain.generateUnsignedExecuteReport}
819
+ * {@inheritDoc Chain.generateUnsignedExecute}
800
820
  * @returns array containing one unsigned `manuallyExecute` TransactionRequest object
801
821
  * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
802
822
  */
803
- async generateUnsignedExecuteReport({ offRamp, execReport, ...opts }) {
804
- const [_, version] = await this.typeAndVersion(offRamp);
823
+ async generateUnsignedExecute(opts) {
824
+ let input, offRamp;
825
+ if (!('input' in opts)) {
826
+ if (!this.apiClient)
827
+ throw new CCIPApiClientNotAvailableError();
828
+ ({ offRamp, ...input } = await this.apiClient.getExecutionInput(opts.messageId));
829
+ }
830
+ else {
831
+ ;
832
+ ({ offRamp, input } = opts);
833
+ }
834
+ if ('verifications' in input) {
835
+ const contract = new Contract(offRamp, interfaces.OffRamp_v2_0, this.provider);
836
+ const message = decodeMessageV1(input.encodedMessage);
837
+ const messageId = keccak256(input.encodedMessage);
838
+ // `execute` doesn't revert on failure, so we need to estimate using `executeSingleMessage`
839
+ const txGasLimit = await contract.executeSingleMessage.estimateGas({
840
+ ...message,
841
+ executionGasLimit: BigInt(message.executionGasLimit),
842
+ ccipReceiveGasLimit: BigInt(message.ccipReceiveGasLimit),
843
+ finality: BigInt(message.finality),
844
+ }, messageId, input.verifications.map(({ destAddress }) => destAddress), input.verifications.map(({ ccvData }) => hexlify(ccvData)), BigInt(opts.gasLimit ?? 0), { from: offRamp });
845
+ const execTx = await contract.execute.populateTransaction(input.encodedMessage, input.verifications.map(({ destAddress }) => destAddress), input.verifications.map(({ ccvData }) => hexlify(ccvData)), BigInt(opts.gasLimit ?? 0));
846
+ execTx.gasLimit = txGasLimit + 40000n; // plus `execute`'s overhead
847
+ return { family: ChainFamily.EVM, transactions: [execTx] };
848
+ }
805
849
  let manualExecTx;
806
- const offchainTokenData = execReport.offchainTokenData.map(encodeEVMOffchainTokenData);
850
+ const [_, version] = await this.typeAndVersion(offRamp);
851
+ const offchainTokenData = input.offchainTokenData.map(encodeEVMOffchainTokenData);
807
852
  switch (version) {
808
853
  case CCIPVersion.V1_2: {
809
- const contract = new Contract(offRamp, EVM2EVMOffRamp_1_2_ABI, this.provider);
854
+ const contract = new Contract(offRamp, interfaces.EVM2EVMOffRamp_v1_2, this.provider);
810
855
  const gasOverride = BigInt(opts.gasLimit ?? 0);
811
856
  manualExecTx = await contract.manuallyExecute.populateTransaction({
812
- ...execReport,
813
- proofs: execReport.proofs.map((d) => hexlify(d)),
814
- messages: [execReport.message],
857
+ ...input,
858
+ proofs: input.proofs.map((d) => hexlify(d)),
859
+ messages: [input.message],
815
860
  offchainTokenData: [offchainTokenData],
816
861
  }, [gasOverride]);
817
862
  break;
818
863
  }
819
864
  case CCIPVersion.V1_5: {
820
- const contract = new Contract(offRamp, EVM2EVMOffRamp_1_5_ABI, this.provider);
865
+ const contract = new Contract(offRamp, interfaces.EVM2EVMOffRamp_v1_5, this.provider);
821
866
  manualExecTx = await contract.manuallyExecute.populateTransaction({
822
- ...execReport,
823
- proofs: execReport.proofs.map((d) => hexlify(d)),
824
- messages: [execReport.message],
867
+ ...input,
868
+ proofs: input.proofs.map((d) => hexlify(d)),
869
+ messages: [input.message],
825
870
  offchainTokenData: [offchainTokenData],
826
871
  }, [
827
872
  {
828
873
  receiverExecutionGasLimit: BigInt(opts.gasLimit ?? 0),
829
- tokenGasOverrides: execReport.message.tokenAmounts.map(() => BigInt(opts.tokensGasLimit ?? opts.gasLimit ?? 0)),
874
+ tokenGasOverrides: input.message.tokenAmounts.map(() => BigInt(opts.tokensGasLimit ?? opts.gasLimit ?? 0)),
830
875
  },
831
876
  ]);
832
877
  break;
833
878
  }
834
879
  case CCIPVersion.V1_6: {
835
880
  // normalize message
836
- const sender = zeroPadValue(getAddressBytes(execReport.message.sender), 32);
837
- const tokenAmounts = execReport.message.tokenAmounts.map((ta) => ({
881
+ const senderBytes = getAddressBytes(input.message.sender);
882
+ // Addresses ≤32 bytes (EVM 20B, Aptos/Solana/Sui 32B) are zero-padded to 32 bytes;
883
+ // Addresses >32 bytes (e.g., TON 36B) are used as raw bytes without padding
884
+ const sender = senderBytes.length <= 32 ? zeroPadValue(senderBytes, 32) : hexlify(senderBytes);
885
+ const tokenAmounts = input.message.tokenAmounts.map((ta) => ({
838
886
  ...ta,
839
887
  sourcePoolAddress: zeroPadValue(getAddressBytes(ta.sourcePoolAddress), 32),
840
888
  extraData: hexlify(getDataBytes(ta.extraData)),
841
889
  }));
842
890
  const message = {
843
- ...execReport.message,
891
+ ...input.message,
844
892
  sender,
845
893
  tokenAmounts,
846
894
  };
847
- const contract = new Contract(offRamp, OffRamp_1_6_ABI, this.provider);
895
+ const contract = new Contract(offRamp, interfaces.OffRamp_v1_6, this.provider);
848
896
  manualExecTx = await contract.manuallyExecute.populateTransaction([
849
897
  {
850
- ...execReport,
851
- proofs: execReport.proofs.map((p) => hexlify(p)),
852
- sourceChainSelector: execReport.message.sourceChainSelector,
898
+ ...input,
899
+ proofs: input.proofs.map((p) => hexlify(p)),
900
+ sourceChainSelector: input.message.sourceChainSelector,
853
901
  messages: [
854
902
  {
855
903
  ...message,
@@ -868,7 +916,7 @@ export class EVMChain extends Chain {
868
916
  [
869
917
  {
870
918
  receiverExecutionGasLimit: BigInt(opts.gasLimit ?? 0),
871
- tokenGasOverrides: execReport.message.tokenAmounts.map(() => BigInt(opts.tokensGasLimit ?? opts.gasLimit ?? 0)),
919
+ tokenGasOverrides: input.message.tokenAmounts.map(() => BigInt(opts.tokensGasLimit ?? opts.gasLimit ?? 0)),
872
920
  },
873
921
  ],
874
922
  ]);
@@ -880,22 +928,24 @@ export class EVMChain extends Chain {
880
928
  return { family: ChainFamily.EVM, transactions: [manualExecTx] };
881
929
  }
882
930
  /**
883
- * {@inheritDoc Chain.executeReport}
931
+ * {@inheritDoc Chain.execute}
884
932
  * @throws {@link CCIPWalletInvalidError} if wallet is not a valid Signer
885
933
  * @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
886
934
  * @throws {@link CCIPExecTxRevertedError} if execution transaction reverts
887
935
  */
888
- async executeReport(opts) {
936
+ async execute(opts) {
889
937
  const wallet = opts.wallet;
890
938
  if (!isSigner(wallet))
891
939
  throw new CCIPWalletInvalidError(wallet);
892
- const unsignedTxs = await this.generateUnsignedExecuteReport({
940
+ const unsignedTxs = await this.generateUnsignedExecute({
893
941
  ...opts,
894
942
  payer: await wallet.getAddress(),
895
943
  });
896
- const unsignedTx = await wallet.populateTransaction(unsignedTxs.transactions[0]);
897
- unsignedTx.from = undefined; // some signers don't like receiving pre-populated `from`
898
- const response = await submitTransaction(wallet, unsignedTx, this.provider);
944
+ const unsignedTx = unsignedTxs.transactions[0];
945
+ unsignedTx.nonce = await this.nextNonce(await wallet.getAddress());
946
+ const populatedTx = await wallet.populateTransaction(unsignedTx);
947
+ populatedTx.from = undefined; // some signers don't like receiving pre-populated `from`
948
+ const response = await submitTransaction(wallet, populatedTx, this.provider);
899
949
  this.logger.debug('manuallyExecute =>', response.hash);
900
950
  const receipt = await response.wait(1, 60_000);
901
951
  if (!receipt?.hash)
@@ -1046,6 +1096,48 @@ export class EVMChain extends Chain {
1046
1096
  }
1047
1097
  return Object.fromEntries(await Promise.all(tokens.map(async (token) => [token, await this.getTokenInfo(token)])));
1048
1098
  }
1099
+ /** {@inheritDoc Chain.getVerifications} */
1100
+ async getVerifications(opts) {
1101
+ const { offRamp, request } = opts;
1102
+ if (request.lane.version >= CCIPVersion.V2_0) {
1103
+ const message = request.message;
1104
+ if (!message.encodedMessage)
1105
+ throw new CCIPNotImplementedError(`CCIPAPIClient getMessageById v2 encodedMessage`);
1106
+ const contract = new Contract(offRamp, interfaces.OffRamp_v2_0, this.provider);
1107
+ const ccvs = await contract.getCCVsForMessage(message.encodedMessage);
1108
+ const [requiredCCVs, optionalCCVs, optionalThreshold] = ccvs.map(resultToObject);
1109
+ const verificationPolicy = {
1110
+ requiredCCVs,
1111
+ optionalCCVs,
1112
+ optionalThreshold: Number(optionalThreshold),
1113
+ };
1114
+ if (this.apiClient) {
1115
+ const apiRes = await this.apiClient.getMessageById(request.message.messageId);
1116
+ if ('verifiers' in apiRes.message) {
1117
+ const verifiers = apiRes.message.verifiers;
1118
+ return {
1119
+ verificationPolicy,
1120
+ verifications: verifiers.items.map((item) => ({
1121
+ destAddress: item.destAddress,
1122
+ sourceAddress: item.sourceAddress,
1123
+ ccvData: item.verification.data,
1124
+ timestamp: new Date(item.verification.timestamp).getTime() / 1e3,
1125
+ })),
1126
+ };
1127
+ }
1128
+ }
1129
+ const url = `${CCV_INDEXER_URL}/v1/verifierresults/${request.message.messageId}`;
1130
+ const res = await fetch(url);
1131
+ const json = await res.json();
1132
+ return json;
1133
+ }
1134
+ else if (request.lane.version < CCIPVersion.V1_6) {
1135
+ // v1.2..v1.5 EVM (only) have separate CommitStore
1136
+ opts.offRamp = await this.getCommitStoreForOffRamp(opts.offRamp);
1137
+ }
1138
+ // fallback <=v1.6
1139
+ return super.getVerifications(opts);
1140
+ }
1049
1141
  /** {@inheritDoc Chain.getExecutionReceipts} */
1050
1142
  async *getExecutionReceipts(opts) {
1051
1143
  const { messageId, sourceChainSelector } = opts;
@@ -1063,10 +1155,13 @@ export class EVMChain extends Chain {
1063
1155
  };
1064
1156
  }
1065
1157
  else /* >= V1.6 */ {
1158
+ const topicHash = version === CCIPVersion.V1_6
1159
+ ? interfaces.OffRamp_v1_6.getEvent('ExecutionStateChanged').topicHash
1160
+ : interfaces.OffRamp_v2_0.getEvent('ExecutionStateChanged').topicHash;
1066
1161
  opts_ = {
1067
1162
  ...opts,
1068
1163
  topics: [
1069
- interfaces.OffRamp_v1_6.getEvent('ExecutionStateChanged').topicHash,
1164
+ topicHash,
1070
1165
  sourceChainSelector ? toBeHex(sourceChainSelector, 32) : null,
1071
1166
  null,
1072
1167
  messageId ?? null,