@chainlink/ccip-sdk 1.0.0 → 1.1.1

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 (113) hide show
  1. package/dist/api/index.d.ts +4 -4
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +110 -11
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/types.d.ts +34 -0
  6. package/dist/api/types.d.ts.map +1 -1
  7. package/dist/aptos/index.d.ts.map +1 -1
  8. package/dist/aptos/index.js +5 -5
  9. package/dist/aptos/index.js.map +1 -1
  10. package/dist/chain.d.ts +109 -5
  11. package/dist/chain.d.ts.map +1 -1
  12. package/dist/chain.js +96 -8
  13. package/dist/chain.js.map +1 -1
  14. package/dist/errors/codes.d.ts +1 -1
  15. package/dist/errors/codes.d.ts.map +1 -1
  16. package/dist/errors/codes.js +2 -1
  17. package/dist/errors/codes.js.map +1 -1
  18. package/dist/errors/index.d.ts +2 -2
  19. package/dist/errors/index.d.ts.map +1 -1
  20. package/dist/errors/index.js +2 -2
  21. package/dist/errors/index.js.map +1 -1
  22. package/dist/errors/recovery.js +1 -1
  23. package/dist/errors/recovery.js.map +1 -1
  24. package/dist/errors/specialized.d.ts +22 -19
  25. package/dist/errors/specialized.d.ts.map +1 -1
  26. package/dist/errors/specialized.js +30 -25
  27. package/dist/errors/specialized.js.map +1 -1
  28. package/dist/evm/abi/OffRamp_2_0.d.ts +24 -12
  29. package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -1
  30. package/dist/evm/abi/OffRamp_2_0.js +16 -8
  31. package/dist/evm/abi/OffRamp_2_0.js.map +1 -1
  32. package/dist/evm/abi/TokenPool_2_0.d.ts +1552 -0
  33. package/dist/evm/abi/TokenPool_2_0.d.ts.map +1 -0
  34. package/dist/evm/abi/TokenPool_2_0.js +1637 -0
  35. package/dist/evm/abi/TokenPool_2_0.js.map +1 -0
  36. package/dist/evm/const.d.ts +1 -0
  37. package/dist/evm/const.d.ts.map +1 -1
  38. package/dist/evm/const.js +2 -0
  39. package/dist/evm/const.js.map +1 -1
  40. package/dist/evm/index.d.ts +10 -4
  41. package/dist/evm/index.d.ts.map +1 -1
  42. package/dist/evm/index.js +139 -51
  43. package/dist/evm/index.js.map +1 -1
  44. package/dist/evm/messages.d.ts +2 -33
  45. package/dist/evm/messages.d.ts.map +1 -1
  46. package/dist/evm/messages.js +0 -210
  47. package/dist/evm/messages.js.map +1 -1
  48. package/dist/gas.d.ts +4 -0
  49. package/dist/gas.d.ts.map +1 -1
  50. package/dist/gas.js +27 -21
  51. package/dist/gas.js.map +1 -1
  52. package/dist/index.d.ts +3 -2
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +1 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/messages.d.ts +34 -0
  57. package/dist/messages.d.ts.map +1 -0
  58. package/dist/messages.js +211 -0
  59. package/dist/messages.js.map +1 -0
  60. package/dist/solana/cleanup.js +2 -2
  61. package/dist/solana/cleanup.js.map +1 -1
  62. package/dist/solana/exec.js +1 -1
  63. package/dist/solana/exec.js.map +1 -1
  64. package/dist/solana/index.d.ts +19 -19
  65. package/dist/solana/index.d.ts.map +1 -1
  66. package/dist/solana/index.js +17 -2
  67. package/dist/solana/index.js.map +1 -1
  68. package/dist/sui/exec.d.ts +30 -0
  69. package/dist/sui/exec.d.ts.map +1 -0
  70. package/dist/sui/exec.js +92 -0
  71. package/dist/sui/exec.js.map +1 -0
  72. package/dist/sui/index.d.ts +7 -2
  73. package/dist/sui/index.d.ts.map +1 -1
  74. package/dist/sui/index.js +36 -65
  75. package/dist/sui/index.js.map +1 -1
  76. package/dist/sui/manuallyExec/index.d.ts.map +1 -1
  77. package/dist/sui/manuallyExec/index.js +10 -13
  78. package/dist/sui/manuallyExec/index.js.map +1 -1
  79. package/dist/sui/objects.d.ts.map +1 -1
  80. package/dist/sui/objects.js +4 -2
  81. package/dist/sui/objects.js.map +1 -1
  82. package/dist/sui/types.d.ts +9 -1
  83. package/dist/sui/types.d.ts.map +1 -1
  84. package/dist/sui/types.js.map +1 -1
  85. package/dist/ton/index.d.ts.map +1 -1
  86. package/dist/ton/index.js +3 -1
  87. package/dist/ton/index.js.map +1 -1
  88. package/package.json +5 -5
  89. package/src/api/index.ts +126 -11
  90. package/src/api/types.ts +43 -0
  91. package/src/aptos/index.ts +7 -9
  92. package/src/chain.ts +152 -12
  93. package/src/errors/codes.ts +2 -1
  94. package/src/errors/index.ts +1 -1
  95. package/src/errors/recovery.ts +1 -1
  96. package/src/errors/specialized.ts +35 -30
  97. package/src/evm/abi/OffRamp_2_0.ts +16 -8
  98. package/src/evm/abi/TokenPool_2_0.ts +1636 -0
  99. package/src/evm/const.ts +2 -0
  100. package/src/evm/index.ts +231 -84
  101. package/src/evm/messages.ts +3 -285
  102. package/src/gas.ts +27 -19
  103. package/src/index.ts +3 -1
  104. package/src/messages.ts +278 -0
  105. package/src/solana/cleanup.ts +2 -2
  106. package/src/solana/exec.ts +1 -1
  107. package/src/solana/index.ts +20 -2
  108. package/src/sui/exec.ts +131 -0
  109. package/src/sui/index.ts +50 -98
  110. package/src/sui/manuallyExec/index.ts +11 -17
  111. package/src/sui/objects.ts +4 -2
  112. package/src/sui/types.ts +10 -1
  113. package/src/ton/index.ts +5 -1
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,22 +28,24 @@ 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,
36
- CCIPApiClientNotAvailableError,
37
40
  CCIPBlockNotFoundError,
38
41
  CCIPContractNotRouterError,
39
42
  CCIPContractTypeInvalidError,
40
43
  CCIPDataFormatUnsupportedError,
44
+ CCIPError,
41
45
  CCIPExecTxNotConfirmedError,
42
46
  CCIPExecTxRevertedError,
43
47
  CCIPHasherVersionUnsupportedError,
44
48
  CCIPLogDataInvalidError,
45
- CCIPNotImplementedError,
46
49
  CCIPSourceChainUnsupportedError,
47
50
  CCIPTokenNotConfiguredError,
48
51
  CCIPTokenPoolChainConfigNotFoundError,
@@ -63,7 +66,6 @@ import {
63
66
  type ChainLog,
64
67
  type ChainTransaction,
65
68
  type CommitReport,
66
- type ExecutionInput,
67
69
  type ExecutionReceipt,
68
70
  type ExecutionState,
69
71
  type Lane,
@@ -95,6 +97,7 @@ import type OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
95
97
  import type OnRamp_2_0_ABI from './abi/OnRamp_2_0.ts'
96
98
  import type Router_ABI from './abi/Router.ts'
97
99
  import type TokenAdminRegistry_1_5_ABI from './abi/TokenAdminRegistry_1_5.ts'
100
+ import type TokenPool_2_0_ABI from './abi/TokenPool_2_0.ts'
98
101
  import {
99
102
  CCV_INDEXER_URL,
100
103
  VersionedContractABI,
@@ -111,21 +114,21 @@ import {
111
114
  import { estimateExecGas } from './gas.ts'
112
115
  import { getV12LeafHasher, getV16LeafHasher } from './hasher.ts'
113
116
  import { getEvmLogs } from './logs.ts'
114
- import {
115
- type CCIPMessage_V1_6_EVM,
116
- type CCIPMessage_V2_0,
117
- type CleanAddressable,
118
- type MessageV1,
119
- type TokenTransferV1,
120
- decodeMessageV1,
121
- } from './messages.ts'
122
- export { decodeMessageV1 }
123
- export type { MessageV1, TokenTransferV1 }
117
+ import type { CCIPMessage_V1_6_EVM, CCIPMessage_V2_0, CleanAddressable } from './messages.ts'
124
118
  import { encodeEVMOffchainTokenData } from './offchain.ts'
125
119
  import { buildMessageForDest, decodeMessage, getMessagesInBatch } from '../requests.ts'
126
120
  import { type UnsignedEVMTx, resultToObject } from './types.ts'
121
+ import { decodeMessageV1 } from '../messages.ts'
127
122
  export type { UnsignedEVMTx }
128
123
 
124
+ /** Raw on-chain TokenBucket struct returned by TokenPool rate limiter queries. */
125
+ type RateLimiterBucket = { tokens: bigint; isEnabled: boolean; capacity: bigint; rate: bigint }
126
+
127
+ /** Converts an on-chain bucket to the public RateLimiterState, stripping `isEnabled`. */
128
+ function toRateLimiterState(b: RateLimiterBucket): RateLimiterState {
129
+ return b.isEnabled ? { tokens: b.tokens, capacity: b.capacity, rate: b.rate } : null
130
+ }
131
+
129
132
  /** typeguard for ethers Signer interface (used for `wallet`s) */
130
133
  function isSigner(wallet: unknown): wallet is Signer {
131
134
  return (
@@ -625,6 +628,45 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
625
628
  }
626
629
  }
627
630
 
631
+ /**
632
+ * {@inheritDoc Chain.getLaneFeatures}
633
+ */
634
+ override async getLaneFeatures(opts: {
635
+ router: string
636
+ destChainSelector: bigint
637
+ token?: string
638
+ }): Promise<Partial<LaneFeatures>> {
639
+ const onRamp = await this.getOnRampForRouter(opts.router, opts.destChainSelector)
640
+ const [, version] = await this.typeAndVersion(onRamp)
641
+
642
+ const result: Partial<LaneFeatures> = {}
643
+
644
+ // default FTF value for V2_0+ lanes if no token/pool or pool doesn't specify
645
+ if (version >= CCIPVersion.V2_0) result[LaneFeature.MIN_BLOCK_CONFIRMATIONS] = 1
646
+
647
+ // MIN_BLOCK_CONFIRMATIONS — V2_0+ only
648
+ if (opts.token) {
649
+ const { tokenPool } = await this.getRegistryTokenConfig(
650
+ await this.getTokenAdminRegistryFor(onRamp),
651
+ opts.token,
652
+ )
653
+ if (tokenPool) {
654
+ const { minBlockConfirmations } = await this.getTokenPoolConfig(tokenPool)
655
+ if (minBlockConfirmations != null)
656
+ result[LaneFeature.MIN_BLOCK_CONFIRMATIONS] = minBlockConfirmations
657
+
658
+ const remote = await this.getTokenPoolRemote(tokenPool, opts.destChainSelector)
659
+ result[LaneFeature.RATE_LIMITS] = remote.outboundRateLimiterState
660
+ if (minBlockConfirmations && 'customBlockConfirmationsOutboundRateLimiterState' in remote) {
661
+ result[LaneFeature.CUSTOM_BLOCK_CONFIRMATIONS_RATE_LIMITS] =
662
+ remote.customBlockConfirmationsOutboundRateLimiterState
663
+ }
664
+ }
665
+ }
666
+
667
+ return result
668
+ }
669
+
628
670
  /**
629
671
  * {@inheritDoc Chain.getRouterForOffRamp}
630
672
  * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
@@ -887,11 +929,22 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
887
929
  ? type.includes('OnRamp')
888
930
  ? interfaces.EVM2EVMOnRamp_v1_5
889
931
  : interfaces.EVM2EVMOffRamp_v1_5
890
- : type.includes('OnRamp')
891
- ? interfaces.OnRamp_v1_6
892
- : interfaces.OffRamp_v1_6,
932
+ : version < CCIPVersion.V2_0
933
+ ? type.includes('OnRamp')
934
+ ? interfaces.OnRamp_v1_6
935
+ : interfaces.OffRamp_v1_6
936
+ : type.includes('OnRamp')
937
+ ? interfaces.OnRamp_v2_0
938
+ : interfaces.OffRamp_v2_0,
893
939
  this.provider,
894
- ) as unknown as TypedContract<typeof OnRamp_1_6_ABI | typeof OffRamp_1_6_ABI>
940
+ ) as unknown as TypedContract<
941
+ | typeof EVM2EVMOnRamp_1_5_ABI
942
+ | typeof EVM2EVMOffRamp_1_5_ABI
943
+ | typeof OnRamp_1_6_ABI
944
+ | typeof OffRamp_1_6_ABI
945
+ | typeof OnRamp_2_0_ABI
946
+ | typeof OffRamp_2_0_ABI
947
+ >
895
948
  const { tokenAdminRegistry } = await contract.getStaticConfig()
896
949
  return tokenAdminRegistry as string
897
950
  }
@@ -975,10 +1028,12 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
975
1028
  )
976
1029
 
977
1030
  // make sure to approve once per token, for the total amount (including fee, if needed)
978
- const amountsToApprove = (message.tokenAmounts ?? []).reduce(
979
- (acc, { token, amount }) => ({ ...acc, [token]: (acc[token] ?? 0n) + amount }),
980
- {} as { [token: string]: bigint },
981
- )
1031
+ const amountsToApprove = (message.tokenAmounts ?? [])
1032
+ .filter(({ token }) => token && token !== ZeroAddress)
1033
+ .reduce(
1034
+ (acc, { token, amount }) => ({ ...acc, [token]: (acc[token] ?? 0n) + amount }),
1035
+ {} as { [token: string]: bigint },
1036
+ )
982
1037
  if (feeToken !== ZeroAddress)
983
1038
  amountsToApprove[feeToken] = (amountsToApprove[feeToken] ?? 0n) + message.fee
984
1039
 
@@ -992,7 +1047,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
992
1047
  ) as unknown as TypedContract<typeof Token_ABI>
993
1048
  const allowance = await contract.allowance(sender, router)
994
1049
  if (allowance >= amount) return
995
- const amnt = opts.approveMax ? 2n ** 256n - 1n : amount
1050
+ const amnt = opts.approveMax ? BigInt(2) ** BigInt(256) - BigInt(1) : amount
996
1051
  return contract.approve.populateTransaction(router, amnt, { from: sender })
997
1052
  }),
998
1053
  )
@@ -1003,6 +1058,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1003
1058
  interfaces.Router,
1004
1059
  this.provider,
1005
1060
  ) as unknown as TypedContract<typeof Router_ABI>
1061
+
1062
+ // if `token` is ZeroAddress, send its `amount` as `value` to router/EtherSenderReceiver (plus possibly native fee)
1063
+ // if native fee, include it in value; otherwise, it's transferedFrom feeToken
1064
+ const value = (message.tokenAmounts ?? [])
1065
+ .filter(({ token }) => token === ZeroAddress)
1066
+ .reduce((acc, { amount }) => acc + amount, feeToken === ZeroAddress ? message.fee : 0n)
1067
+
1006
1068
  const sendTx = await contract.ccipSend.populateTransaction(
1007
1069
  destChainSelector,
1008
1070
  {
@@ -1012,11 +1074,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1012
1074
  extraArgs,
1013
1075
  feeToken,
1014
1076
  },
1015
- {
1016
- from: sender,
1017
- // if native fee, include it in value; otherwise, it's transferedFrom feeToken
1018
- ...(feeToken === ZeroAddress && { value: message.fee }),
1019
- },
1077
+ { from: sender, ...(value > 0n ? { value } : {}) },
1020
1078
  )
1021
1079
  const txRequests = [...approveTxs, sendTx] as SetRequired<typeof sendTx, 'from'>[]
1022
1080
  return {
@@ -1080,13 +1138,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1080
1138
  async generateUnsignedExecute(
1081
1139
  opts: Parameters<Chain['generateUnsignedExecute']>[0],
1082
1140
  ): Promise<UnsignedEVMTx> {
1083
- let input: ExecutionInput, offRamp: string
1084
- if (!('input' in opts)) {
1085
- if (!this.apiClient) throw new CCIPApiClientNotAvailableError()
1086
- ;({ offRamp, ...input } = await this.apiClient.getExecutionInput(opts.messageId))
1087
- } else {
1088
- ;({ offRamp, input } = opts)
1089
- }
1141
+ const { offRamp, input } = await this.resolveExecuteOpts(opts)
1090
1142
  if ('verifications' in input) {
1091
1143
  const contract = new Contract(
1092
1144
  offRamp,
@@ -1100,6 +1152,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1100
1152
  const txGasLimit = await contract.executeSingleMessage.estimateGas(
1101
1153
  {
1102
1154
  ...message,
1155
+ onRampAddress: zeroPadValue(getAddressBytes(message.onRampAddress), 32),
1156
+ sender: zeroPadValue(getAddressBytes(message.sender), 32),
1157
+ tokenTransfer: message.tokenTransfer.map((ta) => ({
1158
+ ...ta,
1159
+ sourcePoolAddress: zeroPadValue(getAddressBytes(ta.sourcePoolAddress), 32),
1160
+ sourceTokenAddress: zeroPadValue(getAddressBytes(ta.sourceTokenAddress), 32),
1161
+ })),
1103
1162
  executionGasLimit: BigInt(message.executionGasLimit),
1104
1163
  ccipReceiveGasLimit: BigInt(message.ccipReceiveGasLimit),
1105
1164
  finality: BigInt(message.finality),
@@ -1226,6 +1285,22 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1226
1285
  default:
1227
1286
  throw new CCIPVersionUnsupportedError(version)
1228
1287
  }
1288
+
1289
+ /* Executing a message for the first time has some hard try/catches on-chain
1290
+ * so we need to ensure some lower-bounds gasLimits */
1291
+ let gasLimit = await this.provider.estimateGas(manualExecTx)
1292
+ if (
1293
+ 'gasLimit' in input.message &&
1294
+ input.message.gasLimit &&
1295
+ gasLimit < input.message.gasLimit + 100000n
1296
+ )
1297
+ // if message requested gasLimit, ensure execution more than 100k above requested, otherwise it's clearly a try/catch fail
1298
+ gasLimit = BigInt(input.message.gasLimit) + 200000n
1299
+ else if ('gasLimit' in input.message && !input.message.gasLimit && gasLimit < 240000n)
1300
+ // if message didn't request gasLimit, ensure execution gasLimit is above 240k (empiric)
1301
+ gasLimit = 240000n
1302
+ manualExecTx.gasLimit = gasLimit
1303
+
1229
1304
  return { family: ChainFamily.EVM, transactions: [manualExecTx] }
1230
1305
  }
1231
1306
 
@@ -1252,7 +1327,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1252
1327
  const response = await submitTransaction(wallet, populatedTx, this.provider)
1253
1328
  this.logger.debug('manuallyExecute =>', response.hash)
1254
1329
 
1255
- const receipt = await response.wait(1, 60_000)
1330
+ let receipt = await response.wait(0)
1331
+ if (!receipt) receipt = await response.wait(1, 240_000)
1256
1332
  if (!receipt?.hash) throw new CCIPExecTxNotConfirmedError(response.hash)
1257
1333
  if (!receipt.status) throw new CCIPExecTxRevertedError(response.hash)
1258
1334
  const tx = await this.getTransaction(receipt)
@@ -1328,24 +1404,44 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1328
1404
  token: string
1329
1405
  router: string
1330
1406
  typeAndVersion: string
1407
+ minBlockConfirmations?: number
1331
1408
  }> {
1332
- const [_, , typeAndVersion] = await this.typeAndVersion(tokenPool)
1333
-
1334
- const contract = new Contract(
1335
- tokenPool,
1336
- interfaces.TokenPool_v1_6,
1337
- this.provider,
1338
- ) as unknown as TypedContract<typeof TokenPool_ABI>
1409
+ const [_, version, typeAndVersion] = await this.typeAndVersion(tokenPool)
1339
1410
 
1411
+ let contract, router, minBlockConfirmations
1412
+ if (version < CCIPVersion.V2_0) {
1413
+ contract = new Contract(
1414
+ tokenPool,
1415
+ interfaces.TokenPool_v1_6,
1416
+ this.provider,
1417
+ ) as unknown as TypedContract<typeof TokenPool_ABI>
1418
+ router = contract.getRouter()
1419
+ } else {
1420
+ contract = new Contract(
1421
+ tokenPool,
1422
+ interfaces.TokenPool_v2_0,
1423
+ this.provider,
1424
+ ) as unknown as TypedContract<typeof TokenPool_2_0_ABI>
1425
+ router = contract.getDynamicConfig().then(([router]) => router)
1426
+ minBlockConfirmations = contract.getMinBlockConfirmations().catch((err) => {
1427
+ if (isError(err, 'CALL_EXCEPTION')) return 0
1428
+ throw CCIPError.from(err)
1429
+ })
1430
+ }
1340
1431
  const token = contract.getToken()
1341
- const router = contract.getRouter()
1342
- return Promise.all([token, router]).then(([token, router]) => {
1343
- return {
1344
- token: token as string,
1345
- router: router as string,
1346
- typeAndVersion,
1347
- }
1348
- })
1432
+
1433
+ return Promise.all([token, router, minBlockConfirmations]).then(
1434
+ ([token, router, minBlockConfirmations]) => {
1435
+ return {
1436
+ token: token as CleanAddressable<typeof token>,
1437
+ router: router as CleanAddressable<typeof router>,
1438
+ typeAndVersion,
1439
+ ...(minBlockConfirmations != null && {
1440
+ minBlockConfirmations: Number(minBlockConfirmations),
1441
+ }),
1442
+ }
1443
+ },
1444
+ )
1349
1445
  }
1350
1446
 
1351
1447
  /** {@inheritDoc Chain.getTokenPoolRemotes} */
@@ -1359,53 +1455,93 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1359
1455
  if (remoteChainSelector) supportedChains = Promise.resolve([networkInfo(remoteChainSelector)])
1360
1456
 
1361
1457
  let remotePools: Promise<string[][]>
1362
- let contract
1458
+ let remoteInfo
1363
1459
  if (version < '1.5.1') {
1364
- const contract_ = new Contract(
1460
+ const contract = new Contract(
1365
1461
  tokenPool,
1366
1462
  interfaces.TokenPool_v1_5,
1367
1463
  this.provider,
1368
1464
  ) as unknown as TypedContract<typeof TokenPool_1_5_ABI>
1369
- contract = contract_
1370
1465
  supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1371
1466
  remotePools = supportedChains.then((chains) =>
1372
1467
  Promise.all(
1373
1468
  chains.map((chain) =>
1374
- contract_
1469
+ contract
1375
1470
  .getRemotePool(chain.chainSelector)
1376
1471
  .then((remotePool) => [decodeAddress(remotePool, chain.family)]),
1377
1472
  ),
1378
1473
  ),
1379
1474
  )
1380
- } else {
1381
- const contract_ = new Contract(
1475
+ remoteInfo = supportedChains.then((chains) =>
1476
+ Promise.all(
1477
+ chains.map((chain) =>
1478
+ Promise.all([
1479
+ contract.getRemoteToken(chain.chainSelector),
1480
+ resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1481
+ resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1482
+ ] as const),
1483
+ ),
1484
+ ),
1485
+ )
1486
+ } else if (version < CCIPVersion.V2_0) {
1487
+ const contract = new Contract(
1382
1488
  tokenPool,
1383
1489
  interfaces.TokenPool_v1_6,
1384
1490
  this.provider,
1385
1491
  ) as unknown as TypedContract<typeof TokenPool_ABI>
1386
- contract = contract_
1387
1492
  supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1388
1493
  remotePools = supportedChains.then((chains) =>
1389
1494
  Promise.all(
1390
1495
  chains.map((chain) =>
1391
- contract_
1496
+ contract
1392
1497
  .getRemotePools(chain.chainSelector)
1393
1498
  .then((pools) => pools.map((remotePool) => decodeAddress(remotePool, chain.family))),
1394
1499
  ),
1395
1500
  ),
1396
1501
  )
1397
- }
1398
- const remoteInfo = supportedChains.then((chains) =>
1399
- Promise.all(
1400
- chains.map((chain) =>
1401
- Promise.all([
1402
- contract.getRemoteToken(chain.chainSelector),
1403
- resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1404
- resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1405
- ] as const),
1502
+ remoteInfo = supportedChains.then((chains) =>
1503
+ Promise.all(
1504
+ chains.map((chain) =>
1505
+ Promise.all([
1506
+ contract.getRemoteToken(chain.chainSelector),
1507
+ resultToObject(contract.getCurrentOutboundRateLimiterState(chain.chainSelector)),
1508
+ resultToObject(contract.getCurrentInboundRateLimiterState(chain.chainSelector)),
1509
+ ] as const),
1510
+ ),
1406
1511
  ),
1407
- ),
1408
- )
1512
+ )
1513
+ } else {
1514
+ const contract = new Contract(
1515
+ tokenPool,
1516
+ interfaces.TokenPool_v2_0,
1517
+ this.provider,
1518
+ ) as unknown as TypedContract<typeof TokenPool_2_0_ABI>
1519
+ supportedChains ??= contract.getSupportedChains().then((chains) => chains.map(networkInfo))
1520
+ remotePools = supportedChains.then((chains) =>
1521
+ Promise.all(
1522
+ chains.map((chain) =>
1523
+ contract
1524
+ .getRemotePools(chain.chainSelector)
1525
+ .then((pools) => pools.map((remotePool) => decodeAddress(remotePool, chain.family))),
1526
+ ),
1527
+ ),
1528
+ )
1529
+ remoteInfo = supportedChains.then((chains) =>
1530
+ Promise.all(
1531
+ chains.map((chain) =>
1532
+ Promise.all([
1533
+ contract.getRemoteToken(chain.chainSelector),
1534
+ contract.getCurrentRateLimiterState(chain.chainSelector, false),
1535
+ contract.getCurrentRateLimiterState(chain.chainSelector, true),
1536
+ ] as const).then(
1537
+ ([remoteToken, [outbound, inbound], [customOutbound, customInbound]]) => {
1538
+ return [remoteToken, outbound, inbound, customOutbound, customInbound] as const
1539
+ },
1540
+ ),
1541
+ ),
1542
+ ),
1543
+ )
1544
+ }
1409
1545
  return Promise.all([supportedChains, remotePools, remoteInfo]).then(
1410
1546
  ([supportedChains, remotePools, remoteInfo]) =>
1411
1547
  Object.fromEntries(
@@ -1418,8 +1554,16 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1418
1554
  {
1419
1555
  remoteToken: decodeAddress(remoteTokenRaw, chain.family),
1420
1556
  remotePools: remotePools[i]!.map((pool) => decodeAddress(pool, chain.family)),
1421
- inboundRateLimiterState: remoteInfo[i]![1].isEnabled ? remoteInfo[i]![1] : null,
1422
- outboundRateLimiterState: remoteInfo[i]![2].isEnabled ? remoteInfo[i]![2] : null,
1557
+ outboundRateLimiterState: toRateLimiterState(remoteInfo[i]![1]),
1558
+ inboundRateLimiterState: toRateLimiterState(remoteInfo[i]![2]),
1559
+ ...(remoteInfo[i]!.length === 5 && {
1560
+ customBlockConfirmationsOutboundRateLimiterState: toRateLimiterState(
1561
+ remoteInfo[i]![3],
1562
+ ),
1563
+ customBlockConfirmationsInboundRateLimiterState: toRateLimiterState(
1564
+ remoteInfo[i]![4],
1565
+ ),
1566
+ }),
1423
1567
  },
1424
1568
  ] as const
1425
1569
  }),
@@ -1461,7 +1605,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1461
1605
  tokens = Array.from(tokens_)
1462
1606
  break
1463
1607
  }
1464
- case CCIPVersion.V1_6: {
1608
+ case CCIPVersion.V1_6:
1609
+ case CCIPVersion.V2_0: {
1465
1610
  const feeQuoter = await this.getFeeQuoterFor(onRamp)
1466
1611
  const contract = new Contract(
1467
1612
  feeQuoter,
@@ -1489,15 +1634,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1489
1634
  ): Promise<CCIPVerifications> {
1490
1635
  const { offRamp, request } = opts
1491
1636
  if (request.lane.version >= CCIPVersion.V2_0) {
1492
- const message = request.message as CCIPMessage_V2_0
1493
- if (!message.encodedMessage)
1494
- throw new CCIPNotImplementedError(`CCIPAPIClient getMessageById v2 encodedMessage`)
1637
+ const { encodedMessage } = request.message as CCIPMessage_V2_0
1495
1638
  const contract = new Contract(
1496
1639
  offRamp,
1497
1640
  interfaces.OffRamp_v2_0,
1498
1641
  this.provider,
1499
1642
  ) as unknown as TypedContract<typeof OffRamp_2_0_ABI>
1500
- const ccvs = await contract.getCCVsForMessage(message.encodedMessage)
1643
+ const ccvs = await contract.getCCVsForMessage(encodedMessage)
1501
1644
  const [requiredCCVs, optionalCCVs, optionalThreshold] = ccvs.map(
1502
1645
  resultToObject,
1503
1646
  ) as unknown as CleanAddressable<typeof ccvs>
@@ -1511,20 +1654,24 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1511
1654
  const apiRes = await this.apiClient.getMessageById(request.message.messageId)
1512
1655
  if ('verifiers' in apiRes.message) {
1513
1656
  const verifiers = apiRes.message.verifiers as {
1514
- items: {
1657
+ items?: {
1515
1658
  destAddress: string
1516
1659
  sourceAddress: string
1517
- verification: { data: string; timestamp: string }
1660
+ verification?: { data: string; timestamp: string }
1518
1661
  }[]
1519
1662
  }
1520
1663
  return {
1521
1664
  verificationPolicy,
1522
- verifications: verifiers.items.map((item) => ({
1523
- destAddress: item.destAddress,
1524
- sourceAddress: item.sourceAddress,
1525
- ccvData: item.verification.data,
1526
- timestamp: new Date(item.verification.timestamp).getTime() / 1e3,
1527
- })),
1665
+ verifications: (verifiers.items ?? [])
1666
+ .filter((item) => item.verification?.data)
1667
+ .map((item) => ({
1668
+ destAddress: item.destAddress,
1669
+ sourceAddress: item.sourceAddress,
1670
+ ccvData: item.verification!.data,
1671
+ ...(!!item.verification?.timestamp && {
1672
+ timestamp: new Date(item.verification.timestamp).getTime() / 1e3,
1673
+ }),
1674
+ })),
1528
1675
  }
1529
1676
  }
1530
1677
  }