@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
package/src/evm/const.ts CHANGED
@@ -19,6 +19,7 @@ import OnRamp_2_0_ABI from './abi/OnRamp_2_0.ts'
19
19
  import PriceRegistry_1_2_ABI from './abi/PriceRegistry_1_2.ts'
20
20
  import Router_ABI from './abi/Router.ts'
21
21
  import TokenAdminRegistry_ABI from './abi/TokenAdminRegistry_1_5.ts'
22
+ import TokenPool_2_0_ABI from './abi/TokenPool_2_0.ts'
22
23
 
23
24
  export const defaultAbiCoder = AbiCoder.defaultAbiCoder()
24
25
 
@@ -38,6 +39,7 @@ export const interfaces = {
38
39
  FeeQuoter: new Interface(FeeQuoter_ABI),
39
40
  TokenPool_v1_5_1: new Interface(TokenPool_1_5_1_ABI),
40
41
  TokenPool_v1_5: new Interface(TokenPool_1_5_ABI),
42
+ TokenPool_v2_0: new Interface(TokenPool_2_0_ABI),
41
43
  TokenPool_v1_6: new Interface(TokenPool_1_6_ABI),
42
44
  CommitStore_v1_5: new Interface(CommitStore_1_5_ABI),
43
45
  CommitStore_v1_2: new Interface(CommitStore_1_2_ABI),
package/src/evm/index.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  getAddress,
16
16
  hexlify,
17
17
  isBytesLike,
18
+ isError,
18
19
  isHexString,
19
20
  keccak256,
20
21
  toBeHex,
@@ -27,9 +28,12 @@ import type { PickDeep, SetRequired } from 'type-fest'
27
28
  import {
28
29
  type ChainContext,
29
30
  type GetBalanceOpts,
31
+ type LaneFeatures,
30
32
  type LogFilter,
33
+ type RateLimiterState,
31
34
  type TokenPoolRemote,
32
35
  Chain,
36
+ LaneFeature,
33
37
  } from '../chain.ts'
34
38
  import {
35
39
  CCIPAddressInvalidEvmError,
@@ -38,11 +42,11 @@ import {
38
42
  CCIPContractNotRouterError,
39
43
  CCIPContractTypeInvalidError,
40
44
  CCIPDataFormatUnsupportedError,
45
+ CCIPError,
41
46
  CCIPExecTxNotConfirmedError,
42
47
  CCIPExecTxRevertedError,
43
48
  CCIPHasherVersionUnsupportedError,
44
49
  CCIPLogDataInvalidError,
45
- CCIPNotImplementedError,
46
50
  CCIPSourceChainUnsupportedError,
47
51
  CCIPTokenNotConfiguredError,
48
52
  CCIPTokenPoolChainConfigNotFoundError,
@@ -60,15 +64,14 @@ import {
60
64
  type CCIPMessage,
61
65
  type CCIPRequest,
62
66
  type CCIPVerifications,
67
+ type ChainLog,
63
68
  type ChainTransaction,
64
69
  type CommitReport,
65
70
  type ExecutionInput,
66
71
  type ExecutionReceipt,
67
72
  type ExecutionState,
68
73
  type Lane,
69
- type Log_,
70
74
  type NetworkInfo,
71
- type OffchainTokenData,
72
75
  type WithLogger,
73
76
  CCIPVersion,
74
77
  ChainFamily,
@@ -96,6 +99,7 @@ import type OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
96
99
  import type OnRamp_2_0_ABI from './abi/OnRamp_2_0.ts'
97
100
  import type Router_ABI from './abi/Router.ts'
98
101
  import type TokenAdminRegistry_1_5_ABI from './abi/TokenAdminRegistry_1_5.ts'
102
+ import type TokenPool_2_0_ABI from './abi/TokenPool_2_0.ts'
99
103
  import {
100
104
  CCV_INDEXER_URL,
101
105
  VersionedContractABI,
@@ -112,21 +116,21 @@ import {
112
116
  import { estimateExecGas } from './gas.ts'
113
117
  import { getV12LeafHasher, getV16LeafHasher } from './hasher.ts'
114
118
  import { getEvmLogs } from './logs.ts'
115
- import {
116
- type CCIPMessage_V1_6_EVM,
117
- type CCIPMessage_V2_0,
118
- type CleanAddressable,
119
- type MessageV1,
120
- type TokenTransferV1,
121
- decodeMessageV1,
122
- } from './messages.ts'
123
- export { decodeMessageV1 }
124
- export type { MessageV1, TokenTransferV1 }
125
- import { encodeEVMOffchainTokenData, fetchEVMOffchainTokenData } from './offchain.ts'
119
+ import type { CCIPMessage_V1_6_EVM, CCIPMessage_V2_0, CleanAddressable } from './messages.ts'
120
+ import { encodeEVMOffchainTokenData } from './offchain.ts'
126
121
  import { buildMessageForDest, decodeMessage, getMessagesInBatch } from '../requests.ts'
127
122
  import { type UnsignedEVMTx, resultToObject } from './types.ts'
123
+ import { decodeMessageV1 } from '../messages.ts'
128
124
  export type { UnsignedEVMTx }
129
125
 
126
+ /** Raw on-chain TokenBucket struct returned by TokenPool rate limiter queries. */
127
+ type RateLimiterBucket = { tokens: bigint; isEnabled: boolean; capacity: bigint; rate: bigint }
128
+
129
+ /** Converts an on-chain bucket to the public RateLimiterState, stripping `isEnabled`. */
130
+ function toRateLimiterState(b: RateLimiterBucket): RateLimiterState {
131
+ return b.isEnabled ? { tokens: b.tokens, capacity: b.capacity, rate: b.rate } : null
132
+ }
133
+
130
134
  /** typeguard for ethers Signer interface (used for `wallet`s) */
131
135
  function isSigner(wallet: unknown): wallet is Signer {
132
136
  return (
@@ -339,9 +343,9 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
339
343
  const chainTx = {
340
344
  ...tx,
341
345
  timestamp,
342
- logs: [] as Log_[],
346
+ logs: [] as ChainLog[],
343
347
  }
344
- const logs: Log_[] = tx.logs.map((l) => Object.assign(l, { tx: chainTx }))
348
+ const logs: ChainLog[] = tx.logs.map((l) => Object.assign(l, { tx: chainTx }))
345
349
  chainTx.logs = logs
346
350
  return chainTx
347
351
  }
@@ -626,6 +630,45 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
626
630
  }
627
631
  }
628
632
 
633
+ /**
634
+ * {@inheritDoc Chain.getLaneFeatures}
635
+ */
636
+ override async getLaneFeatures(opts: {
637
+ router: string
638
+ destChainSelector: bigint
639
+ token?: string
640
+ }): Promise<Partial<LaneFeatures>> {
641
+ const onRamp = await this.getOnRampForRouter(opts.router, opts.destChainSelector)
642
+ const [, version] = await this.typeAndVersion(onRamp)
643
+
644
+ const result: Partial<LaneFeatures> = {}
645
+
646
+ // default FTF value for V2_0+ lanes if no token/pool or pool doesn't specify
647
+ if (version >= CCIPVersion.V2_0) result[LaneFeature.MIN_BLOCK_CONFIRMATIONS] = 1
648
+
649
+ // MIN_BLOCK_CONFIRMATIONS — V2_0+ only
650
+ if (opts.token) {
651
+ const { tokenPool } = await this.getRegistryTokenConfig(
652
+ await this.getTokenAdminRegistryFor(onRamp),
653
+ opts.token,
654
+ )
655
+ if (tokenPool) {
656
+ const { minBlockConfirmations } = await this.getTokenPoolConfig(tokenPool)
657
+ if (minBlockConfirmations != null)
658
+ result[LaneFeature.MIN_BLOCK_CONFIRMATIONS] = minBlockConfirmations
659
+
660
+ const remote = await this.getTokenPoolRemote(tokenPool, opts.destChainSelector)
661
+ result[LaneFeature.RATE_LIMITS] = remote.outboundRateLimiterState
662
+ if (minBlockConfirmations && 'customBlockConfirmationsOutboundRateLimiterState' in remote) {
663
+ result[LaneFeature.CUSTOM_BLOCK_CONFIRMATIONS_RATE_LIMITS] =
664
+ remote.customBlockConfirmationsOutboundRateLimiterState
665
+ }
666
+ }
667
+ }
668
+
669
+ return result
670
+ }
671
+
629
672
  /**
630
673
  * {@inheritDoc Chain.getRouterForOffRamp}
631
674
  * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
@@ -888,11 +931,22 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
888
931
  ? type.includes('OnRamp')
889
932
  ? interfaces.EVM2EVMOnRamp_v1_5
890
933
  : interfaces.EVM2EVMOffRamp_v1_5
891
- : type.includes('OnRamp')
892
- ? interfaces.OnRamp_v1_6
893
- : interfaces.OffRamp_v1_6,
934
+ : version < CCIPVersion.V2_0
935
+ ? type.includes('OnRamp')
936
+ ? interfaces.OnRamp_v1_6
937
+ : interfaces.OffRamp_v1_6
938
+ : type.includes('OnRamp')
939
+ ? interfaces.OnRamp_v2_0
940
+ : interfaces.OffRamp_v2_0,
894
941
  this.provider,
895
- ) as unknown as TypedContract<typeof OnRamp_1_6_ABI | typeof OffRamp_1_6_ABI>
942
+ ) as unknown as TypedContract<
943
+ | typeof EVM2EVMOnRamp_1_5_ABI
944
+ | typeof EVM2EVMOffRamp_1_5_ABI
945
+ | typeof OnRamp_1_6_ABI
946
+ | typeof OffRamp_1_6_ABI
947
+ | typeof OnRamp_2_0_ABI
948
+ | typeof OffRamp_2_0_ABI
949
+ >
896
950
  const { tokenAdminRegistry } = await contract.getStaticConfig()
897
951
  return tokenAdminRegistry as string
898
952
  }
@@ -976,10 +1030,12 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
976
1030
  )
977
1031
 
978
1032
  // make sure to approve once per token, for the total amount (including fee, if needed)
979
- const amountsToApprove = (message.tokenAmounts ?? []).reduce(
980
- (acc, { token, amount }) => ({ ...acc, [token]: (acc[token] ?? 0n) + amount }),
981
- {} as { [token: string]: bigint },
982
- )
1033
+ const amountsToApprove = (message.tokenAmounts ?? [])
1034
+ .filter(({ token }) => token && token !== ZeroAddress)
1035
+ .reduce(
1036
+ (acc, { token, amount }) => ({ ...acc, [token]: (acc[token] ?? 0n) + amount }),
1037
+ {} as { [token: string]: bigint },
1038
+ )
983
1039
  if (feeToken !== ZeroAddress)
984
1040
  amountsToApprove[feeToken] = (amountsToApprove[feeToken] ?? 0n) + message.fee
985
1041
 
@@ -993,7 +1049,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
993
1049
  ) as unknown as TypedContract<typeof Token_ABI>
994
1050
  const allowance = await contract.allowance(sender, router)
995
1051
  if (allowance >= amount) return
996
- const amnt = opts.approveMax ? 2n ** 256n - 1n : amount
1052
+ const amnt = opts.approveMax ? BigInt(2) ** BigInt(256) - BigInt(1) : amount
997
1053
  return contract.approve.populateTransaction(router, amnt, { from: sender })
998
1054
  }),
999
1055
  )
@@ -1004,6 +1060,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1004
1060
  interfaces.Router,
1005
1061
  this.provider,
1006
1062
  ) as unknown as TypedContract<typeof Router_ABI>
1063
+
1064
+ // if `token` is ZeroAddress, send its `amount` as `value` to router/EtherSenderReceiver (plus possibly native fee)
1065
+ // if native fee, include it in value; otherwise, it's transferedFrom feeToken
1066
+ const value = (message.tokenAmounts ?? [])
1067
+ .filter(({ token }) => token === ZeroAddress)
1068
+ .reduce((acc, { amount }) => acc + amount, feeToken === ZeroAddress ? message.fee : 0n)
1069
+
1007
1070
  const sendTx = await contract.ccipSend.populateTransaction(
1008
1071
  destChainSelector,
1009
1072
  {
@@ -1013,11 +1076,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1013
1076
  extraArgs,
1014
1077
  feeToken,
1015
1078
  },
1016
- {
1017
- from: sender,
1018
- // if native fee, include it in value; otherwise, it's transferedFrom feeToken
1019
- ...(feeToken === ZeroAddress && { value: message.fee }),
1020
- },
1079
+ { from: sender, ...(value > 0n ? { value } : {}) },
1021
1080
  )
1022
1081
  const txRequests = [...approveTxs, sendTx] as SetRequired<typeof sendTx, 'from'>[]
1023
1082
  return {
@@ -1073,11 +1132,6 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1073
1132
  return (await this.getMessagesInTx(await this.getTransaction(tx)))[0]!
1074
1133
  }
1075
1134
 
1076
- /** {@inheritDoc Chain.getOffchainTokenData} */
1077
- getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
1078
- return fetchEVMOffchainTokenData(request, this)
1079
- }
1080
-
1081
1135
  /**
1082
1136
  * {@inheritDoc Chain.generateUnsignedExecute}
1083
1137
  * @returns array containing one unsigned `manuallyExecute` TransactionRequest object
@@ -1106,6 +1160,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1106
1160
  const txGasLimit = await contract.executeSingleMessage.estimateGas(
1107
1161
  {
1108
1162
  ...message,
1163
+ onRampAddress: zeroPadValue(getAddressBytes(message.onRampAddress), 32),
1164
+ sender: zeroPadValue(getAddressBytes(message.sender), 32),
1165
+ tokenTransfer: message.tokenTransfer.map((ta) => ({
1166
+ ...ta,
1167
+ sourcePoolAddress: zeroPadValue(getAddressBytes(ta.sourcePoolAddress), 32),
1168
+ sourceTokenAddress: zeroPadValue(getAddressBytes(ta.sourceTokenAddress), 32),
1169
+ })),
1109
1170
  executionGasLimit: BigInt(message.executionGasLimit),
1110
1171
  ccipReceiveGasLimit: BigInt(message.ccipReceiveGasLimit),
1111
1172
  finality: BigInt(message.finality),
@@ -1232,6 +1293,22 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1232
1293
  default:
1233
1294
  throw new CCIPVersionUnsupportedError(version)
1234
1295
  }
1296
+
1297
+ /* Executing a message for the first time has some hard try/catches on-chain
1298
+ * so we need to ensure some lower-bounds gasLimits */
1299
+ let gasLimit = await this.provider.estimateGas(manualExecTx)
1300
+ if (
1301
+ 'gasLimit' in input.message &&
1302
+ input.message.gasLimit &&
1303
+ gasLimit < input.message.gasLimit + 100000n
1304
+ )
1305
+ // if message requested gasLimit, ensure execution more than 100k above requested, otherwise it's clearly a try/catch fail
1306
+ gasLimit = BigInt(input.message.gasLimit) + 200000n
1307
+ else if ('gasLimit' in input.message && !input.message.gasLimit && gasLimit < 240000n)
1308
+ // if message didn't request gasLimit, ensure execution gasLimit is above 240k (empiric)
1309
+ gasLimit = 240000n
1310
+ manualExecTx.gasLimit = gasLimit
1311
+
1235
1312
  return { family: ChainFamily.EVM, transactions: [manualExecTx] }
1236
1313
  }
1237
1314
 
@@ -1258,7 +1335,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1258
1335
  const response = await submitTransaction(wallet, populatedTx, this.provider)
1259
1336
  this.logger.debug('manuallyExecute =>', response.hash)
1260
1337
 
1261
- const receipt = await response.wait(1, 60_000)
1338
+ let receipt = await response.wait(0)
1339
+ if (!receipt) receipt = await response.wait(1, 240_000)
1262
1340
  if (!receipt?.hash) throw new CCIPExecTxNotConfirmedError(response.hash)
1263
1341
  if (!receipt.status) throw new CCIPExecTxRevertedError(response.hash)
1264
1342
  const tx = await this.getTransaction(receipt)
@@ -1334,24 +1412,44 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1334
1412
  token: string
1335
1413
  router: string
1336
1414
  typeAndVersion: string
1415
+ minBlockConfirmations?: number
1337
1416
  }> {
1338
- const [_, , typeAndVersion] = await this.typeAndVersion(tokenPool)
1339
-
1340
- const contract = new Contract(
1341
- tokenPool,
1342
- interfaces.TokenPool_v1_6,
1343
- this.provider,
1344
- ) as unknown as TypedContract<typeof TokenPool_ABI>
1417
+ const [_, version, typeAndVersion] = await this.typeAndVersion(tokenPool)
1345
1418
 
1419
+ let contract, router, minBlockConfirmations
1420
+ if (version < CCIPVersion.V2_0) {
1421
+ contract = new Contract(
1422
+ tokenPool,
1423
+ interfaces.TokenPool_v1_6,
1424
+ this.provider,
1425
+ ) as unknown as TypedContract<typeof TokenPool_ABI>
1426
+ router = contract.getRouter()
1427
+ } else {
1428
+ contract = new Contract(
1429
+ tokenPool,
1430
+ interfaces.TokenPool_v2_0,
1431
+ this.provider,
1432
+ ) as unknown as TypedContract<typeof TokenPool_2_0_ABI>
1433
+ router = contract.getDynamicConfig().then(([router]) => router)
1434
+ minBlockConfirmations = contract.getMinBlockConfirmations().catch((err) => {
1435
+ if (isError(err, 'CALL_EXCEPTION')) return 0
1436
+ throw CCIPError.from(err)
1437
+ })
1438
+ }
1346
1439
  const token = contract.getToken()
1347
- const router = contract.getRouter()
1348
- return Promise.all([token, router]).then(([token, router]) => {
1349
- return {
1350
- token: token as string,
1351
- router: router as string,
1352
- typeAndVersion,
1353
- }
1354
- })
1440
+
1441
+ return Promise.all([token, router, minBlockConfirmations]).then(
1442
+ ([token, router, minBlockConfirmations]) => {
1443
+ return {
1444
+ token: token as CleanAddressable<typeof token>,
1445
+ router: router as CleanAddressable<typeof router>,
1446
+ typeAndVersion,
1447
+ ...(minBlockConfirmations != null && {
1448
+ minBlockConfirmations: Number(minBlockConfirmations),
1449
+ }),
1450
+ }
1451
+ },
1452
+ )
1355
1453
  }
1356
1454
 
1357
1455
  /** {@inheritDoc Chain.getTokenPoolRemotes} */
@@ -1365,53 +1463,93 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1365
1463
  if (remoteChainSelector) supportedChains = Promise.resolve([networkInfo(remoteChainSelector)])
1366
1464
 
1367
1465
  let remotePools: Promise<string[][]>
1368
- let contract
1466
+ let remoteInfo
1369
1467
  if (version < '1.5.1') {
1370
- const contract_ = new Contract(
1468
+ const contract = new Contract(
1371
1469
  tokenPool,
1372
1470
  interfaces.TokenPool_v1_5,
1373
1471
  this.provider,
1374
1472
  ) as unknown as TypedContract<typeof TokenPool_1_5_ABI>
1375
- contract = contract_
1376
1473
  supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1377
1474
  remotePools = supportedChains.then((chains) =>
1378
1475
  Promise.all(
1379
1476
  chains.map((chain) =>
1380
- contract_
1477
+ contract
1381
1478
  .getRemotePool(chain.chainSelector)
1382
1479
  .then((remotePool) => [decodeAddress(remotePool, chain.family)]),
1383
1480
  ),
1384
1481
  ),
1385
1482
  )
1386
- } else {
1387
- const contract_ = new Contract(
1483
+ remoteInfo = supportedChains.then((chains) =>
1484
+ Promise.all(
1485
+ chains.map((chain) =>
1486
+ Promise.all([
1487
+ contract.getRemoteToken(chain.chainSelector),
1488
+ resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1489
+ resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1490
+ ] as const),
1491
+ ),
1492
+ ),
1493
+ )
1494
+ } else if (version < CCIPVersion.V2_0) {
1495
+ const contract = new Contract(
1388
1496
  tokenPool,
1389
1497
  interfaces.TokenPool_v1_6,
1390
1498
  this.provider,
1391
1499
  ) as unknown as TypedContract<typeof TokenPool_ABI>
1392
- contract = contract_
1393
1500
  supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1394
1501
  remotePools = supportedChains.then((chains) =>
1395
1502
  Promise.all(
1396
1503
  chains.map((chain) =>
1397
- contract_
1504
+ contract
1398
1505
  .getRemotePools(chain.chainSelector)
1399
1506
  .then((pools) => pools.map((remotePool) => decodeAddress(remotePool, chain.family))),
1400
1507
  ),
1401
1508
  ),
1402
1509
  )
1403
- }
1404
- const remoteInfo = supportedChains.then((chains) =>
1405
- Promise.all(
1406
- chains.map((chain) =>
1407
- Promise.all([
1408
- contract.getRemoteToken(chain.chainSelector),
1409
- resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1410
- resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1411
- ] as const),
1510
+ remoteInfo = supportedChains.then((chains) =>
1511
+ Promise.all(
1512
+ chains.map((chain) =>
1513
+ Promise.all([
1514
+ contract.getRemoteToken(chain.chainSelector),
1515
+ resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1516
+ resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1517
+ ] as const),
1518
+ ),
1412
1519
  ),
1413
- ),
1414
- )
1520
+ )
1521
+ } else {
1522
+ const contract = new Contract(
1523
+ tokenPool,
1524
+ interfaces.TokenPool_v2_0,
1525
+ this.provider,
1526
+ ) as unknown as TypedContract<typeof TokenPool_2_0_ABI>
1527
+ supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1528
+ remotePools = supportedChains.then((chains) =>
1529
+ Promise.all(
1530
+ chains.map((chain) =>
1531
+ contract
1532
+ .getRemotePools(chain.chainSelector)
1533
+ .then((pools) => pools.map((remotePool) => decodeAddress(remotePool, chain.family))),
1534
+ ),
1535
+ ),
1536
+ )
1537
+ remoteInfo = supportedChains.then((chains) =>
1538
+ Promise.all(
1539
+ chains.map((chain) =>
1540
+ Promise.all([
1541
+ contract.getRemoteToken(chain.chainSelector),
1542
+ contract.getCurrentRateLimiterState(chain.chainSelector, false),
1543
+ contract.getCurrentRateLimiterState(chain.chainSelector, true),
1544
+ ] as const).then(
1545
+ ([remoteToken, [outbound, inbound], [customOutbound, customInbound]]) => {
1546
+ return [remoteToken, outbound, inbound, customOutbound, customInbound] as const
1547
+ },
1548
+ ),
1549
+ ),
1550
+ ),
1551
+ )
1552
+ }
1415
1553
  return Promise.all([supportedChains, remotePools, remoteInfo]).then(
1416
1554
  ([supportedChains, remotePools, remoteInfo]) =>
1417
1555
  Object.fromEntries(
@@ -1424,8 +1562,16 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1424
1562
  {
1425
1563
  remoteToken: decodeAddress(remoteTokenRaw, chain.family),
1426
1564
  remotePools: remotePools[i]!.map((pool) => decodeAddress(pool, chain.family)),
1427
- inboundRateLimiterState: remoteInfo[i]![1].isEnabled ? remoteInfo[i]![1] : null,
1428
- outboundRateLimiterState: remoteInfo[i]![2].isEnabled ? remoteInfo[i]![2] : null,
1565
+ outboundRateLimiterState: toRateLimiterState(remoteInfo[i]![1]),
1566
+ inboundRateLimiterState: toRateLimiterState(remoteInfo[i]![2]),
1567
+ ...(remoteInfo[i]!.length === 5 && {
1568
+ customBlockConfirmationsOutboundRateLimiterState: toRateLimiterState(
1569
+ remoteInfo[i]![3],
1570
+ ),
1571
+ customBlockConfirmationsInboundRateLimiterState: toRateLimiterState(
1572
+ remoteInfo[i]![4],
1573
+ ),
1574
+ }),
1429
1575
  },
1430
1576
  ] as const
1431
1577
  }),
@@ -1467,7 +1613,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1467
1613
  tokens = Array.from(tokens_)
1468
1614
  break
1469
1615
  }
1470
- case CCIPVersion.V1_6: {
1616
+ case CCIPVersion.V1_6:
1617
+ case CCIPVersion.V2_0: {
1471
1618
  const feeQuoter = await this.getFeeQuoterFor(onRamp)
1472
1619
  const contract = new Contract(
1473
1620
  feeQuoter,
@@ -1495,15 +1642,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1495
1642
  ): Promise<CCIPVerifications> {
1496
1643
  const { offRamp, request } = opts
1497
1644
  if (request.lane.version >= CCIPVersion.V2_0) {
1498
- const message = request.message as CCIPMessage_V2_0
1499
- if (!message.encodedMessage)
1500
- throw new CCIPNotImplementedError(`CCIPAPIClient getMessageById v2 encodedMessage`)
1645
+ const { encodedMessage } = request.message as CCIPMessage_V2_0
1501
1646
  const contract = new Contract(
1502
1647
  offRamp,
1503
1648
  interfaces.OffRamp_v2_0,
1504
1649
  this.provider,
1505
1650
  ) as unknown as TypedContract<typeof OffRamp_2_0_ABI>
1506
- const ccvs = await contract.getCCVsForMessage(message.encodedMessage)
1651
+ const ccvs = await contract.getCCVsForMessage(encodedMessage)
1507
1652
  const [requiredCCVs, optionalCCVs, optionalThreshold] = ccvs.map(
1508
1653
  resultToObject,
1509
1654
  ) as unknown as CleanAddressable<typeof ccvs>
@@ -1517,20 +1662,24 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1517
1662
  const apiRes = await this.apiClient.getMessageById(request.message.messageId)
1518
1663
  if ('verifiers' in apiRes.message) {
1519
1664
  const verifiers = apiRes.message.verifiers as {
1520
- items: {
1665
+ items?: {
1521
1666
  destAddress: string
1522
1667
  sourceAddress: string
1523
- verification: { data: string; timestamp: string }
1668
+ verification?: { data: string; timestamp: string }
1524
1669
  }[]
1525
1670
  }
1526
1671
  return {
1527
1672
  verificationPolicy,
1528
- verifications: verifiers.items.map((item) => ({
1529
- destAddress: item.destAddress,
1530
- sourceAddress: item.sourceAddress,
1531
- ccvData: item.verification.data,
1532
- timestamp: new Date(item.verification.timestamp).getTime() / 1e3,
1533
- })),
1673
+ verifications: (verifiers.items ?? [])
1674
+ .filter((item) => item.verification?.data)
1675
+ .map((item) => ({
1676
+ destAddress: item.destAddress,
1677
+ sourceAddress: item.sourceAddress,
1678
+ ccvData: item.verification!.data,
1679
+ ...(!!item.verification?.timestamp && {
1680
+ timestamp: new Date(item.verification.timestamp).getTime() / 1e3,
1681
+ }),
1682
+ })),
1534
1683
  }
1535
1684
  }
1536
1685
  }
package/src/evm/logs.ts CHANGED
@@ -183,7 +183,7 @@ async function getFallbackArchiveLogs(
183
183
  * - If undefined (default): paginate main provider only by filter.page
184
184
  * - If false: first try whole range with main provider, then fallback to archive provider
185
185
  * - If true: don't paginate (throw if can't fetch wide range from either provider)
186
- * @param ctx - Context object containing provider, logger and destry$ notify promise
186
+ * @param ctx - Context object containing provider, logger and destroy$ notify promise
187
187
  * @returns Async iterator of logs.
188
188
  */
189
189
  export async function* getEvmLogs(