@chainlink/ccip-sdk 0.95.0 → 0.96.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 (115) hide show
  1. package/README.md +2 -2
  2. package/dist/all-chains.d.ts +23 -0
  3. package/dist/all-chains.d.ts.map +1 -0
  4. package/dist/all-chains.js +24 -0
  5. package/dist/all-chains.js.map +1 -0
  6. package/dist/api/index.d.ts +15 -12
  7. package/dist/api/index.d.ts.map +1 -1
  8. package/dist/api/index.js +20 -16
  9. package/dist/api/index.js.map +1 -1
  10. package/dist/api/types.d.ts +25 -29
  11. package/dist/api/types.d.ts.map +1 -1
  12. package/dist/aptos/index.d.ts +33 -8
  13. package/dist/aptos/index.d.ts.map +1 -1
  14. package/dist/aptos/index.js +74 -41
  15. package/dist/aptos/index.js.map +1 -1
  16. package/dist/chain.d.ts +220 -41
  17. package/dist/chain.d.ts.map +1 -1
  18. package/dist/chain.js +105 -15
  19. package/dist/chain.js.map +1 -1
  20. package/dist/errors/codes.d.ts +2 -0
  21. package/dist/errors/codes.d.ts.map +1 -1
  22. package/dist/errors/codes.js +2 -0
  23. package/dist/errors/codes.js.map +1 -1
  24. package/dist/errors/index.d.ts +1 -1
  25. package/dist/errors/index.d.ts.map +1 -1
  26. package/dist/errors/index.js +1 -1
  27. package/dist/errors/index.js.map +1 -1
  28. package/dist/errors/recovery.d.ts.map +1 -1
  29. package/dist/errors/recovery.js +2 -0
  30. package/dist/errors/recovery.js.map +1 -1
  31. package/dist/errors/specialized.d.ts +12 -6
  32. package/dist/errors/specialized.d.ts.map +1 -1
  33. package/dist/errors/specialized.js +19 -7
  34. package/dist/errors/specialized.js.map +1 -1
  35. package/dist/evm/extra-args.d.ts +25 -0
  36. package/dist/evm/extra-args.d.ts.map +1 -0
  37. package/dist/evm/extra-args.js +328 -0
  38. package/dist/evm/extra-args.js.map +1 -0
  39. package/dist/evm/gas.d.ts.map +1 -1
  40. package/dist/evm/gas.js +7 -12
  41. package/dist/evm/gas.js.map +1 -1
  42. package/dist/evm/index.d.ts +70 -24
  43. package/dist/evm/index.d.ts.map +1 -1
  44. package/dist/evm/index.js +72 -91
  45. package/dist/evm/index.js.map +1 -1
  46. package/dist/execution.d.ts.map +1 -1
  47. package/dist/execution.js +16 -2
  48. package/dist/execution.js.map +1 -1
  49. package/dist/extra-args.d.ts +103 -4
  50. package/dist/extra-args.d.ts.map +1 -1
  51. package/dist/extra-args.js +28 -3
  52. package/dist/extra-args.js.map +1 -1
  53. package/dist/gas.d.ts +6 -3
  54. package/dist/gas.d.ts.map +1 -1
  55. package/dist/gas.js +14 -6
  56. package/dist/gas.js.map +1 -1
  57. package/dist/index.d.ts +10 -9
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +8 -8
  60. package/dist/index.js.map +1 -1
  61. package/dist/requests.d.ts +17 -9
  62. package/dist/requests.d.ts.map +1 -1
  63. package/dist/requests.js +17 -9
  64. package/dist/requests.js.map +1 -1
  65. package/dist/selectors.d.ts.map +1 -1
  66. package/dist/selectors.js +12 -0
  67. package/dist/selectors.js.map +1 -1
  68. package/dist/solana/index.d.ts +70 -15
  69. package/dist/solana/index.d.ts.map +1 -1
  70. package/dist/solana/index.js +72 -16
  71. package/dist/solana/index.js.map +1 -1
  72. package/dist/sui/index.d.ts +37 -9
  73. package/dist/sui/index.d.ts.map +1 -1
  74. package/dist/sui/index.js +40 -11
  75. package/dist/sui/index.js.map +1 -1
  76. package/dist/ton/index.d.ts +65 -19
  77. package/dist/ton/index.d.ts.map +1 -1
  78. package/dist/ton/index.js +155 -25
  79. package/dist/ton/index.js.map +1 -1
  80. package/dist/ton/send.d.ts +52 -0
  81. package/dist/ton/send.d.ts.map +1 -0
  82. package/dist/ton/send.js +166 -0
  83. package/dist/ton/send.js.map +1 -0
  84. package/dist/types.d.ts +102 -1
  85. package/dist/types.d.ts.map +1 -1
  86. package/dist/types.js.map +1 -1
  87. package/dist/utils.d.ts +15 -3
  88. package/dist/utils.d.ts.map +1 -1
  89. package/dist/utils.js +19 -6
  90. package/dist/utils.js.map +1 -1
  91. package/package.json +12 -7
  92. package/src/all-chains.ts +26 -0
  93. package/src/api/index.ts +26 -25
  94. package/src/api/types.ts +25 -30
  95. package/src/aptos/index.ts +79 -43
  96. package/src/chain.ts +274 -46
  97. package/src/errors/codes.ts +2 -0
  98. package/src/errors/index.ts +1 -1
  99. package/src/errors/recovery.ts +2 -0
  100. package/src/errors/specialized.ts +24 -7
  101. package/src/evm/extra-args.ts +377 -0
  102. package/src/evm/gas.ts +14 -13
  103. package/src/evm/index.ts +76 -125
  104. package/src/execution.ts +18 -2
  105. package/src/extra-args.ts +108 -4
  106. package/src/gas.ts +16 -9
  107. package/src/index.ts +12 -9
  108. package/src/requests.ts +17 -9
  109. package/src/selectors.ts +12 -0
  110. package/src/solana/index.ts +72 -16
  111. package/src/sui/index.ts +40 -11
  112. package/src/ton/index.ts +192 -27
  113. package/src/ton/send.ts +222 -0
  114. package/src/types.ts +103 -1
  115. package/src/utils.ts +19 -6
package/src/evm/index.ts CHANGED
@@ -13,9 +13,6 @@ import {
13
13
  Result,
14
14
  WebSocketProvider,
15
15
  ZeroAddress,
16
- concat,
17
- dataSlice,
18
- encodeBase58,
19
16
  getAddress,
20
17
  hexlify,
21
18
  isBytesLike,
@@ -49,23 +46,14 @@ import {
49
46
  CCIPMessageDecodeError,
50
47
  CCIPSourceChainUnsupportedError,
51
48
  CCIPTokenNotConfiguredError,
49
+ CCIPTokenPoolChainConfigNotFoundError,
52
50
  CCIPTransactionNotFoundError,
53
51
  CCIPVersionFeatureUnavailableError,
54
52
  CCIPVersionRequiresLaneError,
55
53
  CCIPVersionUnsupportedError,
56
54
  CCIPWalletInvalidError,
57
55
  } from '../errors/index.ts'
58
- import {
59
- type EVMExtraArgsV1,
60
- type EVMExtraArgsV2,
61
- type ExtraArgs,
62
- type SVMExtraArgsV1,
63
- type SuiExtraArgsV1,
64
- EVMExtraArgsV1Tag,
65
- EVMExtraArgsV2Tag,
66
- SVMExtraArgsV1Tag,
67
- SuiExtraArgsV1Tag,
68
- } from '../extra-args.ts'
56
+ import type { ExtraArgs } from '../extra-args.ts'
69
57
  import type { LeafHasher } from '../hasher/common.ts'
70
58
  import { supportedChains } from '../supported-chains.ts'
71
59
  import {
@@ -105,15 +93,12 @@ import EVM2EVMOnRamp_1_5_ABI from './abi/OnRamp_1_5.ts'
105
93
  import OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
106
94
  import type Router_ABI from './abi/Router.ts'
107
95
  import type TokenAdminRegistry_1_5_ABI from './abi/TokenAdminRegistry_1_5.ts'
108
- import {
109
- DEFAULT_GAS_LIMIT,
110
- commitsFragments,
111
- defaultAbiCoder,
112
- interfaces,
113
- receiptsFragments,
114
- requestsFragments,
115
- } from './const.ts'
96
+ import { commitsFragments, interfaces, receiptsFragments, requestsFragments } from './const.ts'
116
97
  import { parseData } from './errors.ts'
98
+ import {
99
+ decodeExtraArgs as decodeExtraArgs_,
100
+ encodeExtraArgs as encodeExtraArgs_,
101
+ } from './extra-args.ts'
117
102
  import { estimateExecGas } from './gas.ts'
118
103
  import { getV12LeafHasher, getV16LeafHasher } from './hasher.ts'
119
104
  import { getEvmLogs } from './logs.ts'
@@ -129,13 +114,6 @@ export type { UnsignedEVMTx }
129
114
 
130
115
  const VersionedContractABI = parseAbi(['function typeAndVersion() view returns (string)'])
131
116
 
132
- const EVMExtraArgsV1 = 'tuple(uint256 gasLimit)'
133
- const EVMExtraArgsV2 = 'tuple(uint256 gasLimit, bool allowOutOfOrderExecution)'
134
- const SVMExtraArgsV1 =
135
- 'tuple(uint32 computeUnits, uint64 accountIsWritableBitmap, bool allowOutOfOrderExecution, bytes32 tokenReceiver, bytes32[] accounts)'
136
- const SuiExtraArgsV1 =
137
- 'tuple(uint256 gasLimit, bool allowOutOfOrderExecution, bytes32 tokenReceiver, bytes32[] receiverObjectIds)'
138
-
139
117
  function resultToObject<T>(o: T): T {
140
118
  if (o instanceof Promise) return o.then(resultToObject) as T
141
119
  if (!(o instanceof Result)) return o
@@ -355,6 +333,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
355
333
  * Decodes a CCIP message from a log event.
356
334
  * @param log - Log event with topics and data.
357
335
  * @returns Decoded CCIPMessage or undefined if not a valid CCIP message.
336
+ * @throws {@link CCIPLogDataInvalidError} if log data is not valid bytes
337
+ * @throws {@link CCIPMessageDecodeError} if message cannot be decoded
358
338
  */
359
339
  static decodeMessage(log: {
360
340
  topics?: readonly string[]
@@ -456,6 +436,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
456
436
  * @param log - Log event with topics and data.
457
437
  * @param lane - Lane info (required for CCIP v1.5 and earlier).
458
438
  * @returns Array of CommitReport or undefined if not a valid commit event.
439
+ * @throws {@link CCIPLogDataInvalidError} if log data is not valid bytes
440
+ * @throws {@link CCIPVersionRequiresLaneError} if CCIP v1.5 event but no lane provided
459
441
  */
460
442
  static decodeCommits(
461
443
  log: { topics?: readonly string[]; data: unknown },
@@ -511,6 +493,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
511
493
  * Decodes an execution receipt from a log event.
512
494
  * @param log - Log event with topics and data.
513
495
  * @returns ExecutionReceipt or undefined if not a valid execution event.
496
+ * @throws {@link CCIPLogDataInvalidError} if log data is not valid bytes
514
497
  */
515
498
  static decodeReceipt(log: {
516
499
  topics?: readonly string[]
@@ -542,43 +525,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
542
525
  * @param extraArgs - Encoded extra arguments bytes.
543
526
  * @returns Decoded extra arguments with tag, or undefined if unknown format.
544
527
  */
545
- static decodeExtraArgs(
546
- extraArgs: BytesLike,
547
- ):
548
- | (EVMExtraArgsV1 & { _tag: 'EVMExtraArgsV1' })
549
- | (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
550
- | (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
551
- | (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
552
- | undefined {
553
- const data = getDataBytes(extraArgs),
554
- tag = dataSlice(data, 0, 4)
555
- switch (tag) {
556
- case EVMExtraArgsV1Tag: {
557
- const args = defaultAbiCoder.decode([EVMExtraArgsV1], dataSlice(data, 4))
558
- return { ...(resultToObject(args[0]) as EVMExtraArgsV1), _tag: 'EVMExtraArgsV1' }
559
- }
560
- case EVMExtraArgsV2Tag: {
561
- const args = defaultAbiCoder.decode([EVMExtraArgsV2], dataSlice(data, 4))
562
- return { ...(resultToObject(args[0]) as EVMExtraArgsV2), _tag: 'EVMExtraArgsV2' }
563
- }
564
- case SVMExtraArgsV1Tag: {
565
- const args = defaultAbiCoder.decode([SVMExtraArgsV1], dataSlice(data, 4))
566
- const parsed = resultToObject(args[0]) as SVMExtraArgsV1
567
- parsed.tokenReceiver = encodeBase58(parsed.tokenReceiver)
568
- parsed.accounts = parsed.accounts.map((a: string) => encodeBase58(a))
569
- return { ...parsed, _tag: 'SVMExtraArgsV1' }
570
- }
571
- case SuiExtraArgsV1Tag: {
572
- const args = defaultAbiCoder.decode([SuiExtraArgsV1], dataSlice(data, 4))
573
- const parsed = resultToObject(args[0]) as SuiExtraArgsV1
574
- return {
575
- ...parsed,
576
- _tag: 'SuiExtraArgsV1',
577
- }
578
- }
579
- default:
580
- return undefined
581
- }
528
+ static decodeExtraArgs(extraArgs: BytesLike) {
529
+ return decodeExtraArgs_(extraArgs)
582
530
  }
583
531
 
584
532
  /**
@@ -587,48 +535,14 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
587
535
  * @returns Encoded extra arguments as hex string.
588
536
  */
589
537
  static encodeExtraArgs(args: ExtraArgs | undefined): string {
590
- if (!args) return '0x'
591
- if ('computeUnits' in args) {
592
- return concat([
593
- SVMExtraArgsV1Tag,
594
- defaultAbiCoder.encode(
595
- [SVMExtraArgsV1],
596
- [
597
- {
598
- ...args,
599
- tokenReceiver: getAddressBytes(args.tokenReceiver),
600
- accounts: args.accounts.map((a) => getAddressBytes(a)),
601
- },
602
- ],
603
- ),
604
- ])
605
- } else if ('receiverObjectIds' in args) {
606
- return concat([
607
- SuiExtraArgsV1Tag,
608
- defaultAbiCoder.encode(
609
- [SuiExtraArgsV1],
610
- [
611
- {
612
- ...args,
613
- tokenReceiver: zeroPadValue(getAddressBytes(args.tokenReceiver), 32),
614
- receiverObjectIds: args.receiverObjectIds.map((a) => getDataBytes(a)),
615
- },
616
- ],
617
- ),
618
- ])
619
- } else if ('allowOutOfOrderExecution' in args) {
620
- if ((args as Partial<typeof args>).gasLimit == null) args.gasLimit = DEFAULT_GAS_LIMIT
621
- return concat([EVMExtraArgsV2Tag, defaultAbiCoder.encode([EVMExtraArgsV2], [args])])
622
- } else if ((args as Partial<typeof args>).gasLimit != null) {
623
- return concat([EVMExtraArgsV1Tag, defaultAbiCoder.encode([EVMExtraArgsV1], [args])])
624
- }
625
- return '0x'
538
+ return encodeExtraArgs_(args)
626
539
  }
627
540
 
628
541
  /**
629
542
  * Converts bytes to a checksummed EVM address.
630
543
  * @param bytes - Bytes to convert (must be 20 bytes or 32 bytes with leading zeros).
631
544
  * @returns Checksummed EVM address.
545
+ * @throws {@link CCIPAddressInvalidEvmError} if bytes cannot be converted to a valid EVM address
632
546
  */
633
547
  static getAddress(bytes: BytesLike): string {
634
548
  if (isHexString(bytes, 20)) return getAddress(bytes)
@@ -655,6 +569,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
655
569
  * Gets lane configuration from an OnRamp contract.
656
570
  * @param onRamp - OnRamp contract address.
657
571
  * @returns Lane configuration.
572
+ * @throws {@link CCIPContractTypeInvalidError} if contract doesn't have destChainSelector
658
573
  */
659
574
  async getLaneForOnRamp(onRamp: string): Promise<Lane> {
660
575
  const [, version] = await this.typeAndVersion(onRamp)
@@ -674,7 +589,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
674
589
  }
675
590
  }
676
591
 
677
- /** {@inheritDoc Chain.getRouterForOnRamp} */
592
+ /**
593
+ * {@inheritDoc Chain.getRouterForOnRamp}
594
+ * @throws {@link CCIPVersionUnsupportedError} if OnRamp version is not supported
595
+ */
678
596
  async getRouterForOnRamp(onRamp: string, destChainSelector: bigint): Promise<string> {
679
597
  const [, version] = await this.typeAndVersion(onRamp)
680
598
  let onRampABI
@@ -703,7 +621,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
703
621
  }
704
622
  }
705
623
 
706
- /** {@inheritDoc Chain.getRouterForOffRamp} */
624
+ /**
625
+ * {@inheritDoc Chain.getRouterForOffRamp}
626
+ * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
627
+ */
707
628
  async getRouterForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string> {
708
629
  const [, version] = await this.typeAndVersion(offRamp)
709
630
  let offRampABI, router
@@ -770,7 +691,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
770
691
  return contract.getOnRamp(destChainSelector) as Promise<string>
771
692
  }
772
693
 
773
- /** {@inheritDoc Chain.getOnRampForOffRamp} */
694
+ /**
695
+ * {@inheritDoc Chain.getOnRampForOffRamp}
696
+ * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
697
+ */
774
698
  async getOnRampForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string> {
775
699
  const [, version] = await this.typeAndVersion(offRamp)
776
700
  let offRampABI
@@ -803,7 +727,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
803
727
  }
804
728
  }
805
729
 
806
- /** {@inheritDoc Chain.getCommitStoreForOffRamp} */
730
+ /**
731
+ * {@inheritDoc Chain.getCommitStoreForOffRamp}
732
+ * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
733
+ */
807
734
  async getCommitStoreForOffRamp(offRamp: string): Promise<string> {
808
735
  const [, version] = await this.typeAndVersion(offRamp)
809
736
  let offRampABI
@@ -875,6 +802,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
875
802
  * @param lane - Lane configuration.
876
803
  * @param ctx - Context object containing logger.
877
804
  * @returns Leaf hasher function.
805
+ * @throws {@link CCIPSourceChainUnsupportedError} if source chain is not EVM for v1.2/v1.5
806
+ * @throws {@link CCIPHasherVersionUnsupportedError} if lane version is not supported
878
807
  */
879
808
  static getDestLeafHasher(
880
809
  { sourceChainSelector, destChainSelector, onRamp, version }: Lane,
@@ -911,7 +840,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
911
840
  return this.getOnRampForRouter(router, networkInfo(someOtherNetwork).chainSelector)
912
841
  }
913
842
 
914
- /** {@inheritDoc Chain.getTokenAdminRegistryFor} */
843
+ /**
844
+ * {@inheritDoc Chain.getTokenAdminRegistryFor}
845
+ * @throws {@link CCIPContractNotRouterError} if address is not a Router, OnRamp, or OffRamp
846
+ */
915
847
  async getTokenAdminRegistryFor(address: string): Promise<string> {
916
848
  let [type, version, typeAndVersion] = await this.typeAndVersion(address)
917
849
  if (type === 'TokenAdminRegistry') {
@@ -942,6 +874,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
942
874
  * @internal
943
875
  * @param address - Router or Ramp contract address.
944
876
  * @returns FeeQuoter contract address.
877
+ * @throws {@link CCIPContractNotRouterError} if address is not a Router, OnRamp, or OffRamp
878
+ * @throws {@link CCIPVersionFeatureUnavailableError} if contract version is below v1.6
945
879
  */
946
880
  async getFeeQuoterFor(address: string): Promise<string> {
947
881
  let [type, version, typeAndVersion] = await this.typeAndVersion(address)
@@ -1064,7 +998,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1064
998
  }
1065
999
  }
1066
1000
 
1067
- /** {@inheritDoc Chain.sendMessage} */
1001
+ /**
1002
+ * {@inheritDoc Chain.sendMessage}
1003
+ * @throws {@link CCIPWalletInvalidError} if wallet is not a valid Signer
1004
+ */
1068
1005
  async sendMessage(opts: Parameters<Chain['sendMessage']>[0]): Promise<CCIPRequest> {
1069
1006
  const wallet = opts.wallet
1070
1007
  if (!isSigner(wallet)) throw new CCIPWalletInvalidError(wallet)
@@ -1106,6 +1043,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1106
1043
  /**
1107
1044
  * {@inheritDoc Chain.generateUnsignedExecuteReport}
1108
1045
  * @returns array containing one unsigned `manuallyExecute` TransactionRequest object
1046
+ * @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
1109
1047
  */
1110
1048
  async generateUnsignedExecuteReport({
1111
1049
  offRamp,
@@ -1220,7 +1158,12 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1220
1158
  return { family: ChainFamily.EVM, transactions: [manualExecTx] }
1221
1159
  }
1222
1160
 
1223
- /** {@inheritDoc Chain.executeReport} */
1161
+ /**
1162
+ * {@inheritDoc Chain.executeReport}
1163
+ * @throws {@link CCIPWalletInvalidError} if wallet is not a valid Signer
1164
+ * @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
1165
+ * @throws {@link CCIPExecTxRevertedError} if execution transaction reverts
1166
+ */
1224
1167
  async executeReport(opts: Parameters<Chain['executeReport']>[0]) {
1225
1168
  const wallet = opts.wallet
1226
1169
  if (!isSigner(wallet)) throw new CCIPWalletInvalidError(wallet)
@@ -1272,7 +1215,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1272
1215
  return res as string[]
1273
1216
  }
1274
1217
 
1275
- /** {@inheritDoc Chain.getRegistryTokenConfig} */
1218
+ /**
1219
+ * {@inheritDoc Chain.getRegistryTokenConfig}
1220
+ * @throws {@link CCIPTokenNotConfiguredError} if token is not configured in registry
1221
+ */
1276
1222
  async getRegistryTokenConfig(
1277
1223
  registry: string,
1278
1224
  token: string,
@@ -1301,8 +1247,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1301
1247
  }
1302
1248
  }
1303
1249
 
1304
- /** {@inheritDoc Chain.getTokenPoolConfigs} */
1305
- async getTokenPoolConfigs(tokenPool: string): Promise<{
1250
+ /** {@inheritDoc Chain.getTokenPoolConfig} */
1251
+ async getTokenPoolConfig(tokenPool: string): Promise<{
1306
1252
  token: string
1307
1253
  router: string
1308
1254
  typeAndVersion: string
@@ -1387,23 +1333,28 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
1387
1333
  return Promise.all([supportedChains, remotePools, remoteInfo]).then(
1388
1334
  ([supportedChains, remotePools, remoteInfo]) =>
1389
1335
  Object.fromEntries(
1390
- supportedChains.map(
1391
- (chain, i) =>
1392
- [
1393
- chain.name,
1394
- {
1395
- remoteToken: decodeAddress(remoteInfo[i]![0], chain.family),
1396
- remotePools: remotePools[i]!.map((pool) => decodeAddress(pool, chain.family)),
1397
- inboundRateLimiterState: remoteInfo[i]![1].isEnabled ? remoteInfo[i]![1] : null,
1398
- outboundRateLimiterState: remoteInfo[i]![2].isEnabled ? remoteInfo[i]![2] : null,
1399
- },
1400
- ] as const,
1401
- ),
1336
+ supportedChains.map((chain, i) => {
1337
+ const remoteTokenRaw = remoteInfo[i]![0]
1338
+ if (!remoteTokenRaw || remoteTokenRaw.match(/^(0x)?0*$/))
1339
+ throw new CCIPTokenPoolChainConfigNotFoundError(tokenPool, tokenPool, chain.name)
1340
+ return [
1341
+ chain.name,
1342
+ {
1343
+ remoteToken: decodeAddress(remoteTokenRaw, chain.family),
1344
+ remotePools: remotePools[i]!.map((pool) => decodeAddress(pool, chain.family)),
1345
+ inboundRateLimiterState: remoteInfo[i]![1].isEnabled ? remoteInfo[i]![1] : null,
1346
+ outboundRateLimiterState: remoteInfo[i]![2].isEnabled ? remoteInfo[i]![2] : null,
1347
+ },
1348
+ ] as const
1349
+ }),
1402
1350
  ),
1403
1351
  )
1404
1352
  }
1405
1353
 
1406
- /** {@inheritDoc Chain.getFeeTokens} */
1354
+ /**
1355
+ * {@inheritDoc Chain.getFeeTokens}
1356
+ * @throws {@link CCIPVersionUnsupportedError} if OnRamp version is not supported
1357
+ */
1407
1358
  async getFeeTokens(router: string) {
1408
1359
  const onRamp = await this._getSomeOnRampFor(router)
1409
1360
  const [_, version] = await this.typeAndVersion(onRamp)
package/src/execution.ts CHANGED
@@ -77,11 +77,27 @@ export const discoverOffRamp = memoize(
77
77
  dest.network.chainSelector,
78
78
  )
79
79
  for (const offRamp of sourceOffRamps) {
80
- const destOnRamp = await source.getOnRampForOffRamp(offRamp, dest.network.chainSelector)
80
+ let destOnRamp: string
81
+ try {
82
+ destOnRamp = await source.getOnRampForOffRamp(offRamp, dest.network.chainSelector)
83
+ } catch {
84
+ logger.debug('discoverOffRamp: skipping offRamp', offRamp, '(no valid source chain config)')
85
+ continue
86
+ }
81
87
  const destRouter = await dest.getRouterForOnRamp(destOnRamp, source.network.chainSelector)
82
88
  const destOffRamps = await dest.getOffRampsForRouter(destRouter, source.network.chainSelector)
83
89
  for (const offRamp of destOffRamps) {
84
- const offRampsOnRamp = await dest.getOnRampForOffRamp(offRamp, source.network.chainSelector)
90
+ let offRampsOnRamp: string
91
+ try {
92
+ offRampsOnRamp = await dest.getOnRampForOffRamp(offRamp, source.network.chainSelector)
93
+ } catch {
94
+ logger.debug(
95
+ 'discoverOffRamp: skipping dest offRamp',
96
+ offRamp,
97
+ '(no valid source chain config)',
98
+ )
99
+ continue
100
+ }
85
101
  logger.debug(
86
102
  'discoverOffRamp: found, from',
87
103
  {
package/src/extra-args.ts CHANGED
@@ -8,6 +8,8 @@ import { ChainFamily } from './types.ts'
8
8
  export const EVMExtraArgsV1Tag = id('CCIP EVMExtraArgsV1').substring(0, 10) as '0x97a657c9'
9
9
  /** Tag identifier for EVMExtraArgsV2 encoding. */
10
10
  export const EVMExtraArgsV2Tag = id('CCIP EVMExtraArgsV2').substring(0, 10) as '0x181dcf10'
11
+ /** Tag identifier for GenericExtraArgsV3 encoding (tightly packed binary format). */
12
+ export const GenericExtraArgsV3Tag = '0x302326cb' as const
11
13
  /** Tag identifier for SVMExtraArgsV1 encoding. */
12
14
  export const SVMExtraArgsV1Tag = id('CCIP SVMExtraArgsV1').substring(0, 10) as '0x1f3b3aba'
13
15
  /** Tag identifier for SuiExtraArgsV1 encoding. */
@@ -15,6 +17,13 @@ export const SuiExtraArgsV1Tag = id('CCIP SuiExtraArgsV1').substring(0, 10) as '
15
17
 
16
18
  /**
17
19
  * EVM extra arguments version 1 with gas limit only.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const args: EVMExtraArgsV1 = {
24
+ * gasLimit: 200_000n,
25
+ * }
26
+ * ```
18
27
  */
19
28
  export type EVMExtraArgsV1 = {
20
29
  /** Gas limit for execution on the destination chain. */
@@ -24,14 +33,70 @@ export type EVMExtraArgsV1 = {
24
33
  /**
25
34
  * EVM extra arguments version 2 with out-of-order execution support.
26
35
  * Also known as GenericExtraArgsV2.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const args: EVMExtraArgsV2 = {
40
+ * gasLimit: 200_000n,
41
+ * allowOutOfOrderExecution: true,
42
+ * }
43
+ * ```
27
44
  */
28
45
  export type EVMExtraArgsV2 = EVMExtraArgsV1 & {
29
46
  /** Whether to allow out-of-order message execution. */
30
47
  allowOutOfOrderExecution: boolean
31
48
  }
32
49
 
50
+ /**
51
+ * Generic extra arguments version 3 with cross-chain verifiers and executor support.
52
+ * Uses tightly packed binary encoding (NOT ABI-encoded).
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const args: GenericExtraArgsV3 = {
57
+ * gasLimit: 200_000n,
58
+ * blockConfirmations: 5,
59
+ * ccvs: ['0x1234...'],
60
+ * ccvArgs: ['0x010203'],
61
+ * executor: '0x5678...',
62
+ * executorArgs: '0x',
63
+ * tokenReceiver: '0xReceiverAddress...',
64
+ * tokenArgs: '0x',
65
+ * }
66
+ * ```
67
+ */
68
+ export type GenericExtraArgsV3 = {
69
+ /** Gas limit for execution on the destination chain (uint32). */
70
+ gasLimit: bigint
71
+ /** Number of block confirmations required. */
72
+ blockConfirmations: number
73
+ /** Cross-chain verifier addresses (EVM addresses). */
74
+ ccvs: string[]
75
+ /** Per-CCV arguments (BytesLike). */
76
+ ccvArgs: BytesLike[]
77
+ /** Executor address (EVM address or empty string for none). */
78
+ executor: string
79
+ /** Executor-specific arguments (BytesLike). */
80
+ executorArgs: BytesLike
81
+ /** Token receiver address (checksummed EVM address or hex string). */
82
+ tokenReceiver: string
83
+ /** Token pool-specific arguments (BytesLike). */
84
+ tokenArgs: BytesLike
85
+ }
86
+
33
87
  /**
34
88
  * Solana (SVM) extra arguments version 1.
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const args: SVMExtraArgsV1 = {
93
+ * computeUnits: 200_000n,
94
+ * accountIsWritableBitmap: 0n,
95
+ * allowOutOfOrderExecution: true,
96
+ * tokenReceiver: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
97
+ * accounts: [],
98
+ * }
99
+ * ```
35
100
  */
36
101
  export type SVMExtraArgsV1 = {
37
102
  /** Compute units for Solana execution. */
@@ -48,6 +113,16 @@ export type SVMExtraArgsV1 = {
48
113
 
49
114
  /**
50
115
  * Sui extra arguments version 1.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const args: SuiExtraArgsV1 = {
120
+ * gasLimit: 200_000n,
121
+ * allowOutOfOrderExecution: true,
122
+ * tokenReceiver: '0x1234...abcd',
123
+ * receiverObjectIds: ['0xobject1...', '0xobject2...'],
124
+ * }
125
+ * ```
51
126
  */
52
127
  export type SuiExtraArgsV1 = EVMExtraArgsV2 & {
53
128
  /** Token receiver address on Sui. */
@@ -59,13 +134,31 @@ export type SuiExtraArgsV1 = EVMExtraArgsV2 & {
59
134
  /**
60
135
  * Union type of all supported extra arguments formats.
61
136
  */
62
- export type ExtraArgs = EVMExtraArgsV1 | EVMExtraArgsV2 | SVMExtraArgsV1 | SuiExtraArgsV1
137
+ export type ExtraArgs =
138
+ | EVMExtraArgsV1
139
+ | EVMExtraArgsV2
140
+ | GenericExtraArgsV3
141
+ | SVMExtraArgsV1
142
+ | SuiExtraArgsV1
63
143
 
64
144
  /**
65
145
  * Encodes extra arguments for CCIP messages.
66
- * The args are *to* a dest network, but are encoded as a message *from* this source chain
67
- * e.g. Solana uses Borsh to encode extraArgs in its produced requests, even those targetting EVM
68
- **/
146
+ * The args are *to* a dest network, but are encoded as a message *from* this source chain.
147
+ * E.g. Solana uses Borsh to encode extraArgs in its produced requests, even those targeting EVM.
148
+ * @param args - Extra arguments to encode
149
+ * @param from - Source chain family for encoding format (defaults to EVM)
150
+ * @returns Encoded extra arguments as hex string
151
+ * @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const encoded = encodeExtraArgs({
156
+ * gasLimit: 200_000n,
157
+ * allowOutOfOrderExecution: true,
158
+ * })
159
+ * // Returns: '0x181dcf10...'
160
+ * ```
161
+ */
69
162
  export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily.EVM): string {
70
163
  const chain = supportedChains[from]
71
164
  if (!chain) throw new CCIPChainFamilyUnsupportedError(from)
@@ -77,6 +170,16 @@ export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily
77
170
  * @param data - Extra arguments bytearray data.
78
171
  * @param from - Optional chain family to narrow decoding attempts.
79
172
  * @returns Extra arguments object if found, undefined otherwise.
173
+ * @throws {@link CCIPChainFamilyUnsupportedError} if specified chain family not supported
174
+ * @throws {@link CCIPExtraArgsParseError} if data cannot be parsed as valid extra args
175
+ *
176
+ * @example
177
+ * ```typescript
178
+ * const decoded = decodeExtraArgs('0x181dcf10...')
179
+ * if (decoded?._tag === 'EVMExtraArgsV2') {
180
+ * console.log(decoded.gasLimit, decoded.allowOutOfOrderExecution)
181
+ * }
182
+ * ```
80
183
  */
81
184
  export function decodeExtraArgs(
82
185
  data: BytesLike,
@@ -84,6 +187,7 @@ export function decodeExtraArgs(
84
187
  ):
85
188
  | (EVMExtraArgsV1 & { _tag: 'EVMExtraArgsV1' })
86
189
  | (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
190
+ | (GenericExtraArgsV3 & { _tag: 'GenericExtraArgsV3' })
87
191
  | (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
88
192
  | (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
89
193
  | undefined {
package/src/gas.ts CHANGED
@@ -10,7 +10,7 @@ import { discoverOffRamp } from './execution.ts'
10
10
  import { sourceToDestTokenAddresses } from './requests.ts'
11
11
 
12
12
  /**
13
- * A subset of [[MessageInput]] for estimating receive execution gas.
13
+ * A subset of {@link MessageInput} for estimating receive execution gas.
14
14
  */
15
15
  export type EstimateMessageInput = {
16
16
  /** receiver contract address */
@@ -19,7 +19,7 @@ export type EstimateMessageInput = {
19
19
  messageId?: string
20
20
  /** optional sender: zero address will be used if omitted */
21
21
  sender?: string
22
- /** optional data: zero bytes will be used if ommitted */
22
+ /** optional data: zero bytes will be used if omitted */
23
23
  data?: BytesLike
24
24
  /**
25
25
  * optional tokenAmounts; `amount` with either source `token` (as in MessageInput) or
@@ -35,7 +35,7 @@ export type EstimateMessageInput = {
35
35
  }
36
36
 
37
37
  /**
38
- * Options for [[estimateReceiveExecution]] function.
38
+ * Options for {@link estimateReceiveExecution} function.
39
39
  */
40
40
  export type EstimateReceiveExecutionOpts = {
41
41
  /** Source chain instance (for token data retrieval) */
@@ -52,6 +52,9 @@ export type EstimateReceiveExecutionOpts = {
52
52
  * Estimate CCIP gasLimit needed to execute a request on a contract receiver.
53
53
  * @param opts - Options for estimation: source and dest chains, router or ramp address, and message
54
54
  * @returns Estimated gasLimit.
55
+ * @throws {@link CCIPMethodUnsupportedError} if dest chain doesn't support estimation
56
+ * @throws {@link CCIPContractTypeInvalidError} if routerOrRamp is not a valid contract type
57
+ * @throws {@link CCIPTokenDecimalsInsufficientError} if dest token has insufficient decimals
55
58
  */
56
59
  export async function estimateReceiveExecution({
57
60
  source,
@@ -69,12 +72,16 @@ export async function estimateReceiveExecution({
69
72
  onRamp = await source.getOnRampForRouter(routerOrRamp, dest.network.chainSelector)
70
73
  else onRamp = routerOrRamp
71
74
  offRamp = await discoverOffRamp(source, dest, onRamp, source)
72
- } catch {
73
- const tnv = await dest.typeAndVersion(routerOrRamp)
74
- if (!tnv[0].includes('OffRamp'))
75
- throw new CCIPContractTypeInvalidError(routerOrRamp, tnv[2], ['OffRamp'])
76
- offRamp = routerOrRamp
77
- onRamp = await dest.getOnRampForOffRamp(offRamp, source.network.chainSelector)
75
+ } catch (sourceErr) {
76
+ try {
77
+ const tnv = await dest.typeAndVersion(routerOrRamp)
78
+ if (!tnv[0].includes('OffRamp'))
79
+ throw new CCIPContractTypeInvalidError(routerOrRamp, tnv[2], ['OffRamp'])
80
+ offRamp = routerOrRamp
81
+ onRamp = await dest.getOnRampForOffRamp(offRamp, source.network.chainSelector)
82
+ } catch {
83
+ throw sourceErr // re-throw original error
84
+ }
78
85
  }
79
86
 
80
87
  const destTokenAmounts = await Promise.all(
package/src/index.ts CHANGED
@@ -1,5 +1,14 @@
1
+ /**
2
+ * \@chainlink/ccip-sdk - SDK for interacting with Chainlink CCIP (Cross-Chain Interoperability Protocol).
3
+ *
4
+ * This package provides tools for sending cross-chain messages, tracking message status,
5
+ * and executing manual message delivery across supported blockchain networks.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
1
10
  export type {
2
- APICCIPRequest,
11
+ APICCIPRequestMetadata,
3
12
  APIErrorResponse,
4
13
  CCIPAPIClientContext,
5
14
  LaneLatencyResponse,
@@ -15,7 +24,9 @@ export type {
15
24
  GetBalanceOpts,
16
25
  LogFilter,
17
26
  RateLimiterState,
27
+ RegistryTokenConfig,
18
28
  TokenInfo,
29
+ TokenPoolConfig,
19
30
  TokenPoolRemote,
20
31
  } from './chain.ts'
21
32
  export { DEFAULT_API_RETRY_CONFIG } from './chain.ts'
@@ -87,11 +98,3 @@ import { ChainFamily, NetworkType } from './types.ts'
87
98
  export { AptosChain, ChainFamily, EVMChain, NetworkType, SolanaChain, SuiChain, TONChain }
88
99
  // use `supportedChains` to override/register derived classes, if needed
89
100
  export { supportedChains } from './supported-chains.ts'
90
- // import `allSupportedChains` to get them all registered, in tree-shaken environments
91
- export const allSupportedChains = {
92
- [ChainFamily.EVM]: EVMChain,
93
- [ChainFamily.Solana]: SolanaChain,
94
- [ChainFamily.Aptos]: AptosChain,
95
- [ChainFamily.Sui]: SuiChain,
96
- [ChainFamily.TON]: TONChain,
97
- }