@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
@@ -77,15 +77,14 @@ import {
77
77
  type CCIPMessage,
78
78
  type CCIPRequest,
79
79
  type CCIPVerifications,
80
+ type ChainLog,
80
81
  type ChainTransaction,
81
82
  type CommitReport,
82
83
  type ExecutionInput,
83
84
  type ExecutionReceipt,
84
85
  type Lane,
85
- type Log_,
86
86
  type MergeArrayElements,
87
87
  type NetworkInfo,
88
- type OffchainTokenData,
89
88
  type WithLogger,
90
89
  CCIPVersion,
91
90
  ChainFamily,
@@ -113,7 +112,6 @@ import { IDL as CCIP_CCTP_TOKEN_POOL } from './idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts
113
112
  import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
114
113
  import { IDL as CCIP_ROUTER_IDL } from './idl/1.6.0/CCIP_ROUTER.ts'
115
114
  import { getTransactionsForAddress } from './logs.ts'
116
- import { fetchSolanaOffchainTokenData } from './offchain.ts'
117
115
  import { generateUnsignedCcipSend, getFee } from './send.ts'
118
116
  import { type CCIPMessage_V1_6_Solana, type UnsignedSolanaTx, isWallet } from './types.ts'
119
117
  import {
@@ -160,7 +158,7 @@ const unknownTokens: { [mint: string]: string } = {
160
158
  }
161
159
 
162
160
  /** Solana-specific log structure with transaction reference and log level. */
163
- export type SolanaLog = Log_ & { tx: SolanaTransaction; data: string; level: number }
161
+ export type SolanaLog = ChainLog & { tx: SolanaTransaction; data: string; level: number }
164
162
  /** Solana-specific transaction structure with versioned transaction response. */
165
163
  export type SolanaTransaction = MergeArrayElements<
166
164
  ChainTransaction,
@@ -430,13 +428,13 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
430
428
  * - `watch`: Watch for new logs
431
429
  * - `programs`: Special option to allow querying by address of interest, but yielding matching
432
430
  * logs from specific (string address) program or any (true)
433
- * @returns AsyncIterableIterator of parsed Log_ objects.
431
+ * @returns AsyncIterableIterator of parsed ChainLog objects.
434
432
  * @throws {@link CCIPLogsAddressRequiredError} if address is not provided
435
433
  * @throws {@link CCIPTopicsInvalidError} if topics contain invalid values
436
434
  */
437
435
  async *getLogs(
438
436
  opts: LogFilter & { programs?: string[] | true },
439
- ): AsyncGenerator<Log_ & { tx: SolanaTransaction }> {
437
+ ): AsyncGenerator<ChainLog & { tx: SolanaTransaction }> {
440
438
  let programs: true | string[]
441
439
  if (!opts.address) {
442
440
  throw new CCIPLogsAddressRequiredError()
@@ -895,7 +893,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
895
893
  * @throws {@link CCIPLogDataMissingError} if log data is missing
896
894
  */
897
895
  static decodeCommits(
898
- log: Pick<Log_, 'data'>,
896
+ log: Pick<ChainLog, 'data'>,
899
897
  lane?: Omit<Lane, 'destChainSelector'>,
900
898
  ): CommitReport[] | undefined {
901
899
  // Check if this is a CommitReportAccepted event by looking at the discriminant
@@ -950,7 +948,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
950
948
  * @throws {@link CCIPLogDataMissingError} if log data is missing
951
949
  * @throws {@link CCIPExecutionStateInvalidError} if execution state is invalid
952
950
  */
953
- static decodeReceipt(log: Pick<Log_, 'data' | 'tx' | 'index'>): ExecutionReceipt | undefined {
951
+ static decodeReceipt(log: Pick<ChainLog, 'data' | 'tx' | 'index'>): ExecutionReceipt | undefined {
954
952
  // Check if this is a ExecutionStateChanged event by looking at the discriminant
955
953
  if (!log.data || typeof log.data !== 'string') {
956
954
  throw new CCIPLogDataMissingError()
@@ -983,7 +981,7 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
983
981
  } else throw new CCIPExecutionStateInvalidError(util.inspect(decoded.data.state))
984
982
 
985
983
  let returnData
986
- if (log.tx) {
984
+ if (log.tx?.logs) {
987
985
  // use only last receipt per tx+message (i.e. skip intermediary InProgress=1 states for Solana)
988
986
  const laterReceiptLog = log.tx.logs
989
987
  .filter((l) => l.index > log.index)
@@ -1107,11 +1105,6 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1107
1105
  return (await this.getMessagesInTx(await this.getTransaction(hash)))[0]!
1108
1106
  }
1109
1107
 
1110
- /** {@inheritDoc Chain.getOffchainTokenData} */
1111
- async getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
1112
- return fetchSolanaOffchainTokenData(request, this)
1113
- }
1114
-
1115
1108
  /**
1116
1109
  * {@inheritDoc Chain.generateUnsignedExecute}
1117
1110
  * @returns instructions - array of instructions to execute the report
@@ -1209,13 +1202,13 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1209
1202
  if (Array.isArray(data)) {
1210
1203
  if (data.every((e) => typeof e === 'string')) return getErrorFromLogs(data)
1211
1204
  else if (data.every((e) => typeof e === 'object' && 'data' in e && 'address' in e))
1212
- return getErrorFromLogs(data as Log_[])
1205
+ return getErrorFromLogs(data as ChainLog[])
1213
1206
  } else if (typeof data === 'object') {
1214
1207
  if ('transactionLogs' in data && 'transactionMessage' in data) {
1215
- const parsed = getErrorFromLogs(data.transactionLogs as Log_[] | string[])
1208
+ const parsed = getErrorFromLogs(data.transactionLogs as ChainLog[] | string[])
1216
1209
  if (parsed) return { message: data.transactionMessage, ...parsed }
1217
1210
  }
1218
- if ('logs' in data) return getErrorFromLogs(data.logs as Log_[] | string[])
1211
+ if ('logs' in data) return getErrorFromLogs(data.logs as ChainLog[] | string[])
1219
1212
  } else if (typeof data === 'string') {
1220
1213
  const parsedExtraArgs = this.decodeExtraArgs(getDataBytes(data))
1221
1214
  if (parsedExtraArgs) return parsedExtraArgs
@@ -1597,6 +1590,23 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1597
1590
  static override buildMessageForDest(
1598
1591
  message: Parameters<ChainStatic['buildMessageForDest']>[0],
1599
1592
  ): AnyMessage & { extraArgs: SVMExtraArgsV1 } {
1593
+ /** Valid field names for SVMExtraArgsV1, including recognised aliases. */
1594
+ const SVM_EXTRA_ARGS_FIELDS = new Set([
1595
+ 'computeUnits',
1596
+ 'gasLimit', // alias for computeUnits
1597
+ 'allowOutOfOrderExecution',
1598
+ 'tokenReceiver',
1599
+ 'accounts',
1600
+ 'accountIsWritableBitmap',
1601
+ ])
1602
+ if (message.extraArgs) {
1603
+ const unknown = Object.keys(message.extraArgs).filter((k) => !SVM_EXTRA_ARGS_FIELDS.has(k))
1604
+ if (unknown.length)
1605
+ throw new CCIPArgumentInvalidError(
1606
+ 'extraArgs',
1607
+ `unknown field(s) for SVMExtraArgsV1: ${unknown.map((k) => JSON.stringify(k)).join(', ')}`,
1608
+ )
1609
+ }
1600
1610
  if (
1601
1611
  !(
1602
1612
  message.extraArgs &&
@@ -1,29 +1,10 @@
1
- import { type BN, BorshCoder } from '@coral-xyz/anchor'
2
- import type { PublicKey } from '@solana/web3.js'
1
+ import { BorshCoder } from '@coral-xyz/anchor'
3
2
  import { hexlify } from 'ethers'
4
3
 
5
- import {
6
- CCIPCctpDecodeError,
7
- CCIPCctpMultipleEventsError,
8
- CCIPDataFormatUnsupportedError,
9
- } from '../errors/index.ts'
10
- import { getUsdcAttestation } from '../offchain.ts'
11
- import type { CCIPMessage, CCIPRequest, OffchainTokenData, WithLogger } from '../types.ts'
12
- import { bytesToBuffer, networkInfo, util } from '../utils.ts'
4
+ import type { OffchainTokenData } from '../types.ts'
5
+ import { bytesToBuffer } from '../utils.ts'
13
6
  import { IDL as BASE_TOKEN_POOL } from './idl/1.6.0/BASE_TOKEN_POOL.ts'
14
7
  import { IDL as CCTP_TOKEN_POOL } from './idl/1.6.0/CCIP_CCTP_TOKEN_POOL.ts'
15
- import type { SolanaLog, SolanaTransaction } from './index.ts'
16
- import { hexDiscriminator } from './utils.ts'
17
-
18
- interface CcipCctpMessageSentEvent {
19
- originalSender: PublicKey
20
- remoteChainSelector: BN
21
- msgTotalNonce: BN
22
- eventAddress: PublicKey
23
- sourceDomain: number
24
- cctpNonce: BN
25
- messageSentBytes: Uint8Array
26
- }
27
8
 
28
9
  interface CcipCctpMessageAndAttestation {
29
10
  message: {
@@ -38,84 +19,6 @@ const cctpTokenPoolCoder = new BorshCoder({
38
19
  errors: [...BASE_TOKEN_POOL.errors, ...CCTP_TOKEN_POOL.errors],
39
20
  })
40
21
 
41
- /**
42
- * Analyzes a Solana transaction to extract CcipCctpMessageSentEvent, fetch Circle attestation,
43
- * and encode the data in the format required by the destination chain.
44
- * @param request - CCIP request containing transaction data and chain routing info.
45
- * @param logger - Logger instance for logging messages.
46
- * @returns Array of encoded offchain token data (only one supported for Solana right now).
47
- * @throws Error if transaction hash is missing or CcipCctpMessageSentEvent parsing fails.
48
- */
49
- export async function fetchSolanaOffchainTokenData(
50
- request: Pick<CCIPRequest, 'tx' | 'lane'> & {
51
- message: CCIPMessage
52
- log: Pick<CCIPRequest['log'], 'topics' | 'index' | 'transactionHash' | 'address'>
53
- },
54
- { logger = console }: WithLogger = {},
55
- ): Promise<OffchainTokenData[]> {
56
- if (!request.message.tokenAmounts.length) {
57
- return []
58
- }
59
-
60
- if (request.message.tokenAmounts.length > 1) {
61
- throw new CCIPDataFormatUnsupportedError(
62
- `Expected at most 1 token transfer, found ${request.message.tokenAmounts.length}`,
63
- )
64
- }
65
-
66
- const { networkType } = networkInfo(request.lane.sourceChainSelector)
67
- const txSignature = request.log.transactionHash
68
-
69
- // Parse Solana transaction to find CCTP event
70
- const tx = request.tx as SolanaTransaction
71
- const log = request.log as SolanaLog
72
- const logMessages = tx.tx.meta!.logMessages!
73
- // there may have multiple ccipSend calls in same tx;
74
- // use `invoke [level]` to filter only logs inside this call
75
- const requestInvokeIdx = logMessages.findLastIndex(
76
- (l, i) => i < log.index && l === `Program ${request.log.address} invoke [${log.level}]`,
77
- )
78
- const cctpEvents = []
79
- for (const l of tx.logs) {
80
- if (requestInvokeIdx >= l.index || l.index >= log.index) continue
81
- if (l.topics[0] !== hexDiscriminator('CcipCctpMessageSentEvent')) continue
82
- const decoded = cctpTokenPoolCoder.events.decode(l.data)
83
- if (!decoded) throw new CCIPCctpDecodeError(util.inspect(l))
84
- cctpEvents.push(decoded.data as unknown as CcipCctpMessageSentEvent)
85
- }
86
- const offchainTokenData: OffchainTokenData[] = request.message.tokenAmounts.map(() => undefined)
87
-
88
- // If no CcipCctpMessageSentEvent found, return defaults so we don't block execution
89
- if (cctpEvents.length === 0) {
90
- logger.debug('No USDC/CCTP events found')
91
- return offchainTokenData
92
- }
93
-
94
- // Currently, we only support ONE token per transfer
95
- if (cctpEvents.length > 1) {
96
- throw new CCIPCctpMultipleEventsError(cctpEvents.length, txSignature)
97
- }
98
-
99
- // NOTE: assuming USDC token is the first (and only) token in the CCIP message, we will process the CCTP event.
100
- // If later multi-token transfers support is added, we need to add more info in order to match each token with it's event and offchainTokenData.
101
- const cctpEvent = cctpEvents[0]
102
- if (cctpEvent) {
103
- const message = hexlify(cctpEvent.messageSentBytes)
104
- try {
105
- // Extract message bytes to fetch circle's attestation and then encode offchainTokenData.
106
- const attestation = await getUsdcAttestation(message, networkType)
107
-
108
- offchainTokenData[0] = { _tag: 'usdc', message, attestation }
109
- } catch (error) {
110
- logger.warn(`❌ Solana CCTP: Failed to fetch attestation for ${txSignature}:`, message, error)
111
- }
112
- }
113
-
114
- logger.debug('Got Solana offchain token data', offchainTokenData)
115
-
116
- return offchainTokenData
117
- }
118
-
119
22
  /**
120
23
  * Encodes CCTP message and attestation
121
24
  *
@@ -26,7 +26,7 @@ import {
26
26
  CCIPTokenMintNotFoundError,
27
27
  CCIPTransactionNotFinalizedError,
28
28
  } from '../errors/index.ts'
29
- import type { Log_, WithLogger } from '../types.ts'
29
+ import type { ChainLog, WithLogger } from '../types.ts'
30
30
  import { getDataBytes, sleep } from '../utils.ts'
31
31
  import type { IDL as BASE_TOKEN_POOL_IDL } from './idl/1.6.0/BASE_TOKEN_POOL.ts'
32
32
  import type { UnsignedSolanaTx, Wallet } from './types.ts'
@@ -143,7 +143,7 @@ export function camelToSnakeCase(str: string): string {
143
143
  .replace(/^_/, '')
144
144
  }
145
145
 
146
- type ParsedLog = Pick<Log_, 'topics' | 'index' | 'address' | 'data'> & {
146
+ type ParsedLog = Pick<ChainLog, 'topics' | 'index' | 'address' | 'data'> & {
147
147
  data: string
148
148
  level: number
149
149
  }
@@ -160,7 +160,7 @@ type ParsedLog = Pick<Log_, 'topics' | 'index' | 'address' | 'data'> & {
160
160
  * This function:
161
161
  * 1. Tracks the program call stack to determine which program emitted each log
162
162
  * 2. Extracts the first 8 bytes from base64 "Program data:" logs as topics (event discriminants)
163
- * 3. Converts logs to EVM-compatible Log_ format for CCIP compatibility
163
+ * 3. Converts logs to EVM-compatible ChainLog format for CCIP compatibility
164
164
  * 4. Returns ALL logs from the transaction - filtering should be done by the caller
165
165
  *
166
166
  * @param logs - Array of logMessages from Solana transaction
@@ -215,7 +215,10 @@ export function parseSolanaLogs(logs: readonly string[]): ParsedLog[] {
215
215
  * @returns Parsed error info with program and error details.
216
216
  */
217
217
  export function getErrorFromLogs(
218
- logs_: readonly string[] | readonly Pick<Log_, 'address' | 'index' | 'data' | 'topics'>[] | null,
218
+ logs_:
219
+ | readonly string[]
220
+ | readonly Pick<ChainLog, 'address' | 'index' | 'data' | 'topics'>[]
221
+ | null,
219
222
  ): { program: string; [k: string]: string } | undefined {
220
223
  if (!logs_?.length) return
221
224
  let logs
@@ -229,7 +232,7 @@ export function getErrorFromLogs(
229
232
  (acc, l) =>
230
233
  // if acc is empty (i.e. on last log), or it is emitted by the same program and not a Program data:
231
234
  !acc.length || (l.address === acc[0]!.address && !l.topics.length) ? [l, ...acc] : acc,
232
- [] as Pick<Log_, 'address' | 'index' | 'data'>[],
235
+ [] as Pick<ChainLog, 'address' | 'index' | 'data'>[],
233
236
  )
234
237
  .map(({ data }) => data as string)
235
238
  .reduceRight(
package/src/sui/index.ts CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  getReceiverModule,
26
26
  } from './objects.ts'
27
27
  import {
28
+ CCIPArgumentInvalidError,
28
29
  CCIPContractNotRouterError,
29
30
  CCIPDataFormatUnsupportedError,
30
31
  CCIPError,
@@ -47,15 +48,14 @@ import {
47
48
  type CCIPMessage,
48
49
  type CCIPRequest,
49
50
  type CCIPVersion,
51
+ type ChainLog,
50
52
  type ChainTransaction,
51
53
  type CommitReport,
52
54
  type ExecutionInput,
53
55
  type ExecutionReceipt,
54
56
  type ExecutionState,
55
57
  type Lane,
56
- type Log_,
57
58
  type NetworkInfo,
58
- type OffchainTokenData,
59
59
  type WithLogger,
60
60
  ChainFamily,
61
61
  } from '../types.ts'
@@ -181,7 +181,7 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
181
181
  })
182
182
 
183
183
  // Extract events from the transaction
184
- const events: Log_[] = []
184
+ const events: ChainLog[] = []
185
185
  if (txResponse.events?.length) {
186
186
  for (const [i, event] of txResponse.events.entries()) {
187
187
  const eventType = event.type
@@ -576,7 +576,7 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
576
576
  * @returns Decoded CCIPMessage or undefined if not valid.
577
577
  * @throws {@link CCIPSuiLogInvalidError} if log data format is invalid
578
578
  */
579
- static decodeMessage(log: Log_): CCIPMessage | undefined {
579
+ static decodeMessage(log: ChainLog): CCIPMessage | undefined {
580
580
  const { data } = log
581
581
  if (
582
582
  (typeof data !== 'string' || !data.startsWith('{')) &&
@@ -622,7 +622,7 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
622
622
  * @returns Array of decoded commit reports or undefined.
623
623
  */
624
624
  static decodeCommits(
625
- { data, topics }: SetOptional<Pick<Log_, 'data' | 'topics'>, 'topics'>,
625
+ { data, topics }: SetOptional<Pick<ChainLog, 'data' | 'topics'>, 'topics'>,
626
626
  lane?: Lane,
627
627
  ): CommitReport[] | undefined {
628
628
  // Check if this is an CommitReportAccepted event
@@ -658,7 +658,7 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
658
658
  static decodeReceipt({
659
659
  data,
660
660
  topics,
661
- }: SetOptional<Pick<Log_, 'data' | 'topics'>, 'topics'>): ExecutionReceipt | undefined {
661
+ }: SetOptional<Pick<ChainLog, 'data' | 'topics'>, 'topics'>): ExecutionReceipt | undefined {
662
662
  // Check if this is an ExecutionStateChanged event
663
663
  if (topics?.[0] && topics[0] !== 'ExecutionStateChanged') return
664
664
 
@@ -728,12 +728,6 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
728
728
  return Promise.reject(new CCIPNotImplementedError('SuiChain.sendMessage'))
729
729
  }
730
730
 
731
- /** {@inheritDoc Chain.getOffchainTokenData} */
732
- getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
733
- // default offchain token data
734
- return Promise.resolve(request.message.tokenAmounts.map(() => undefined))
735
- }
736
-
737
731
  /** {@inheritDoc Chain.generateUnsignedExecute} */
738
732
  override generateUnsignedExecute(
739
733
  _opts: Parameters<Chain['generateUnsignedExecute']>[0],
@@ -888,6 +882,22 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
888
882
  static override buildMessageForDest(
889
883
  message: Parameters<ChainStatic['buildMessageForDest']>[0],
890
884
  ): AnyMessage & { extraArgs: SuiExtraArgsV1 } {
885
+ /** Valid field names for SuiExtraArgsV1, including recognised aliases. */
886
+ const SUI_EXTRA_ARGS_FIELDS = new Set([
887
+ 'gasLimit',
888
+ 'allowOutOfOrderExecution',
889
+ 'tokenReceiver',
890
+ 'receiverObjectIds',
891
+ 'accounts', // alias for receiverObjectIds
892
+ ])
893
+ if (message.extraArgs) {
894
+ const unknown = Object.keys(message.extraArgs).filter((k) => !SUI_EXTRA_ARGS_FIELDS.has(k))
895
+ if (unknown.length)
896
+ throw new CCIPArgumentInvalidError(
897
+ 'extraArgs',
898
+ `unknown field(s) for SuiExtraArgsV1: ${unknown.map((k) => JSON.stringify(k)).join(', ')}`,
899
+ )
900
+ }
891
901
  const gasLimit =
892
902
  message.extraArgs && 'gasLimit' in message.extraArgs && message.extraArgs.gasLimit != null
893
903
  ? message.extraArgs.gasLimit
package/src/ton/exec.ts CHANGED
@@ -1,11 +1,8 @@
1
1
  import { type Cell, beginCell } from '@ton/core'
2
2
 
3
3
  import type { ExecutionInput } from '../types.ts'
4
- import {
5
- type CCIPMessage_V1_6_TON,
6
- MANUALLY_EXECUTE_OPCODE,
7
- serializeExecutionReport,
8
- } from './types.ts'
4
+ import { MANUALLY_EXECUTE_OPCODE, serializeExecutionReport } from './types.ts'
5
+ import type { CCIPMessage_V1_6_EVM } from '../evm/messages.ts'
9
6
 
10
7
  /**
11
8
  * Generates an unsigned execute report payload for the TON OffRamp contract.
@@ -17,7 +14,7 @@ import {
17
14
  */
18
15
  export function generateUnsignedExecuteReport(
19
16
  offRamp: string,
20
- execReport: ExecutionInput<CCIPMessage_V1_6_TON>,
17
+ execReport: ExecutionInput<CCIPMessage_V1_6_EVM>,
21
18
  opts?: { gasLimit?: number },
22
19
  ): { to: string; body: Cell } {
23
20
  // Serialize the execution report
package/src/ton/index.ts CHANGED
@@ -29,14 +29,13 @@ import { supportedChains } from '../supported-chains.ts'
29
29
  import {
30
30
  type CCIPExecution,
31
31
  type CCIPRequest,
32
+ type ChainLog,
32
33
  type ChainTransaction,
33
34
  type CommitReport,
34
35
  type ExecutionInput,
35
36
  type ExecutionReceipt,
36
37
  type Lane,
37
- type Log_,
38
38
  type NetworkInfo,
39
- type OffchainTokenData,
40
39
  type WithLogger,
41
40
  CCIPVersion,
42
41
  ChainFamily,
@@ -52,8 +51,9 @@ import {
52
51
  } from '../utils.ts'
53
52
  import { generateUnsignedExecuteReport } from './exec.ts'
54
53
  import { getTONLeafHasher } from './hasher.ts'
55
- import { type CCIPMessage_V1_6_TON, type UnsignedTONTx, isTONWallet } from './types.ts'
54
+ import { type UnsignedTONTx, isTONWallet } from './types.ts'
56
55
  import { crc32, lookupTxByRawHash, parseJettonContent } from './utils.ts'
56
+ import type { CCIPMessage_V1_6_EVM } from '../evm/messages.ts'
57
57
  export type { TONWallet, UnsignedTONTx } from './types.ts'
58
58
 
59
59
  /**
@@ -308,18 +308,22 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
308
308
  const compositeHash = `${address.toRawString()}:${tx.lt}:${tx.hash().toString('hex')}`
309
309
  const res = {
310
310
  hash: compositeHash,
311
- logs: [] as Log_[],
311
+ logs: [] as ChainLog[],
312
312
  blockNumber: Number(tx.lt), // Note: This is lt (logical time), not block seqno
313
313
  timestamp: tx.now,
314
314
  from: address.toRawString(),
315
315
  tx,
316
316
  }
317
- const logs: Log_[] = []
317
+ const logs: ChainLog[] = []
318
318
  for (const [index, msg] of tx.outMessages) {
319
319
  if (msg.info.type !== 'external-out') continue
320
320
  const topics = []
321
321
  // logs are external messages where dest "address" is the uint32 topic (e.g. crc32("ExecutionStateChanged"))
322
- if (msg.info.dest && msg.info.dest.value > 0n && msg.info.dest.value < 2n ** 32n)
322
+ if (
323
+ msg.info.dest &&
324
+ msg.info.dest.value > 0n &&
325
+ msg.info.dest.value < BigInt(2) ** BigInt(32)
326
+ )
323
327
  topics.push(toBeHex(msg.info.dest.value, 4))
324
328
  let data = ''
325
329
  try {
@@ -350,7 +354,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
350
354
  * @param opts - Log filter options (startBlock/endBlock are interpreted as lt values)
351
355
  * @throws {@link CCIPTopicsInvalidError} if topics format is invalid
352
356
  */
353
- async *getLogs(opts: LogFilter): AsyncIterableIterator<Log_> {
357
+ async *getLogs(opts: LogFilter): AsyncIterableIterator<ChainLog> {
354
358
  let topics
355
359
  if (opts.topics?.length) {
356
360
  if (!opts.topics.every((topic) => typeof topic === 'string'))
@@ -587,7 +591,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
587
591
  }: {
588
592
  data: unknown
589
593
  topics?: readonly string[]
590
- }): CCIPMessage_V1_6_TON | undefined {
594
+ }): CCIPMessage_V1_6_EVM | undefined {
591
595
  if (!data || typeof data !== 'string') return
592
596
  if (topics?.length && topics[0] !== crc32('CCIPMessageSent')) return
593
597
 
@@ -660,7 +664,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
660
664
 
661
665
  // Load tokenAmounts from ref 3
662
666
  const _tokenAmountsCell = bodySlice.loadRef()
663
- const tokenAmounts: CCIPMessage_V1_6_TON['tokenAmounts'] = [] // TODO: FIXME: parse when implemented
667
+ const tokenAmounts: CCIPMessage_V1_6_EVM['tokenAmounts'] = [] // TODO: FIXME: parse when implemented
664
668
 
665
669
  // Load feeToken (inline address in body)
666
670
  const feeToken = bodySlice.loadMaybeAddress()?.toString() ?? ''
@@ -1099,11 +1103,6 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
1099
1103
  throw new CCIPTransactionNotFoundError(seqno.toString())
1100
1104
  }
1101
1105
 
1102
- /** {@inheritDoc Chain.getOffchainTokenData} */
1103
- getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
1104
- return Promise.resolve(request.message.tokenAmounts.map(() => undefined))
1105
- }
1106
-
1107
1106
  /**
1108
1107
  * {@inheritDoc Chain.generateUnsignedExecute}
1109
1108
  * @throws {@link CCIPExtraArgsInvalidError} if extra args are not EVMExtraArgsV2 format
@@ -1125,7 +1124,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
1125
1124
 
1126
1125
  const unsigned = generateUnsignedExecuteReport(
1127
1126
  offRamp,
1128
- input as ExecutionInput<CCIPMessage_V1_6_TON>,
1127
+ input as ExecutionInput<CCIPMessage_V1_6_EVM>,
1129
1128
  opts,
1130
1129
  )
1131
1130
 
@@ -1161,7 +1160,7 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
1161
1160
  ...unsigned,
1162
1161
  })
1163
1162
 
1164
- const message = opts.input.message as CCIPMessage_V1_6_TON
1163
+ const message = opts.input.message as CCIPMessage_V1_6_EVM
1165
1164
  for await (const exec of this.getExecutionReceipts({
1166
1165
  offRamp,
1167
1166
  messageId: message.messageId,
package/src/ton/types.ts CHANGED
@@ -2,13 +2,10 @@ import { type Builder, Address, Cell, beginCell } from '@ton/core'
2
2
  import { toBigInt } from 'ethers'
3
3
 
4
4
  import { CCIPDataFormatUnsupportedError } from '../errors/specialized.ts'
5
- import type { EVMExtraArgsV2 } from '../extra-args.ts'
5
+ import type { CCIPMessage_V1_6_EVM } from '../evm/messages.ts'
6
6
  import type { CCIPMessage_V1_6, ChainFamily, ExecutionInput } from '../types.ts'
7
7
  import { bytesToBuffer } from '../utils.ts'
8
8
 
9
- /** TON-specific CCIP v1.6 message type with EVMExtraArgsV2 (GenericExtraArgsV2) */
10
- export type CCIPMessage_V1_6_TON = CCIPMessage_V1_6 & EVMExtraArgsV2
11
-
12
9
  /** Opcode for OffRamp_ManuallyExecute message on TON */
13
10
  export const MANUALLY_EXECUTE_OPCODE = 0xa00785cf
14
11
 
@@ -83,7 +80,7 @@ function asSnakeData<T>(array: T[], builderFn: (item: T) => Builder): Cell {
83
80
  * @returns BOC-serialized Cell containing the execution report.
84
81
  */
85
82
  export function serializeExecutionReport(
86
- execReport: ExecutionInput<CCIPMessage_V1_6_TON>,
83
+ execReport: ExecutionInput<CCIPMessage_V1_6_EVM>,
87
84
  ): Builder {
88
85
  return beginCell()
89
86
  .storeUint(execReport.message.sourceChainSelector, 64)
@@ -97,7 +94,7 @@ export function serializeExecutionReport(
97
94
  .storeUint(execReport.proofFlagBits, 256)
98
95
  }
99
96
 
100
- function serializeMessage(message: CCIPMessage_V1_6_TON): Builder {
97
+ function serializeMessage(message: CCIPMessage_V1_6_EVM): Builder {
101
98
  return beginCell()
102
99
  .storeUint(BigInt(message.messageId), 256)
103
100
  .storeUint(message.sourceChainSelector, 64)
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { AbiParametersToPrimitiveTypes, ExtractAbiEvent } from 'abitype'
2
- import type { BytesLike, Log } from 'ethers'
2
+ import type { BytesLike, Log as EVMLog } from 'ethers'
3
+ import type { SetOptional } from 'type-fest'
3
4
 
4
5
  import type { APICCIPRequestMetadata } from './api/types.ts'
5
6
  import type OffRamp_1_6_ABI from './evm/abi/OffRamp_1_6.ts'
@@ -7,7 +8,6 @@ import type { CCIPMessage_EVM, CCIPMessage_V1_6_EVM, CCIPMessage_V2_0 } from './
7
8
  import type { ExtraArgs } from './extra-args.ts'
8
9
  import type { CCIPMessage_V1_6_Solana } from './solana/types.ts'
9
10
  import type { CCIPMessage_V1_6_Sui } from './sui/types.ts'
10
- import type { CCIPMessage_V1_6_TON } from './ton/types.ts'
11
11
  // v1.6 Base type from EVM contains the intersection of all other CCIPMessage v1.6 types
12
12
  export type { CCIPMessage_V1_6 } from './evm/messages.ts'
13
13
 
@@ -157,17 +157,20 @@ export interface Lane<V extends CCIPVersion = CCIPVersion> {
157
157
  export type CCIPMessage<V extends CCIPVersion = CCIPVersion> = V extends typeof CCIPVersion.V2_0
158
158
  ? CCIPMessage_V2_0
159
159
  : V extends typeof CCIPVersion.V1_6
160
- ? CCIPMessage_V1_6_EVM | CCIPMessage_V1_6_Solana | CCIPMessage_V1_6_Sui | CCIPMessage_V1_6_TON
160
+ ? CCIPMessage_V1_6_EVM | CCIPMessage_V1_6_Solana | CCIPMessage_V1_6_Sui
161
161
  : CCIPMessage_EVM<V>
162
162
 
163
163
  /**
164
164
  * Generic log structure compatible across chain families.
165
165
  */
166
- export type Log_ = Pick<Log, 'topics' | 'index' | 'address' | 'blockNumber' | 'transactionHash'> & {
166
+ export type ChainLog = Pick<
167
+ EVMLog,
168
+ 'topics' | 'index' | 'address' | 'blockNumber' | 'transactionHash'
169
+ > & {
167
170
  /** Log data as bytes or parsed object. */
168
171
  data: BytesLike | Record<string, unknown>
169
172
  /** Optional reference to the containing transaction. */
170
- tx?: ChainTransaction
173
+ tx?: SetOptional<ChainTransaction, 'logs'>
171
174
  }
172
175
 
173
176
  /**
@@ -188,7 +191,7 @@ export type ChainTransaction = {
188
191
  /** Transaction hash. */
189
192
  hash: string
190
193
  /** Logs emitted by this transaction. */
191
- logs: readonly Log_[]
194
+ logs: readonly ChainLog[]
192
195
  /** Block number containing this transaction. */
193
196
  blockNumber: number
194
197
  /** Unix timestamp of the block. */
@@ -206,9 +209,9 @@ export interface CCIPRequest<V extends CCIPVersion = CCIPVersion> {
206
209
  /** Lane configuration for this request. */
207
210
  lane: Lane<V>
208
211
  message: CCIPMessage<V>
209
- log: Log_
212
+ log: ChainLog
210
213
  /** Transaction that emitted the request. */
211
- tx: Pick<ChainTransaction, 'hash' | 'logs' | 'blockNumber' | 'timestamp' | 'from' | 'error'>
214
+ tx: Omit<ChainTransaction, 'logs'>
212
215
 
213
216
  /**
214
217
  * API-enriched metadata. Present only when fetched via CCIP API.
@@ -263,7 +266,7 @@ export type CCIPVerifications =
263
266
  /** The commit report data. */
264
267
  report: CommitReport
265
268
  /** Log event from the commit. */
266
- log: Log_
269
+ log: ChainLog
267
270
  }
268
271
  | {
269
272
  /** Policy for this request */
@@ -373,7 +376,7 @@ export interface CCIPExecution {
373
376
  /** Execution receipt data. */
374
377
  receipt: ExecutionReceipt
375
378
  /** Log event from the execution. */
376
- log: Log_
379
+ log: ChainLog
377
380
  /** Unix timestamp of the execution. */
378
381
  timestamp: number
379
382
  }