@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
package/dist/evm/index.js CHANGED
@@ -1,23 +1,24 @@
1
- import util from 'util';
2
1
  import { parseAbi } from 'abitype';
3
- import { AbstractSigner, BaseWallet, Contract, JsonRpcProvider, Result, SigningKey, WebSocketProvider, ZeroAddress, concat, dataSlice, encodeBase58, getAddress, getBytes, hexlify, isBytesLike, isHexString, toBigInt, zeroPadValue, } from 'ethers';
4
- import moize, {} from 'moize';
5
- import { Chain, ChainFamily, } from "../chain.js";
2
+ import { Contract, JsonRpcProvider, Result, WebSocketProvider, ZeroAddress, concat, dataSlice, encodeBase58, getAddress, getBytes, hexlify, isBytesLike, isHexString, toBeHex, toBigInt, zeroPadValue, } from 'ethers';
3
+ import { memoize } from 'micro-memoize';
4
+ import { Chain } from "../chain.js";
6
5
  import { EVMExtraArgsV1Tag, EVMExtraArgsV2Tag, SVMExtraArgsV1Tag, SuiExtraArgsV1Tag, } from "../extra-args.js";
7
6
  import { supportedChains } from "../supported-chains.js";
8
- import { CCIPVersion, } from "../types.js";
9
- import { blockRangeGenerator, decodeAddress, decodeOnRampAddress, getAddressBytes, getDataBytes, getSomeBlockNumberBefore, networkInfo, parseTypeAndVersion, } from "../utils.js";
7
+ import { CCIPVersion, ChainFamily, } from "../types.js";
8
+ import { decodeAddress, decodeOnRampAddress, getAddressBytes, getDataBytes, networkInfo, parseTypeAndVersion, util, } from "../utils.js";
10
9
  import EVM2EVMOffRamp_1_2_ABI from "./abi/OffRamp_1_2.js";
11
10
  import EVM2EVMOffRamp_1_5_ABI from "./abi/OffRamp_1_5.js";
12
11
  import OffRamp_1_6_ABI from "./abi/OffRamp_1_6.js";
13
12
  import EVM2EVMOnRamp_1_2_ABI from "./abi/OnRamp_1_2.js";
14
13
  import EVM2EVMOnRamp_1_5_ABI from "./abi/OnRamp_1_5.js";
15
14
  import OnRamp_1_6_ABI from "./abi/OnRamp_1_6.js";
16
- import { DEFAULT_APPROVE_GAS_LIMIT, DEFAULT_GAS_LIMIT, commitsFragments, defaultAbiCoder, getAllFragmentsMatchingEvents, interfaces, receiptsFragments, requestsFragments, } from "./const.js";
15
+ import { DEFAULT_GAS_LIMIT, commitsFragments, defaultAbiCoder, interfaces, receiptsFragments, requestsFragments, } from "./const.js";
17
16
  import { parseData } from "./errors.js";
18
17
  import { getV12LeafHasher, getV16LeafHasher } from "./hasher.js";
18
+ import { getEvmLogs } from "./logs.js";
19
19
  import { parseSourceTokenData, } from "./messages.js";
20
20
  import { encodeEVMOffchainTokenData, fetchEVMOffchainTokenData } from "./offchain.js";
21
+ import { fetchAllMessagesInBatch, fetchCCIPRequestById, fetchCCIPRequestsInTx, } from "../requests.js";
21
22
  const VersionedContractABI = parseAbi(['function typeAndVersion() view returns (string)']);
22
23
  const EVMExtraArgsV1 = 'tuple(uint256 gasLimit)';
23
24
  const EVMExtraArgsV2 = 'tuple(uint256 gasLimit, bool allowOutOfOrderExecution)';
@@ -42,68 +43,58 @@ function resultsToMessage(result) {
42
43
  ...(result.header ? { header: result.header.toObject() } : {}),
43
44
  };
44
45
  }
46
+ /** typeguard for ethers Signer interface (used for `wallet`s) */
47
+ function isSigner(wallet) {
48
+ return (typeof wallet === 'object' &&
49
+ wallet !== null &&
50
+ 'signTransaction' in wallet &&
51
+ 'getAddress' in wallet);
52
+ }
53
+ /**
54
+ * EVM chain implementation supporting Ethereum-compatible networks.
55
+ */
45
56
  export class EVMChain extends Chain {
57
+ static {
58
+ supportedChains[ChainFamily.EVM] = EVMChain;
59
+ }
46
60
  static family = ChainFamily.EVM;
47
61
  static decimals = 18;
48
- network;
49
62
  provider;
50
- constructor(provider, network) {
51
- if (network.family !== ChainFamily.EVM)
52
- throw new Error(`Invalid network family for EVMChain: ${network.family}`);
53
- super();
54
- this.network = network;
63
+ destroy$;
64
+ /**
65
+ * Creates a new EVMChain instance.
66
+ * @param provider - JSON-RPC provider for the EVM network.
67
+ * @param network - Network information for this chain.
68
+ */
69
+ constructor(provider, network, ctx) {
70
+ super(network, ctx);
55
71
  this.provider = provider;
56
- this.typeAndVersion = moize.default(this.typeAndVersion.bind(this));
57
- this.getBlockTimestamp = moize.default(this.getBlockTimestamp.bind(this), {
72
+ this.destroy$ = new Promise((resolve) => (this.destroy = resolve));
73
+ void this.destroy$.finally(() => provider.destroy());
74
+ this.typeAndVersion = memoize(this.typeAndVersion.bind(this));
75
+ this.provider.getBlock = memoize(provider.getBlock.bind(provider), {
58
76
  maxSize: 100,
59
- updateCacheForKey: (key) => typeof key[key.length - 1] !== 'number',
77
+ maxArgs: 1,
78
+ async: true,
79
+ forceUpdate: ([block]) => typeof block !== 'number',
60
80
  });
61
- this.getTransaction = moize.default(this.getTransaction.bind(this), {
81
+ this.getTransaction = memoize(this.getTransaction.bind(this), {
62
82
  maxSize: 100,
63
- transformArgs: (args) => typeof args[0] !== 'string'
83
+ transformKey: (args) => typeof args[0] !== 'string'
64
84
  ? [args[0].hash]
65
85
  : args,
66
86
  });
67
- this.getTokenForTokenPool = moize.default(this.getTokenForTokenPool.bind(this));
68
- this.getNativeTokenForRouter = moize.default(this.getNativeTokenForRouter.bind(this), {
87
+ this.getTokenForTokenPool = memoize(this.getTokenForTokenPool.bind(this));
88
+ this.getNativeTokenForRouter = memoize(this.getNativeTokenForRouter.bind(this), {
69
89
  maxArgs: 1,
70
- isPromise: true,
90
+ async: true,
71
91
  });
72
- this.getTokenInfo = moize.default(this.getTokenInfo.bind(this));
73
- this.getWallet = moize.default(this.getWallet.bind(this), { maxSize: 1, maxArgs: 0 });
74
- this.getTokenAdminRegistryFor = moize.default(this.getTokenAdminRegistryFor.bind(this), {
75
- isPromise: true,
92
+ this.getTokenInfo = memoize(this.getTokenInfo.bind(this));
93
+ this.getTokenAdminRegistryFor = memoize(this.getTokenAdminRegistryFor.bind(this), {
94
+ async: true,
76
95
  maxArgs: 1,
77
96
  });
78
- }
79
- // overwrite EVMChain.getWallet to implement custom wallet loading
80
- // some signers don't like to be `.connect`ed, so pass provider as first param
81
- static getWallet(_provider, _opts) {
82
- throw new Error('static EVM wallet loading not available');
83
- }
84
- // cached wallet/signer getter
85
- async getWallet(opts = {}) {
86
- if (typeof opts.wallet === 'number' ||
87
- (typeof opts.wallet === 'string' && opts.wallet.match(/^(\d+|0x[a-fA-F0-9]{40})$/))) {
88
- // if given a number, numeric string or address, use ethers `provider.getSigner` (e.g. geth or MM)
89
- return this.provider.getSigner(typeof opts.wallet === 'string' && opts.wallet.match(/^0x[a-fA-F0-9]{40}$/)
90
- ? opts.wallet
91
- : Number(opts.wallet));
92
- }
93
- else if (typeof opts.wallet === 'string') {
94
- // support receiving private key directly (not recommended)
95
- try {
96
- return Promise.resolve(new BaseWallet(new SigningKey((opts.wallet.startsWith('0x') ? '' : '0x') + opts.wallet), this.provider));
97
- }
98
- catch (_) {
99
- // pass
100
- }
101
- }
102
- else if (opts.wallet instanceof AbstractSigner) {
103
- // if given a signer, return/cache it
104
- return opts.wallet;
105
- }
106
- return this.constructor.getWallet(this.provider, opts);
97
+ this.getFeeTokens = memoize(this.getFeeTokens.bind(this), { async: true, maxArgs: 1 });
107
98
  }
108
99
  /**
109
100
  * Expose ethers provider's `listAccounts`, if provider supports it
@@ -111,9 +102,11 @@ export class EVMChain extends Chain {
111
102
  async listAccounts() {
112
103
  return (await this.provider.listAccounts()).map(({ address }) => address);
113
104
  }
114
- async getWalletAddress(opts) {
115
- return (await this.getWallet(opts)).getAddress();
116
- }
105
+ /**
106
+ * Creates a JSON-RPC provider from a URL.
107
+ * @param url - WebSocket (wss://) or HTTP (https://) endpoint URL.
108
+ * @returns A ready JSON-RPC provider.
109
+ */
117
110
  static async _getProvider(url) {
118
111
  let provider;
119
112
  let providerReady;
@@ -137,28 +130,38 @@ export class EVMChain extends Chain {
137
130
  }
138
131
  return providerReady;
139
132
  }
140
- static async fromProvider(provider) {
133
+ /**
134
+ * Creates an EVMChain instance from an existing provider.
135
+ * @param provider - JSON-RPC provider instance.
136
+ * @param ctx - context containing logger.
137
+ * @returns A new EVMChain instance.
138
+ */
139
+ static async fromProvider(provider, ctx) {
141
140
  try {
142
- return new EVMChain(provider, networkInfo(Number((await provider.getNetwork()).chainId)));
141
+ return new EVMChain(provider, networkInfo(Number((await provider.getNetwork()).chainId)), ctx);
143
142
  }
144
143
  catch (err) {
145
144
  provider.destroy();
146
145
  throw err;
147
146
  }
148
147
  }
149
- static async fromUrl(url) {
150
- return this.fromProvider(await this._getProvider(url));
151
- }
152
- // eslint-disable-next-line @typescript-eslint/require-await
153
- async destroy() {
154
- this.provider.destroy();
148
+ /**
149
+ * Creates an EVMChain instance from an RPC URL.
150
+ * @param url - WebSocket (wss://) or HTTP (https://) endpoint URL.
151
+ * @param ctx - context containing logger.
152
+ * @returns A new EVMChain instance.
153
+ */
154
+ static async fromUrl(url, ctx) {
155
+ return this.fromProvider(await this._getProvider(url), ctx);
155
156
  }
157
+ /** {@inheritDoc Chain.getBlockTimestamp} */
156
158
  async getBlockTimestamp(block) {
157
- const res = await this.provider.getBlock(block);
159
+ const res = await this.provider.getBlock(block); // cached
158
160
  if (!res)
159
161
  throw new Error(`Block not found: ${block}`);
160
162
  return res.timestamp;
161
163
  }
164
+ /** {@inheritDoc Chain.getTransaction} */
162
165
  async getTransaction(hash) {
163
166
  const tx = typeof hash === 'string' ? await this.provider.getTransactionReceipt(hash) : hash;
164
167
  if (!tx)
@@ -166,7 +169,6 @@ export class EVMChain extends Chain {
166
169
  const timestamp = await this.getBlockTimestamp(tx.blockNumber);
167
170
  const chainTx = {
168
171
  ...tx,
169
- chain: this,
170
172
  timestamp,
171
173
  logs: [],
172
174
  };
@@ -174,39 +176,40 @@ export class EVMChain extends Chain {
174
176
  chainTx.logs = logs;
175
177
  return chainTx;
176
178
  }
179
+ /** {@inheritDoc Chain.getLogs} */
177
180
  async *getLogs(filter) {
178
- const endBlock = filter.endBlock ?? (await this.provider.getBlockNumber());
179
- if (filter.topics?.length &&
180
- filter.topics.every((t) => typeof t === 'string')) {
181
- const topics = new Set(filter.topics
182
- .filter(isHexString)
183
- .concat(Object.keys(getAllFragmentsMatchingEvents(filter.topics)))
184
- .flat());
185
- if (!topics.size) {
186
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
187
- throw new Error(`Could not find matching topics: ${filter.topics}`);
188
- }
189
- filter.topics = [Array.from(topics)];
190
- }
191
- if (!filter.startBlock && filter.startTime) {
192
- filter.startBlock = await getSomeBlockNumberBefore(this.getBlockTimestamp.bind(this), endBlock, filter.startTime);
193
- }
194
- for (const blockRange of blockRangeGenerator({ ...filter, endBlock })) {
195
- console.debug('evm getLogs:', {
196
- ...blockRange,
197
- ...(filter.address ? { address: filter.address } : {}),
198
- ...(filter.topics?.length ? { topics: filter.topics } : {}),
199
- });
200
- const logs = await this.provider.getLogs({
201
- ...blockRange,
202
- ...(filter.address ? { address: filter.address } : {}),
203
- ...(filter.topics?.length ? { topics: filter.topics } : {}),
204
- });
205
- if (!filter.startBlock)
206
- logs.reverse();
207
- yield* logs;
181
+ yield* getEvmLogs(filter, this);
182
+ }
183
+ /** {@inheritDoc Chain.fetchRequestsInTx} */
184
+ async fetchRequestsInTx(tx) {
185
+ return fetchCCIPRequestsInTx(this, typeof tx === 'string' ? await this.getTransaction(tx) : tx);
186
+ }
187
+ /** {@inheritDoc Chain.fetchRequestById} */
188
+ fetchRequestById(messageId, onRamp, opts) {
189
+ return fetchCCIPRequestById(this, messageId, { address: onRamp, ...opts });
190
+ }
191
+ /** {@inheritDoc Chain.fetchAllMessagesInBatch} */
192
+ async fetchAllMessagesInBatch(request, commit, opts) {
193
+ let opts_;
194
+ if (request.lane.version >= CCIPVersion.V1_6) {
195
+ // specialized getLogs filter for v1.6 CCIPMessageSent events, to filter by dest
196
+ opts_ = {
197
+ ...opts,
198
+ topics: [[request.log.topics[0]], [toBeHex(request.lane.destChainSelector, 32)]],
199
+ };
208
200
  }
201
+ return fetchAllMessagesInBatch(this, request, commit, opts_);
202
+ }
203
+ /** {@inheritDoc Chain.typeAndVersion} */
204
+ async typeAndVersion(address) {
205
+ const contract = new Contract(address, VersionedContractABI, this.provider);
206
+ return parseTypeAndVersion(await contract.typeAndVersion());
209
207
  }
208
+ /**
209
+ * Decodes a CCIP message from a log event.
210
+ * @param log - Log event with topics and data.
211
+ * @returns Decoded CCIPMessage or undefined if not a valid CCIP message.
212
+ */
210
213
  static decodeMessage(log) {
211
214
  if (!isBytesLike(log.data))
212
215
  throw new Error(`invalid data=${util.inspect(log.data)}`);
@@ -259,7 +262,7 @@ export class EVMChain extends Chain {
259
262
  };
260
263
  }
261
264
  catch (_) {
262
- console.debug('legacy sourceTokenData:', i, message.sourceTokenData[i]);
265
+ // legacy sourceTokenData
263
266
  }
264
267
  }
265
268
  if (typeof tokenAmount.destExecData === 'string' && tokenAmount.destGasAmount == null) {
@@ -294,6 +297,12 @@ export class EVMChain extends Chain {
294
297
  }
295
298
  return message;
296
299
  }
300
+ /**
301
+ * Decodes commit reports from a log event.
302
+ * @param log - Log event with topics and data.
303
+ * @param lane - Lane info (required for CCIP v1.5 and earlier).
304
+ * @returns Array of CommitReport or undefined if not a valid commit event.
305
+ */
297
306
  static decodeCommits(log, lane) {
298
307
  if (!isBytesLike(log.data))
299
308
  throw new Error(`invalid data=${util.inspect(log.data)}`);
@@ -348,6 +357,11 @@ export class EVMChain extends Chain {
348
357
  }
349
358
  }
350
359
  }
360
+ /**
361
+ * Decodes an execution receipt from a log event.
362
+ * @param log - Log event with topics and data.
363
+ * @returns ExecutionReceipt or undefined if not a valid execution event.
364
+ */
351
365
  static decodeReceipt(log) {
352
366
  if (!isBytesLike(log.data))
353
367
  throw new Error(`invalid data=${util.inspect(log.data)}`);
@@ -373,6 +387,11 @@ export class EVMChain extends Chain {
373
387
  }
374
388
  }
375
389
  }
390
+ /**
391
+ * Decodes extra arguments from a CCIP message.
392
+ * @param extraArgs - Encoded extra arguments bytes.
393
+ * @returns Decoded extra arguments with tag, or undefined if unknown format.
394
+ */
376
395
  static decodeExtraArgs(extraArgs) {
377
396
  const data = getDataBytes(extraArgs), tag = dataSlice(data, 0, 4);
378
397
  switch (tag) {
@@ -404,6 +423,11 @@ export class EVMChain extends Chain {
404
423
  return undefined;
405
424
  }
406
425
  }
426
+ /**
427
+ * Encodes extra arguments for a CCIP message.
428
+ * @param args - Extra arguments to encode.
429
+ * @returns Encoded extra arguments as hex string.
430
+ */
407
431
  static encodeExtraArgs(args) {
408
432
  if (!args)
409
433
  return '0x';
@@ -441,6 +465,11 @@ export class EVMChain extends Chain {
441
465
  }
442
466
  return '0x';
443
467
  }
468
+ /**
469
+ * Converts bytes to a checksummed EVM address.
470
+ * @param bytes - Bytes to convert (must be 20 bytes or 32 bytes with leading zeros).
471
+ * @returns Checksummed EVM address.
472
+ */
444
473
  static getAddress(bytes) {
445
474
  bytes = getBytes(bytes);
446
475
  if (bytes.length < 20)
@@ -455,10 +484,11 @@ export class EVMChain extends Chain {
455
484
  }
456
485
  return getAddress(hexlify(bytes));
457
486
  }
458
- async typeAndVersion(address) {
459
- const contract = new Contract(address, VersionedContractABI, this.provider);
460
- return parseTypeAndVersion(await contract.typeAndVersion());
461
- }
487
+ /**
488
+ * Gets lane configuration from an OnRamp contract.
489
+ * @param onRamp - OnRamp contract address.
490
+ * @returns Lane configuration.
491
+ */
462
492
  async getLaneForOnRamp(onRamp) {
463
493
  const [, version] = await this.typeAndVersion(onRamp);
464
494
  const onRampABI = version === CCIPVersion.V1_2 ? EVM2EVMOnRamp_1_2_ABI : EVM2EVMOnRamp_1_5_ABI;
@@ -474,6 +504,7 @@ export class EVMChain extends Chain {
474
504
  onRamp,
475
505
  };
476
506
  }
507
+ /** {@inheritDoc Chain.getRouterForOnRamp} */
477
508
  async getRouterForOnRamp(onRamp, destChainSelector) {
478
509
  const [, version] = await this.typeAndVersion(onRamp);
479
510
  let onRampABI;
@@ -497,6 +528,7 @@ export class EVMChain extends Chain {
497
528
  throw new Error(`Unsupported version: ${version}`);
498
529
  }
499
530
  }
531
+ /** {@inheritDoc Chain.getRouterForOffRamp} */
500
532
  async getRouterForOffRamp(offRamp, sourceChainSelector) {
501
533
  const [, version] = await this.typeAndVersion(offRamp);
502
534
  let offRampABI, router;
@@ -521,10 +553,12 @@ export class EVMChain extends Chain {
521
553
  }
522
554
  return router;
523
555
  }
556
+ /** {@inheritDoc Chain.getNativeTokenForRouter} */
524
557
  async getNativeTokenForRouter(router) {
525
558
  const contract = new Contract(router, interfaces.Router, this.provider);
526
559
  return contract.getWrappedNative();
527
560
  }
561
+ /** {@inheritDoc Chain.getOffRampsForRouter} */
528
562
  async getOffRampsForRouter(router, sourceChainSelector) {
529
563
  const contract = new Contract(router, interfaces.Router, this.provider);
530
564
  const offRamps = await contract.getOffRamps();
@@ -532,10 +566,12 @@ export class EVMChain extends Chain {
532
566
  .filter((offRamp) => offRamp.sourceChainSelector === sourceChainSelector)
533
567
  .map(({ offRamp }) => offRamp);
534
568
  }
569
+ /** {@inheritDoc Chain.getOnRampForRouter} */
535
570
  async getOnRampForRouter(router, destChainSelector) {
536
571
  const contract = new Contract(router, interfaces.Router, this.provider);
537
572
  return contract.getOnRamp(destChainSelector);
538
573
  }
574
+ /** {@inheritDoc Chain.getOnRampForOffRamp} */
539
575
  async getOnRampForOffRamp(offRamp, sourceChainSelector) {
540
576
  const [, version] = await this.typeAndVersion(offRamp);
541
577
  let offRampABI;
@@ -559,6 +595,7 @@ export class EVMChain extends Chain {
559
595
  throw new Error(`Unsupported version: ${version}`);
560
596
  }
561
597
  }
598
+ /** {@inheritDoc Chain.getCommitStoreForOffRamp} */
562
599
  async getCommitStoreForOffRamp(offRamp) {
563
600
  const [, version] = await this.typeAndVersion(offRamp);
564
601
  let offRampABI;
@@ -579,10 +616,12 @@ export class EVMChain extends Chain {
579
616
  throw new Error(`Unsupported version: ${version}`);
580
617
  }
581
618
  }
619
+ /** {@inheritDoc Chain.getTokenForTokenPool} */
582
620
  async getTokenForTokenPool(tokenPool) {
583
621
  const contract = new Contract(tokenPool, interfaces.TokenPool_v1_6, this.provider);
584
622
  return contract.getToken();
585
623
  }
624
+ /** {@inheritDoc Chain.getTokenInfo} */
586
625
  async getTokenInfo(token) {
587
626
  const contract = new Contract(token, interfaces.Token, this.provider);
588
627
  const [symbol, decimals, name] = await Promise.all([
@@ -592,7 +631,13 @@ export class EVMChain extends Chain {
592
631
  ]);
593
632
  return { symbol, decimals: Number(decimals), name };
594
633
  }
595
- static getDestLeafHasher({ sourceChainSelector, destChainSelector, onRamp, version, }) {
634
+ /**
635
+ * Gets the leaf hasher for computing Merkle proofs on the destination chain.
636
+ * @param lane - Lane configuration.
637
+ * @param ctx - Context object containing logger.
638
+ * @returns Leaf hasher function.
639
+ */
640
+ static getDestLeafHasher({ sourceChainSelector, destChainSelector, onRamp, version }, ctx) {
596
641
  switch (version) {
597
642
  case CCIPVersion.V1_2:
598
643
  case CCIPVersion.V1_5:
@@ -600,11 +645,16 @@ export class EVMChain extends Chain {
600
645
  throw new Error(`Unsupported source chain: ${sourceChainSelector}`);
601
646
  return getV12LeafHasher(sourceChainSelector, destChainSelector, onRamp);
602
647
  case CCIPVersion.V1_6:
603
- return getV16LeafHasher(sourceChainSelector, destChainSelector, onRamp);
648
+ return getV16LeafHasher(sourceChainSelector, destChainSelector, onRamp, ctx);
604
649
  default:
605
650
  throw new Error(`Unsupported hasher version for EVM: ${version}`);
606
651
  }
607
652
  }
653
+ /**
654
+ * Gets any available OnRamp for the given router.
655
+ * @param router - Router contract address.
656
+ * @returns OnRamp contract address.
657
+ */
608
658
  async _getSomeOnRampFor(router) {
609
659
  // when given a router, we take any onRamp we can find, as usually they all use same registry
610
660
  const someOtherNetwork = this.network.isTestnet
@@ -616,6 +666,7 @@ export class EVMChain extends Chain {
616
666
  : 'ethereum-mainnet';
617
667
  return this.getOnRampForRouter(router, networkInfo(someOtherNetwork).chainSelector);
618
668
  }
669
+ /** {@inheritDoc Chain.getTokenAdminRegistryFor} */
619
670
  async getTokenAdminRegistryFor(address) {
620
671
  let [type, version, typeAndVersion] = await this.typeAndVersion(address);
621
672
  if (type === 'TokenAdminRegistry') {
@@ -638,6 +689,11 @@ export class EVMChain extends Chain {
638
689
  const { tokenAdminRegistry } = await contract.getStaticConfig();
639
690
  return tokenAdminRegistry;
640
691
  }
692
+ /**
693
+ * Gets the FeeQuoter contract address for a given Router or Ramp.
694
+ * @param address - Router or Ramp contract address.
695
+ * @returns FeeQuoter contract address.
696
+ */
641
697
  async getFeeQuoterFor(address) {
642
698
  let [type, version, typeAndVersion] = await this.typeAndVersion(address);
643
699
  if (type === 'FeeQuoter') {
@@ -656,6 +712,7 @@ export class EVMChain extends Chain {
656
712
  const { feeQuoter } = await contract.getDynamicConfig();
657
713
  return feeQuoter;
658
714
  }
715
+ /** {@inheritDoc Chain.getFee} */
659
716
  async getFee(router_, destChainSelector, message) {
660
717
  const router = new Contract(router_, interfaces.Router, this.provider);
661
718
  return router.getFee(destChainSelector, {
@@ -666,7 +723,19 @@ export class EVMChain extends Chain {
666
723
  extraArgs: hexlify(this.constructor.encodeExtraArgs(message.extraArgs)),
667
724
  });
668
725
  }
669
- async sendMessage(router_, destChainSelector, message, opts) {
726
+ /**
727
+ * Generate unsigned txs for ccipSend'ing a message
728
+ * @param sender - sender address
729
+ * @param router - address of the Router contract
730
+ * @param destChainSelector - chainSelector of destination chain
731
+ * @param message - AnyMessage to send; if `fee` is not present, it'll be calculated
732
+ * @param approveMax - if tokens approvals are needed, opt into approving maximum allowance
733
+ * @returns Array containing 0 or more unsigned token approvals txs (if needed at the time of
734
+ * generation), followed by a ccipSend TransactionRequest
735
+ */
736
+ async generateUnsignedSendMessage(sender, router, destChainSelector, message, opts) {
737
+ if (!message.fee)
738
+ message.fee = await this.getFee(router, destChainSelector, message);
670
739
  const feeToken = message.feeToken ?? ZeroAddress;
671
740
  const receiver = zeroPadValue(getAddressBytes(message.receiver), 32);
672
741
  const data = hexlify(message.data);
@@ -675,52 +744,85 @@ export class EVMChain extends Chain {
675
744
  const amountsToApprove = (message.tokenAmounts ?? []).reduce((acc, { token, amount }) => ({ ...acc, [token]: (acc[token] ?? 0n) + amount }), {});
676
745
  if (feeToken !== ZeroAddress)
677
746
  amountsToApprove[feeToken] = (amountsToApprove[feeToken] ?? 0n) + message.fee;
678
- const wallet = await this.getWallet(opts); // moized wallet arg (if called previously)
679
- // approve all tokens (including fee token) in parallel
680
- let nonce = await this.provider.getTransactionCount(await this.getWalletAddress());
681
- await Promise.all(Object.entries(amountsToApprove).map(async ([token, amount]) => {
682
- const contract = new Contract(token, interfaces.Token, wallet);
683
- const allowance = await contract.allowance(await wallet.getAddress(), router_);
684
- if (allowance < amount) {
685
- const amnt = opts?.approveMax ? 2n ** 256n - 1n : amount;
686
- // optimization: hardcode nonce and gasLimit to send all approvals in parallel without estimating
687
- console.info('Approving', amnt, 'of', token, 'tokens for router', router_);
688
- const tx = await contract.approve(router_, amnt, {
689
- nonce: nonce++,
690
- gasLimit: DEFAULT_APPROVE_GAS_LIMIT,
691
- });
692
- console.info('=>', tx.hash);
693
- await tx.wait(1, 60_000);
694
- }
695
- }));
696
- const router = new Contract(router_, interfaces.Router, wallet);
697
- const tx = await router.ccipSend(destChainSelector, {
747
+ const approveTxs = (await Promise.all(Object.entries(amountsToApprove).map(async ([token, amount]) => {
748
+ const contract = new Contract(token, interfaces.Token, this.provider);
749
+ const allowance = await contract.allowance(sender, router);
750
+ if (allowance >= amount)
751
+ return;
752
+ const amnt = opts?.approveMax ? 2n ** 256n - 1n : amount;
753
+ return contract.approve.populateTransaction(router, amnt, { from: sender });
754
+ }))).filter((tx) => tx != null);
755
+ const contract = new Contract(router, interfaces.Router, this.provider);
756
+ const sendTx = await contract.ccipSend.populateTransaction(destChainSelector, {
698
757
  receiver,
699
758
  data,
700
759
  tokenAmounts: message.tokenAmounts ?? [],
701
760
  extraArgs,
702
761
  feeToken,
703
762
  }, {
704
- nonce: nonce++,
763
+ from: sender,
705
764
  // if native fee, include it in value; otherwise, it's transferedFrom feeToken
706
- ...(feeToken === ZeroAddress ? { value: message.fee } : {}),
765
+ ...(feeToken === ZeroAddress && { value: message.fee }),
707
766
  });
708
- const receipt = await tx.wait(1);
709
- return this.getTransaction(receipt);
767
+ const txRequests = [...approveTxs, sendTx];
768
+ return {
769
+ family: ChainFamily.EVM,
770
+ transactions: txRequests,
771
+ };
772
+ }
773
+ /** {@inheritDoc Chain.sendMessage} */
774
+ async sendMessage(router_, destChainSelector, message, opts) {
775
+ const wallet = opts.wallet;
776
+ if (!isSigner(wallet))
777
+ throw new Error(`Wallet must be a Signer, got=${util.inspect(wallet)}`);
778
+ const sender = await wallet.getAddress();
779
+ const txs = await this.generateUnsignedSendMessage(sender, router_, destChainSelector, message, opts);
780
+ const approveTxs = txs.transactions.slice(0, txs.transactions.length - 1);
781
+ let sendTx = txs.transactions[txs.transactions.length - 1];
782
+ // approve all tokens (including feeToken, if needed) in parallel
783
+ let nonce = await this.provider.getTransactionCount(sender);
784
+ const responses = await Promise.all(approveTxs.map(async (tx) => {
785
+ tx.nonce = nonce++;
786
+ tx = await wallet.populateTransaction(tx);
787
+ tx.from = undefined;
788
+ const signed = await wallet.signTransaction(tx);
789
+ const response = await this.provider.broadcastTransaction(signed);
790
+ this.logger.debug('approve =>', response.hash);
791
+ return response;
792
+ }));
793
+ if (responses.length)
794
+ await responses[responses.length - 1].wait(1, 60_000); // wait last tx nonce to be mined
795
+ sendTx.nonce = nonce++;
796
+ // sendTx.gasLimit = await this.provider.estimateGas(sendTx)
797
+ sendTx = await wallet.populateTransaction(sendTx);
798
+ sendTx.from = undefined; // some signers don't like receiving pre-populated `from`
799
+ const signed = await wallet.signTransaction(sendTx);
800
+ const response = await this.provider.broadcastTransaction(signed);
801
+ this.logger.debug('ccipSend =>', response.hash);
802
+ await response.wait(1, 60_000);
803
+ return (await this.fetchRequestsInTx(await this.getTransaction(response.hash)))[0];
710
804
  }
805
+ /** {@inheritDoc Chain.fetchOffchainTokenData} */
711
806
  fetchOffchainTokenData(request) {
712
- return fetchEVMOffchainTokenData(request);
807
+ return fetchEVMOffchainTokenData(request, this);
713
808
  }
714
- async executeReport(offRamp, execReport, opts) {
809
+ /**
810
+ * Generate unsigned tx to manuallyExecute a message
811
+ * @param _payer - not used in EVM
812
+ * @param offRamp - address of the OffRamp contract
813
+ * @param execReport - execution report
814
+ * @param opts - gas limit overrides for ccipReceive and tokenPool calls options
815
+ * @returns array containing one unsigned `manuallyExecute` TransactionRequest object
816
+ */
817
+ async generateUnsignedExecuteReport(_payer, offRamp, execReport, opts) {
715
818
  const [_, version] = await this.typeAndVersion(offRamp);
716
- const wallet = await this.getWallet(opts);
717
819
  let manualExecTx;
718
820
  const offchainTokenData = execReport.offchainTokenData.map(encodeEVMOffchainTokenData);
719
821
  switch (version) {
720
822
  case CCIPVersion.V1_2: {
721
- const contract = new Contract(offRamp, EVM2EVMOffRamp_1_2_ABI, wallet);
823
+ const contract = new Contract(offRamp, EVM2EVMOffRamp_1_2_ABI, this.provider);
722
824
  const gasOverride = BigInt(opts?.gasLimit ?? 0);
723
- manualExecTx = await contract.manuallyExecute({
825
+ manualExecTx = await contract.manuallyExecute.populateTransaction({
724
826
  ...execReport,
725
827
  proofs: execReport.proofs.map((d) => hexlify(d)),
726
828
  messages: [execReport.message],
@@ -729,8 +831,8 @@ export class EVMChain extends Chain {
729
831
  break;
730
832
  }
731
833
  case CCIPVersion.V1_5: {
732
- const contract = new Contract(offRamp, EVM2EVMOffRamp_1_5_ABI, wallet);
733
- manualExecTx = await contract.manuallyExecute({
834
+ const contract = new Contract(offRamp, EVM2EVMOffRamp_1_5_ABI, this.provider);
835
+ manualExecTx = await contract.manuallyExecute.populateTransaction({
734
836
  ...execReport,
735
837
  proofs: execReport.proofs.map((d) => hexlify(d)),
736
838
  messages: [execReport.message],
@@ -756,8 +858,8 @@ export class EVMChain extends Chain {
756
858
  sender,
757
859
  tokenAmounts,
758
860
  };
759
- const contract = new Contract(offRamp, OffRamp_1_6_ABI, wallet);
760
- manualExecTx = await contract.manuallyExecute([
861
+ const contract = new Contract(offRamp, OffRamp_1_6_ABI, this.provider);
862
+ manualExecTx = await contract.manuallyExecute.populateTransaction([
761
863
  {
762
864
  ...execReport,
763
865
  proofs: execReport.proofs.map((p) => hexlify(p)),
@@ -778,20 +880,38 @@ export class EVMChain extends Chain {
778
880
  default:
779
881
  throw new Error(`Unsupported version: ${version}`);
780
882
  }
781
- const receipt = await this.provider.waitForTransaction(manualExecTx.hash, 1, 60e3);
883
+ return { family: ChainFamily.EVM, transactions: [manualExecTx] };
884
+ }
885
+ /** {@inheritDoc Chain.executeReport} */
886
+ async executeReport(offRamp, execReport, opts) {
887
+ const wallet = opts.wallet;
888
+ if (!isSigner(wallet))
889
+ throw new Error(`Wallet must be a Signer, got=${util.inspect(wallet)}`);
890
+ const unsignedTxs = await this.generateUnsignedExecuteReport(await wallet.getAddress(), offRamp, execReport, opts);
891
+ const unsignedTx = await wallet.populateTransaction(unsignedTxs.transactions[0]);
892
+ unsignedTx.from = undefined; // some signers don't like receiving pre-populated `from`
893
+ const signed = await wallet.signTransaction(unsignedTx);
894
+ const response = await this.provider.broadcastTransaction(signed);
895
+ this.logger.debug('ccipSend =>', response.hash);
896
+ const receipt = await response.wait(1, 60_000);
782
897
  if (!receipt?.hash)
783
- throw new Error(`Could not confirm exec tx: ${manualExecTx.hash}`);
898
+ throw new Error(`Could not confirm exec tx: ${response.hash}`);
784
899
  if (!receipt.status)
785
- throw new Error(`Exec transaction reverted: ${manualExecTx.hash}`);
900
+ throw new Error(`Exec transaction reverted: ${response.hash}`);
786
901
  return this.getTransaction(receipt);
787
902
  }
903
+ /**
904
+ * Parses raw data into typed structures.
905
+ * @param data - Raw data to parse.
906
+ * @returns Parsed data.
907
+ */
788
908
  static parse(data) {
789
909
  return parseData(data);
790
910
  }
791
911
  /**
792
- * Get the supported tokens for a given contract address
793
- *
794
- * @param address Router, OnRamp, OffRamp or TokenAdminRegistry contract
912
+ * Get the supported tokens for a given contract address.
913
+ * @param registry - Router, OnRamp, OffRamp or TokenAdminRegistry contract address.
914
+ * @param opts - Optional parameters.
795
915
  * @returns An array of supported token addresses.
796
916
  */
797
917
  async getSupportedTokens(registry, opts) {
@@ -805,6 +925,7 @@ export class EVMChain extends Chain {
805
925
  } while (page.length === limit);
806
926
  return res;
807
927
  }
928
+ /** {@inheritDoc Chain.getRegistryTokenConfig} */
808
929
  async getRegistryTokenConfig(registry, token) {
809
930
  const contract = new Contract(registry, interfaces.TokenAdminRegistry, this.provider);
810
931
  const config = (await resultToObject(contract.getTokenConfig(token)));
@@ -819,6 +940,7 @@ export class EVMChain extends Chain {
819
940
  administrator: config.administrator,
820
941
  };
821
942
  }
943
+ /** {@inheritDoc Chain.getTokenPoolConfigs} */
822
944
  async getTokenPoolConfigs(tokenPool) {
823
945
  const [_, , typeAndVersion] = await this.typeAndVersion(tokenPool);
824
946
  const contract = new Contract(tokenPool, interfaces.TokenPool_v1_6, this.provider);
@@ -832,6 +954,7 @@ export class EVMChain extends Chain {
832
954
  };
833
955
  });
834
956
  }
957
+ /** {@inheritDoc Chain.getTokenPoolRemotes} */
835
958
  async getTokenPoolRemotes(tokenPool, remoteChainSelector) {
836
959
  const [_, version] = await this.typeAndVersion(tokenPool);
837
960
  let supportedChains;
@@ -870,22 +993,30 @@ export class EVMChain extends Chain {
870
993
  },
871
994
  ])));
872
995
  }
873
- async listFeeTokens(router) {
996
+ /** {@inheritDoc Chain.getFeeTokens} */
997
+ async getFeeTokens(router) {
874
998
  const onRamp = await this._getSomeOnRampFor(router);
875
999
  const [_, version] = await this.typeAndVersion(onRamp);
876
1000
  let tokens;
877
- let onRampABI;
1001
+ let onRampIface;
878
1002
  switch (version) {
879
1003
  case CCIPVersion.V1_2:
880
- onRampABI = EVM2EVMOnRamp_1_2_ABI;
1004
+ onRampIface = interfaces.EVM2EVMOnRamp_v1_2;
881
1005
  // falls through
882
1006
  case CCIPVersion.V1_5: {
883
- onRampABI ??= EVM2EVMOnRamp_1_5_ABI;
884
- const contract = new Contract(onRamp, onRampABI, this.provider);
885
- tokens = await Promise.all([
886
- this.getNativeTokenForRouter(router),
887
- contract.getStaticConfig().then(({ linkToken }) => linkToken),
888
- ]);
1007
+ onRampIface ??= interfaces.EVM2EVMOnRamp_v1_5;
1008
+ const fragment = onRampIface.getEvent('FeeConfigSet');
1009
+ const tokens_ = new Set();
1010
+ for await (const log of this.getLogs({
1011
+ address: onRamp,
1012
+ topics: [fragment.topicHash],
1013
+ startBlock: 1,
1014
+ onlyFallback: true,
1015
+ })) {
1016
+ ;
1017
+ onRampIface.decodeEventLog(fragment, log.data, log.topics).feeConfig.forEach(({ token, enabled }) => enabled ? tokens_.add(token) : tokens_.delete(token));
1018
+ }
1019
+ tokens = Array.from(tokens_);
889
1020
  break;
890
1021
  }
891
1022
  case CCIPVersion.V1_6: {
@@ -899,6 +1030,33 @@ export class EVMChain extends Chain {
899
1030
  }
900
1031
  return Object.fromEntries(await Promise.all(tokens.map(async (token) => [token, await this.getTokenInfo(token)])));
901
1032
  }
1033
+ /** {@inheritDoc Chain.fetchExecutionReceipts} */
1034
+ async *fetchExecutionReceipts(offRamp, request, commit, opts) {
1035
+ let opts_ = opts;
1036
+ if (request.lane.version < CCIPVersion.V1_6) {
1037
+ opts_ = {
1038
+ ...opts,
1039
+ topics: [
1040
+ interfaces.EVM2EVMOffRamp_v1_5.getEvent('ExecutionStateChanged').topicHash,
1041
+ null,
1042
+ request.message.header.messageId,
1043
+ ],
1044
+ // onlyFallback: false,
1045
+ };
1046
+ }
1047
+ else /* >= V1.6 */ {
1048
+ opts_ = {
1049
+ ...opts,
1050
+ topics: [
1051
+ interfaces.OffRamp_v1_6.getEvent('ExecutionStateChanged').topicHash,
1052
+ toBeHex(request.lane.sourceChainSelector, 32),
1053
+ null,
1054
+ request.message.header.messageId,
1055
+ ],
1056
+ // onlyFallback: false,
1057
+ };
1058
+ }
1059
+ yield* super.fetchExecutionReceipts(offRamp, request, commit, opts_);
1060
+ }
902
1061
  }
903
- supportedChains[ChainFamily.EVM] = EVMChain;
904
1062
  //# sourceMappingURL=index.js.map