@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
@@ -198,7 +198,7 @@ async function buildLookupTableIxs(
198
198
  lookupTable: new AddressLookupTableAccount({
199
199
  key: altAddr,
200
200
  state: {
201
- deactivationSlot: 2n ** 64n - 1n,
201
+ deactivationSlot: BigInt(2) ** BigInt(64) - BigInt(1),
202
202
  lastExtendedSlot: recentSlot,
203
203
  lastExtendedSlotStartIndex: 0,
204
204
  addresses,
@@ -1118,9 +1118,10 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1118
1118
  payer,
1119
1119
  ...opts
1120
1120
  }: Parameters<Chain['generateUnsignedExecute']>[0]): Promise<UnsignedSolanaTx> {
1121
- if (!('input' in opts) || !('message' in opts.input) || !('computeUnits' in opts.input.message))
1121
+ const resolved = await this.resolveExecuteOpts(opts)
1122
+ if (!('message' in resolved.input) || !('computeUnits' in resolved.input.message))
1122
1123
  throw new CCIPExecutionReportChainMismatchError('Solana')
1123
- const { offRamp, input } = opts
1124
+ const { offRamp, input } = resolved
1124
1125
  const execReport_ = input as ExecutionInput<CCIPMessage_V1_6_Solana>
1125
1126
  return generateUnsignedExecuteReport(
1126
1127
  this,
@@ -1590,6 +1591,23 @@ export class SolanaChain extends Chain<typeof ChainFamily.Solana> {
1590
1591
  static override buildMessageForDest(
1591
1592
  message: Parameters<ChainStatic['buildMessageForDest']>[0],
1592
1593
  ): AnyMessage & { extraArgs: SVMExtraArgsV1 } {
1594
+ /** Valid field names for SVMExtraArgsV1, including recognised aliases. */
1595
+ const SVM_EXTRA_ARGS_FIELDS = new Set([
1596
+ 'computeUnits',
1597
+ 'gasLimit', // alias for computeUnits
1598
+ 'allowOutOfOrderExecution',
1599
+ 'tokenReceiver',
1600
+ 'accounts',
1601
+ 'accountIsWritableBitmap',
1602
+ ])
1603
+ if (message.extraArgs) {
1604
+ const unknown = Object.keys(message.extraArgs).filter((k) => !SVM_EXTRA_ARGS_FIELDS.has(k))
1605
+ if (unknown.length)
1606
+ throw new CCIPArgumentInvalidError(
1607
+ 'extraArgs',
1608
+ `unknown field(s) for SVMExtraArgsV1: ${unknown.map((k) => JSON.stringify(k)).join(', ')}`,
1609
+ )
1610
+ }
1593
1611
  if (
1594
1612
  !(
1595
1613
  message.extraArgs &&
@@ -0,0 +1,131 @@
1
+ import type { SuiClient } from '@mysten/sui/client'
2
+ import type { Keypair } from '@mysten/sui/cryptography'
3
+ import { Transaction } from '@mysten/sui/transactions'
4
+
5
+ import {
6
+ CCIPError,
7
+ CCIPErrorCode,
8
+ CCIPExecTxRevertedError,
9
+ CCIPExecutionReportChainMismatchError,
10
+ } from '../errors/index.ts'
11
+ import { type ExecutionInput, ChainFamily } from '../types.ts'
12
+ import { getCcipStateAddress } from './discovery.ts'
13
+ import {
14
+ type SuiManuallyExecuteInput,
15
+ type TokenConfig,
16
+ buildManualExecutionPTB,
17
+ } from './manuallyExec/index.ts'
18
+ import { fetchTokenConfigs, getObjectRef, getReceiverModule } from './objects.ts'
19
+ import type { CCIPMessage_V1_6_Sui, UnsignedSuiTx } from './types.ts'
20
+
21
+ /**
22
+ * Builds a Sui manual-execution PTB and returns it as an {@link UnsignedSuiTx}.
23
+ *
24
+ * @param client - Sui RPC client.
25
+ * @param offRamp - OffRamp object ID / address.
26
+ * @param input - Execution input (message + proofs).
27
+ * @param opts - Optional overrides such as `gasLimit` and `receiverObjectIds`.
28
+ * @returns Serialized unsigned transaction ready to sign and submit.
29
+ */
30
+ export async function generateUnsignedExecutePTB(
31
+ client: SuiClient,
32
+ offRamp: string,
33
+ input: ExecutionInput<CCIPMessage_V1_6_Sui>,
34
+ opts?: { gasLimit?: number | bigint; receiverObjectIds?: string[] },
35
+ ): Promise<UnsignedSuiTx> {
36
+ if (!('message' in input)) {
37
+ throw new CCIPExecutionReportChainMismatchError('Sui')
38
+ }
39
+
40
+ const ccip = await getCcipStateAddress(offRamp, client)
41
+
42
+ const ccipObjectRef = await getObjectRef(ccip, client)
43
+ const [offrampStateObject, receiverConfig] = await Promise.all([
44
+ getObjectRef(offRamp, client),
45
+ getReceiverModule(client, ccip, ccipObjectRef, input.message.receiver),
46
+ ])
47
+
48
+ let tokenConfigs: TokenConfig[] = []
49
+ if (input.message.tokenAmounts.length !== 0) {
50
+ tokenConfigs = await fetchTokenConfigs(client, ccip, ccipObjectRef, input.message.tokenAmounts)
51
+ }
52
+
53
+ const suiInput: SuiManuallyExecuteInput = {
54
+ executionReport: input,
55
+ offrampAddress: offRamp,
56
+ ccipAddress: ccip,
57
+ ccipObjectRef,
58
+ offrampStateObject,
59
+ receiverConfig,
60
+ tokenConfigs,
61
+ ...(opts?.receiverObjectIds ? { overrideReceiverObjectIds: opts.receiverObjectIds } : {}),
62
+ }
63
+
64
+ const tx = buildManualExecutionPTB(suiInput)
65
+
66
+ if (opts?.gasLimit) {
67
+ tx.setGasBudget(opts.gasLimit)
68
+ }
69
+
70
+ return {
71
+ family: ChainFamily.Sui,
72
+ transactions: [tx.serialize()],
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Signs and executes a pre-built {@link UnsignedSuiTx} using the provided keypair.
78
+ *
79
+ * @param client - Sui RPC client.
80
+ * @param wallet - Keypair used to sign the transaction.
81
+ * @param unsignedTx - The unsigned Sui transaction to execute.
82
+ * @param logger - Optional logger.
83
+ * @returns The finalized transaction digest string.
84
+ */
85
+ export async function signAndExecuteSuiTx(
86
+ client: SuiClient,
87
+ wallet: Keypair,
88
+ unsignedTx: UnsignedSuiTx,
89
+ logger?: { info: (...args: unknown[]) => void },
90
+ ): Promise<string> {
91
+ const tx = Transaction.from(unsignedTx.transactions[0])
92
+
93
+ logger?.info('Executing Sui CCIP execute transaction...')
94
+
95
+ let digest: string
96
+ try {
97
+ const result = await client.signAndExecuteTransaction({
98
+ signer: wallet,
99
+ transaction: tx,
100
+ options: {
101
+ showEffects: true,
102
+ showEvents: true,
103
+ },
104
+ })
105
+
106
+ if (result.effects?.status.status !== 'success') {
107
+ const errorMsg = result.effects?.status.error ?? 'Unknown error'
108
+ throw new CCIPExecTxRevertedError(result.digest, { context: { error: errorMsg } })
109
+ }
110
+
111
+ digest = result.digest
112
+ } catch (e) {
113
+ if (e instanceof CCIPExecTxRevertedError) throw e
114
+ throw new CCIPError(
115
+ CCIPErrorCode.TRANSACTION_NOT_FINALIZED,
116
+ `Failed to send Sui execute transaction: ${(e as Error).message}`,
117
+ )
118
+ }
119
+
120
+ logger?.info(`Waiting for Sui transaction ${digest} to be finalized...`)
121
+
122
+ await client.waitForTransaction({
123
+ digest,
124
+ options: {
125
+ showEffects: true,
126
+ showEvents: true,
127
+ },
128
+ })
129
+
130
+ return digest
131
+ }
package/src/sui/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { bcs } from '@mysten/sui/bcs'
2
- import { type SuiTransactionBlockResponse, SuiClient } from '@mysten/sui/client'
2
+ import { SuiClient } from '@mysten/sui/client'
3
3
  import type { Keypair } from '@mysten/sui/cryptography'
4
4
  import { SuiGraphQLClient } from '@mysten/sui/graphql'
5
5
  import { Transaction } from '@mysten/sui/transactions'
@@ -17,19 +17,13 @@ import {
17
17
  import { getCcipStateAddress, getOffRampForCcip } from './discovery.ts'
18
18
  import { type CommitEvent, streamSuiLogs } from './events.ts'
19
19
  import { getSuiLeafHasher } from './hasher.ts'
20
+ import { deriveObjectID, getLatestPackageId, getObjectRef } from './objects.ts'
20
21
  import {
21
- deriveObjectID,
22
- fetchTokenConfigs,
23
- getLatestPackageId,
24
- getObjectRef,
25
- getReceiverModule,
26
- } from './objects.ts'
27
- import {
22
+ CCIPArgumentInvalidError,
28
23
  CCIPContractNotRouterError,
29
24
  CCIPDataFormatUnsupportedError,
30
25
  CCIPError,
31
26
  CCIPErrorCode,
32
- CCIPExecTxRevertedError,
33
27
  CCIPExecutionReportChainMismatchError,
34
28
  CCIPLogsAddressRequiredError,
35
29
  CCIPNotImplementedError,
@@ -46,7 +40,6 @@ import {
46
40
  type CCIPExecution,
47
41
  type CCIPMessage,
48
42
  type CCIPRequest,
49
- type CCIPVersion,
50
43
  type ChainLog,
51
44
  type ChainTransaction,
52
45
  type CommitReport,
@@ -66,12 +59,9 @@ import {
66
59
  parseTypeAndVersion,
67
60
  util,
68
61
  } from '../utils.ts'
69
- import {
70
- type SuiManuallyExecuteInput,
71
- type TokenConfig,
72
- buildManualExecutionPTB,
73
- } from './manuallyExec/index.ts'
74
- import type { CCIPMessage_V1_6_Sui } from './types.ts'
62
+ import { generateUnsignedExecutePTB, signAndExecuteSuiTx } from './exec.ts'
63
+ import type { CCIPMessage_V1_6_Sui, UnsignedSuiTx } from './types.ts'
64
+ export type { UnsignedSuiTx }
75
65
 
76
66
  const DEFAULT_GAS_LIMIT = 1000000n
77
67
 
@@ -727,11 +717,28 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
727
717
  return Promise.reject(new CCIPNotImplementedError('SuiChain.sendMessage'))
728
718
  }
729
719
 
730
- /** {@inheritDoc Chain.generateUnsignedExecute} */
731
- override generateUnsignedExecute(
732
- _opts: Parameters<Chain['generateUnsignedExecute']>[0],
733
- ): Promise<never> {
734
- return Promise.reject(new CCIPNotImplementedError('SuiChain.generateUnsignedExecute'))
720
+ /**
721
+ * {@inheritDoc Chain.generateUnsignedExecute}
722
+ * @throws {@link CCIPExecutionReportChainMismatchError} if input is not a Sui v1.6 execution report
723
+ */
724
+ override async generateUnsignedExecute(
725
+ opts: Parameters<Chain['generateUnsignedExecute']>[0],
726
+ ): Promise<UnsignedSuiTx> {
727
+ const resolved = await this.resolveExecuteOpts(opts)
728
+ if (!resolved.offRamp.includes('::')) resolved.offRamp += '::offramp'
729
+ if (!('message' in resolved.input)) {
730
+ throw new CCIPExecutionReportChainMismatchError('Sui')
731
+ }
732
+
733
+ return generateUnsignedExecutePTB(
734
+ this.client,
735
+ resolved.offRamp,
736
+ resolved.input as ExecutionInput<CCIPMessage_V1_6_Sui>,
737
+ {
738
+ gasLimit: resolved.gasLimit,
739
+ receiverObjectIds: (resolved as { receiverObjectIds?: string[] }).receiverObjectIds,
740
+ },
741
+ )
735
742
  }
736
743
 
737
744
  /**
@@ -744,94 +751,23 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
744
751
  receiverObjectIds?: string[]
745
752
  },
746
753
  ): Promise<CCIPExecution> {
747
- if (!('input' in opts && 'message' in opts.input)) {
748
- throw new CCIPExecutionReportChainMismatchError('Sui')
749
- }
750
- const { input, offRamp } = opts
751
754
  const wallet = opts.wallet as Keypair
752
755
 
753
- // Discover the CCIP package from the offramp
754
- const ccip = await getCcipStateAddress(offRamp, this.client)
755
-
756
- const ccipObjectRef = await getObjectRef(ccip, this.client)
757
- const offrampStateObject = await getObjectRef(offRamp, this.client)
758
- const receiverConfig = await getReceiverModule(
759
- this.client,
760
- ccip,
761
- ccipObjectRef,
762
- input.message.receiver,
763
- )
764
- let tokenConfigs: TokenConfig[] = []
765
- if (input.message.tokenAmounts.length !== 0) {
766
- tokenConfigs = await fetchTokenConfigs(
767
- this.client,
768
- ccip,
769
- ccipObjectRef,
770
- input.message.tokenAmounts as CCIPMessage<typeof CCIPVersion.V1_6>['tokenAmounts'],
771
- )
772
- }
773
-
774
- const suiInput: SuiManuallyExecuteInput = {
775
- executionReport: input as ExecutionInput<CCIPMessage_V1_6_Sui>,
776
- offrampAddress: offRamp,
777
- ccipAddress: ccip,
778
- ccipObjectRef,
779
- offrampStateObject,
780
- receiverConfig,
781
- tokenConfigs,
782
- }
783
756
  if (opts.receiverObjectIds) {
784
757
  this.logger.info(
785
758
  `Overriding Sui Manual Execution receiverObjectIds with: ${opts.receiverObjectIds.join(', ')}`,
786
759
  )
787
- suiInput.overrideReceiverObjectIds = opts.receiverObjectIds
788
- }
789
- const tx = buildManualExecutionPTB(suiInput)
790
-
791
- // Set gas budget if provided
792
- if (opts.gasLimit) {
793
- tx.setGasBudget(opts.gasLimit)
794
- }
795
-
796
- this.logger.info(`Executing Sui CCIP execute transaction...`)
797
- // Sign and execute the transaction
798
- let result: SuiTransactionBlockResponse
799
- try {
800
- result = await this.client.signAndExecuteTransaction({
801
- signer: wallet,
802
- transaction: tx,
803
- options: {
804
- showEffects: true,
805
- showEvents: true,
806
- },
807
- })
808
- } catch (e) {
809
- throw new CCIPError(
810
- CCIPErrorCode.TRANSACTION_NOT_FINALIZED,
811
- `Failed to send Sui execute transaction: ${(e as Error).message}`,
812
- )
813
760
  }
814
761
 
815
- // Check if transaction inmediately reverted
816
- if (result.effects?.status.status !== 'success') {
817
- const errorMsg = result.effects?.status.error || 'Unknown error'
818
- throw new CCIPExecTxRevertedError(result.digest, {
819
- context: { error: errorMsg },
820
- })
821
- }
822
-
823
- this.logger.info(`Waiting for Sui transaction ${result.digest} to be finalized...`)
824
-
825
- await this.client.waitForTransaction({
826
- digest: result.digest,
827
- options: {
828
- showEffects: true,
829
- showEvents: true,
830
- },
762
+ const unsignedTx = await this.generateUnsignedExecute({
763
+ ...opts,
764
+ payer: '',
831
765
  })
832
766
 
767
+ const digest = await signAndExecuteSuiTx(this.client, wallet, unsignedTx, this.logger)
768
+
833
769
  // Return the transaction as a ChainTransaction
834
- return this.getExecutionReceiptInTx(await this.getTransaction(result.digest))
770
+ return this.getExecutionReceiptInTx(await this.getTransaction(digest))
835
771
  }
836
772
 
837
773
  /**
@@ -881,6 +817,22 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
881
817
  static override buildMessageForDest(
882
818
  message: Parameters<ChainStatic['buildMessageForDest']>[0],
883
819
  ): AnyMessage & { extraArgs: SuiExtraArgsV1 } {
820
+ /** Valid field names for SuiExtraArgsV1, including recognised aliases. */
821
+ const SUI_EXTRA_ARGS_FIELDS = new Set([
822
+ 'gasLimit',
823
+ 'allowOutOfOrderExecution',
824
+ 'tokenReceiver',
825
+ 'receiverObjectIds',
826
+ 'accounts', // alias for receiverObjectIds
827
+ ])
828
+ if (message.extraArgs) {
829
+ const unknown = Object.keys(message.extraArgs).filter((k) => !SUI_EXTRA_ARGS_FIELDS.has(k))
830
+ if (unknown.length)
831
+ throw new CCIPArgumentInvalidError(
832
+ 'extraArgs',
833
+ `unknown field(s) for SuiExtraArgsV1: ${unknown.map((k) => JSON.stringify(k)).join(', ')}`,
834
+ )
835
+ }
884
836
  const gasLimit =
885
837
  message.extraArgs && 'gasLimit' in message.extraArgs && message.extraArgs.gasLimit != null
886
838
  ? message.extraArgs.gasLimit
@@ -4,9 +4,7 @@ import { Transaction } from '@mysten/sui/transactions'
4
4
 
5
5
  import { serializeExecutionReport } from './encoder.ts'
6
6
  import { CCIPMessageInvalidError } from '../../errors/specialized.ts'
7
- import { decodeExtraArgs } from '../../extra-args.ts'
8
7
  import type { ExecutionInput } from '../../types.ts'
9
- import { networkInfo } from '../../utils.ts'
10
8
  import type { CCIPMessage_V1_6_Sui } from '../types.ts'
11
9
 
12
10
  /** Configuration for manually executing a Sui receiver module. */
@@ -56,12 +54,16 @@ export function buildManualExecutionPTB({
56
54
  }: SuiManuallyExecuteInput): Transaction {
57
55
  const reportBytes = serializeExecutionReport(executionReport)
58
56
 
57
+ // Strip any ::module suffixes to get bare package IDs for move call targets
58
+ const offrampPackageId = offrampAddress.split('::')[0]!
59
+ const ccipPackageId = ccipAddress.split('::')[0]!
60
+
59
61
  // Create transaction
60
62
  const tx = new Transaction()
61
63
 
62
64
  // Step 1: Call manually_init_execute to prepare the execution
63
65
  const receiverParamsArg = tx.moveCall({
64
- target: `${offrampAddress}::offramp::manually_init_execute`,
66
+ target: `${offrampPackageId}::offramp::manually_init_execute`,
65
67
  arguments: [
66
68
  tx.object(ccipObjectRef),
67
69
  tx.object(offrampStateObject),
@@ -72,7 +74,7 @@ export function buildManualExecutionPTB({
72
74
 
73
75
  // Get the message from the from the report using the offramp helper
74
76
  const messageArg = tx.moveCall({
75
- target: `${ccipAddress}::offramp_state_helper::extract_any2sui_message`,
77
+ target: `${ccipPackageId}::offramp_state_helper::extract_any2sui_message`,
76
78
  arguments: [receiverParamsArg],
77
79
  })
78
80
 
@@ -96,17 +98,9 @@ export function buildManualExecutionPTB({
96
98
  }
97
99
  }
98
100
 
99
- // Decode extraArgs to get receiverObjectIds
100
- const decodedExtraArgs = decodeExtraArgs(
101
- executionReport.message.extraArgs,
102
- networkInfo(executionReport.message.destChainSelector).family,
103
- )
104
-
105
- if (!decodedExtraArgs || decodedExtraArgs._tag !== 'SuiExtraArgsV1') {
106
- throw new CCIPMessageInvalidError('Expected Sui extra args')
107
- }
101
+ const { receiverObjectIds } = executionReport.message
108
102
 
109
- if (decodedExtraArgs.receiverObjectIds.length === 0) {
103
+ if (receiverObjectIds.length === 0) {
110
104
  throw new CCIPMessageInvalidError('No receiverObjectIds provided in SUIExtraArgsV1')
111
105
  }
112
106
  // Call the receiver contract
@@ -116,16 +110,16 @@ export function buildManualExecutionPTB({
116
110
  tx.pure.vector('u8', Buffer.from(executionReport.message.messageId.slice(2), 'hex')),
117
111
  tx.object(ccipObjectRef),
118
112
  messageArg,
119
- // if overrideReceiverObjectIds is provided, use them; otherwise, use the ones from decodedExtraArgs (original message)
113
+ // if overrideReceiverObjectIds is provided, use them; otherwise, use the ones from the message
120
114
  ...(overrideReceiverObjectIds && overrideReceiverObjectIds.length > 0
121
115
  ? overrideReceiverObjectIds.map(tx.object)
122
- : decodedExtraArgs.receiverObjectIds.map(tx.object)),
116
+ : receiverObjectIds.map(tx.object)),
123
117
  ],
124
118
  })
125
119
 
126
120
  // Step 2: Call finish_execute to complete the execution
127
121
  tx.moveCall({
128
- target: `${offrampAddress}::offramp::finish_execute`,
122
+ target: `${offrampPackageId}::offramp::finish_execute`,
129
123
  arguments: [
130
124
  tx.object(ccipObjectRef),
131
125
  tx.object(offrampStateObject),
@@ -135,11 +135,12 @@ export async function getReceiverModule(
135
135
  ccipObjectRef: string,
136
136
  receiverPackageId: string,
137
137
  ) {
138
+ const ccipBarePackageId = ccipPackageId.split('::')[0]!
138
139
  // Call get_receiver_config from receiver_registry contract
139
140
  const tx = new Transaction()
140
141
 
141
142
  tx.moveCall({
142
- target: `${ccipPackageId}::receiver_registry::get_receiver_config`,
143
+ target: `${ccipBarePackageId}::receiver_registry::get_receiver_config`,
143
144
  arguments: [tx.object(ccipObjectRef), tx.pure.address(receiverPackageId)],
144
145
  })
145
146
 
@@ -207,12 +208,13 @@ export async function fetchTokenConfigs(
207
208
  ]
208
209
 
209
210
  // Fetch token config for each unique token address
211
+ const ccipBarePackageId = ccipPackageId.split('::')[0]!
210
212
  for (const tokenAddress of tokenAddresses) {
211
213
  const tx = new Transaction()
212
214
 
213
215
  // Call get_token_config_struct from token_admin_registry
214
216
  tx.moveCall({
215
- target: `${ccipPackageId}::token_admin_registry::get_token_config_struct`,
217
+ target: `${ccipBarePackageId}::token_admin_registry::get_token_config_struct`,
216
218
  arguments: [tx.object(ccipObjectRef), tx.pure.address(tokenAddress)],
217
219
  })
218
220
 
package/src/sui/types.ts CHANGED
@@ -2,12 +2,21 @@ import { bcs } from '@mysten/sui/bcs'
2
2
  import { concat } from 'ethers'
3
3
 
4
4
  import { type SuiExtraArgsV1, SuiExtraArgsV1Tag } from '../extra-args.ts'
5
- import type { CCIPMessage_V1_6 } from '../types.ts'
5
+ import type { CCIPMessage_V1_6, ChainFamily } from '../types.ts'
6
6
  import { getAddressBytes, getDataBytes } from '../utils.ts'
7
7
 
8
8
  /** Sui-specific CCIP v1.6 message type with Sui extra args. */
9
9
  export type CCIPMessage_V1_6_Sui = CCIPMessage_V1_6 & SuiExtraArgsV1
10
10
 
11
+ /**
12
+ * Unsigned Sui transaction, serialized via Transaction#serialize().
13
+ * Reconstruct with Transaction.from(transactions[0]).
14
+ */
15
+ export type UnsignedSuiTx = {
16
+ family: typeof ChainFamily.Sui
17
+ transactions: [string]
18
+ }
19
+
11
20
  export const SuiExtraArgsV1Codec = bcs.struct('SuiExtraArgsV1', {
12
21
  gasLimit: bcs.u64(),
13
22
  allowOutOfOrderExecution: bcs.bool(),
package/src/ton/index.ts CHANGED
@@ -319,7 +319,11 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
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 {