@chainlink/ccip-sdk 0.94.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.
- package/README.md +2 -2
- package/dist/all-chains.d.ts +23 -0
- package/dist/all-chains.d.ts.map +1 -0
- package/dist/all-chains.js +24 -0
- package/dist/all-chains.js.map +1 -0
- package/dist/api/index.d.ts +86 -7
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +270 -10
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +134 -13
- package/dist/api/types.d.ts.map +1 -1
- package/dist/aptos/index.d.ts +38 -17
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +91 -61
- package/dist/aptos/index.js.map +1 -1
- package/dist/aptos/logs.js +3 -3
- package/dist/aptos/logs.js.map +1 -1
- package/dist/chain.d.ts +300 -42
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +160 -9
- package/dist/chain.js.map +1 -1
- package/dist/errors/codes.d.ts +9 -3
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +10 -3
- package/dist/errors/codes.js.map +1 -1
- package/dist/errors/index.d.ts +8 -8
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +8 -8
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/recovery.d.ts.map +1 -1
- package/dist/errors/recovery.js +10 -4
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +62 -21
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +128 -41
- package/dist/errors/specialized.js.map +1 -1
- package/dist/evm/extra-args.d.ts +25 -0
- package/dist/evm/extra-args.d.ts.map +1 -0
- package/dist/evm/extra-args.js +328 -0
- package/dist/evm/extra-args.js.map +1 -0
- package/dist/evm/gas.d.ts +14 -0
- package/dist/evm/gas.d.ts.map +1 -0
- package/dist/evm/gas.js +92 -0
- package/dist/evm/gas.js.map +1 -0
- package/dist/evm/index.d.ts +76 -32
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +94 -104
- package/dist/evm/index.js.map +1 -1
- package/dist/evm/offchain.d.ts.map +1 -1
- package/dist/evm/offchain.js +8 -8
- package/dist/evm/offchain.js.map +1 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +24 -3
- package/dist/execution.js.map +1 -1
- package/dist/extra-args.d.ts +103 -4
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +28 -3
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts +46 -19
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +56 -68
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +18 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/dist/offchain.d.ts +5 -4
- package/dist/offchain.d.ts.map +1 -1
- package/dist/offchain.js +7 -6
- package/dist/offchain.js.map +1 -1
- package/dist/requests.d.ts +30 -20
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +86 -56
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts +2 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +625 -278
- package/dist/selectors.js.map +1 -1
- package/dist/solana/exec.d.ts.map +1 -1
- package/dist/solana/exec.js +2 -1
- package/dist/solana/exec.js.map +1 -1
- package/dist/solana/index.d.ts +73 -22
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +91 -28
- package/dist/solana/index.js.map +1 -1
- package/dist/solana/offchain.js +2 -2
- package/dist/solana/offchain.js.map +1 -1
- package/dist/solana/send.d.ts.map +1 -1
- package/dist/solana/send.js +6 -9
- package/dist/solana/send.js.map +1 -1
- package/dist/solana/utils.d.ts +29 -1
- package/dist/solana/utils.d.ts.map +1 -1
- package/dist/solana/utils.js +39 -1
- package/dist/solana/utils.js.map +1 -1
- package/dist/sui/discovery.d.ts +7 -4
- package/dist/sui/discovery.d.ts.map +1 -1
- package/dist/sui/discovery.js +66 -19
- package/dist/sui/discovery.js.map +1 -1
- package/dist/sui/events.d.ts +23 -12
- package/dist/sui/events.d.ts.map +1 -1
- package/dist/sui/events.js +267 -128
- package/dist/sui/events.js.map +1 -1
- package/dist/sui/index.d.ts +57 -41
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +286 -159
- package/dist/sui/index.js.map +1 -1
- package/dist/sui/objects.d.ts +14 -4
- package/dist/sui/objects.d.ts.map +1 -1
- package/dist/sui/objects.js +61 -68
- package/dist/sui/objects.js.map +1 -1
- package/dist/sui/types.d.ts +33 -0
- package/dist/sui/types.d.ts.map +1 -1
- package/dist/sui/types.js.map +1 -1
- package/dist/ton/index.d.ts +67 -21
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +159 -30
- package/dist/ton/index.js.map +1 -1
- package/dist/ton/send.d.ts +52 -0
- package/dist/ton/send.d.ts.map +1 -0
- package/dist/ton/send.js +166 -0
- package/dist/ton/send.js.map +1 -0
- package/dist/ton/utils.d.ts +3 -3
- package/dist/ton/utils.d.ts.map +1 -1
- package/dist/ton/utils.js +6 -5
- package/dist/ton/utils.js.map +1 -1
- package/dist/types.d.ts +126 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +19 -5
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +67 -4
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +126 -17
- package/dist/utils.js.map +1 -1
- package/package.json +14 -9
- package/src/all-chains.ts +26 -0
- package/src/api/index.ts +348 -13
- package/src/api/types.ts +160 -13
- package/src/aptos/index.ts +98 -76
- package/src/aptos/logs.ts +3 -3
- package/src/chain.ts +408 -51
- package/src/errors/codes.ts +10 -3
- package/src/errors/index.ts +8 -5
- package/src/errors/recovery.ts +18 -5
- package/src/errors/specialized.ts +168 -49
- package/src/evm/extra-args.ts +377 -0
- package/src/evm/gas.ts +150 -0
- package/src/evm/index.ts +123 -155
- package/src/evm/offchain.ts +15 -9
- package/src/execution.ts +26 -3
- package/src/extra-args.ts +108 -4
- package/src/gas.ts +101 -115
- package/src/index.ts +27 -14
- package/src/offchain.ts +12 -6
- package/src/requests.ts +117 -67
- package/src/selectors.ts +632 -280
- package/src/solana/exec.ts +3 -1
- package/src/solana/index.ts +97 -37
- package/src/solana/offchain.ts +2 -2
- package/src/solana/send.ts +5 -23
- package/src/solana/utils.ts +66 -0
- package/src/sui/discovery.ts +92 -31
- package/src/sui/events.ts +346 -239
- package/src/sui/index.ts +365 -212
- package/src/sui/objects.ts +74 -98
- package/src/sui/types.ts +35 -0
- package/src/ton/index.ts +199 -35
- package/src/ton/send.ts +222 -0
- package/src/ton/utils.ts +7 -6
- package/src/types.ts +128 -9
- package/src/utils.ts +169 -21
package/src/sui/index.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { bcs } from '@mysten/sui/bcs'
|
|
3
2
|
import { type SuiTransactionBlockResponse, SuiClient } from '@mysten/sui/client'
|
|
4
3
|
import type { Keypair } from '@mysten/sui/cryptography'
|
|
5
4
|
import { SuiGraphQLClient } from '@mysten/sui/graphql'
|
|
6
5
|
import { Transaction } from '@mysten/sui/transactions'
|
|
7
|
-
import {
|
|
8
|
-
import type
|
|
6
|
+
import { isValidSuiAddress, isValidTransactionDigest, normalizeSuiAddress } from '@mysten/sui/utils'
|
|
7
|
+
import { type BytesLike, dataLength, hexlify, isBytesLike, isHexString } from 'ethers'
|
|
8
|
+
import type { PickDeep, SetOptional } from 'type-fest'
|
|
9
9
|
|
|
10
10
|
import { AptosChain } from '../aptos/index.ts'
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type ChainContext,
|
|
13
|
+
type ChainStatic,
|
|
14
|
+
type GetBalanceOpts,
|
|
15
|
+
type LogFilter,
|
|
16
|
+
Chain,
|
|
17
|
+
} from '../chain.ts'
|
|
12
18
|
import {
|
|
13
19
|
CCIPContractNotRouterError,
|
|
14
20
|
CCIPDataFormatUnsupportedError,
|
|
@@ -16,13 +22,17 @@ import {
|
|
|
16
22
|
CCIPErrorCode,
|
|
17
23
|
CCIPExecTxRevertedError,
|
|
18
24
|
CCIPNotImplementedError,
|
|
19
|
-
CCIPSuiMessageVersionInvalidError,
|
|
20
|
-
CCIPVersionFeatureUnavailableError,
|
|
21
25
|
} from '../errors/index.ts'
|
|
26
|
+
import {
|
|
27
|
+
CCIPLogsAddressRequiredError,
|
|
28
|
+
CCIPSuiLogInvalidError,
|
|
29
|
+
CCIPTopicsInvalidError,
|
|
30
|
+
} from '../errors/specialized.ts'
|
|
22
31
|
import type { EVMExtraArgsV2, ExtraArgs, SVMExtraArgsV1, SuiExtraArgsV1 } from '../extra-args.ts'
|
|
23
|
-
import { getSuiLeafHasher } from './hasher.ts'
|
|
24
32
|
import type { LeafHasher } from '../hasher/common.ts'
|
|
33
|
+
import { decodeMessage, getMessagesInBatch } from '../requests.ts'
|
|
25
34
|
import { supportedChains } from '../supported-chains.ts'
|
|
35
|
+
import { getSuiLeafHasher } from './hasher.ts'
|
|
26
36
|
import {
|
|
27
37
|
type AnyMessage,
|
|
28
38
|
type CCIPExecution,
|
|
@@ -41,32 +51,32 @@ import {
|
|
|
41
51
|
type WithLogger,
|
|
42
52
|
ChainFamily,
|
|
43
53
|
} from '../types.ts'
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
import {
|
|
55
|
+
decodeAddress,
|
|
56
|
+
decodeOnRampAddress,
|
|
57
|
+
getDataBytes,
|
|
58
|
+
networkInfo,
|
|
59
|
+
parseTypeAndVersion,
|
|
60
|
+
util,
|
|
61
|
+
} from '../utils.ts'
|
|
62
|
+
import { getCcipStateAddress, getOffRampForCcip } from './discovery.ts'
|
|
63
|
+
import { type CommitEvent, streamSuiLogs } from './events.ts'
|
|
48
64
|
import {
|
|
49
65
|
type SuiManuallyExecuteInput,
|
|
50
66
|
type TokenConfig,
|
|
51
67
|
buildManualExecutionPTB,
|
|
52
68
|
} from './manuallyExec/index.ts'
|
|
53
69
|
import {
|
|
70
|
+
deriveObjectID,
|
|
54
71
|
fetchTokenConfigs,
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
getLatestPackageId,
|
|
73
|
+
getObjectRef,
|
|
57
74
|
getReceiverModule,
|
|
58
75
|
} from './objects.ts'
|
|
76
|
+
import type { CCIPMessage_V1_6_Sui } from './types.ts'
|
|
59
77
|
|
|
60
|
-
export const SUI_EXTRA_ARGS_V1_TAG = '21ea4ca9' as const
|
|
61
78
|
const DEFAULT_GAS_LIMIT = 1000000n
|
|
62
79
|
|
|
63
|
-
type SuiContractDir = {
|
|
64
|
-
ccip?: string
|
|
65
|
-
onRamp?: string
|
|
66
|
-
offRamp?: string
|
|
67
|
-
router?: string
|
|
68
|
-
}
|
|
69
|
-
|
|
70
80
|
/**
|
|
71
81
|
* Sui chain implementation supporting Sui networks.
|
|
72
82
|
* Note: This implementation is currently a placeholder.
|
|
@@ -82,9 +92,6 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
82
92
|
readonly client: SuiClient
|
|
83
93
|
readonly graphqlClient: SuiGraphQLClient
|
|
84
94
|
|
|
85
|
-
// contracts dir <chainSelectorName, SuiContractDir>
|
|
86
|
-
readonly contractsDir: SuiContractDir
|
|
87
|
-
|
|
88
95
|
/**
|
|
89
96
|
* Creates a new SuiChain instance.
|
|
90
97
|
* @param client - Sui client for interacting with the Sui network.
|
|
@@ -95,7 +102,6 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
95
102
|
|
|
96
103
|
this.client = client
|
|
97
104
|
this.network = network
|
|
98
|
-
this.contractsDir = {}
|
|
99
105
|
|
|
100
106
|
// TODO: Graphql client should come from config
|
|
101
107
|
let graphqlUrl: string
|
|
@@ -119,6 +125,8 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
119
125
|
* Creates a SuiChain instance from an RPC URL.
|
|
120
126
|
* @param url - HTTP or WebSocket endpoint URL for the Sui network.
|
|
121
127
|
* @returns A new SuiChain instance.
|
|
128
|
+
* @throws {@link CCIPDataFormatUnsupportedError} if unable to fetch chain identifier
|
|
129
|
+
* @throws {@link CCIPError} if chain identifier is not supported
|
|
122
130
|
*/
|
|
123
131
|
static async fromUrl(url: string, ctx?: ChainContext): Promise<SuiChain> {
|
|
124
132
|
const client = new SuiClient({ url })
|
|
@@ -140,17 +148,19 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
140
148
|
chainId = 'sui:4' // devnet
|
|
141
149
|
} else {
|
|
142
150
|
throw new CCIPError(
|
|
143
|
-
CCIPErrorCode.
|
|
151
|
+
CCIPErrorCode.CHAIN_FAMILY_UNSUPPORTED,
|
|
144
152
|
`Unsupported Sui chain identifier: ${rawChainId}`,
|
|
145
153
|
)
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
const network = networkInfo(chainId) as NetworkInfo<typeof ChainFamily.Sui>
|
|
149
|
-
|
|
157
|
+
const chain = new SuiChain(client, network, ctx)
|
|
158
|
+
return Object.assign(chain, { url })
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
/** {@inheritDoc Chain.getBlockTimestamp} */
|
|
153
|
-
async getBlockTimestamp(block: number): Promise<number> {
|
|
162
|
+
async getBlockTimestamp(block: number | 'finalized'): Promise<number> {
|
|
163
|
+
if (typeof block !== 'number' || block <= 0) return Math.floor(Date.now() / 1000)
|
|
154
164
|
const checkpoint = await this.client.getCheckpoint({
|
|
155
165
|
id: String(block),
|
|
156
166
|
})
|
|
@@ -176,12 +186,12 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
176
186
|
if (txResponse.events?.length) {
|
|
177
187
|
for (const [i, event] of txResponse.events.entries()) {
|
|
178
188
|
const eventType = event.type
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const eventName = eventType.
|
|
189
|
+
const splitIdx = eventType.lastIndexOf('::')
|
|
190
|
+
const address = eventType.substring(0, splitIdx)
|
|
191
|
+
const eventName = eventType.substring(splitIdx + 2)
|
|
182
192
|
|
|
183
193
|
events.push({
|
|
184
|
-
address:
|
|
194
|
+
address: address,
|
|
185
195
|
transactionHash: digest,
|
|
186
196
|
index: i,
|
|
187
197
|
blockNumber: Number(txResponse.checkpoint || 0),
|
|
@@ -200,43 +210,27 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
200
210
|
}
|
|
201
211
|
}
|
|
202
212
|
|
|
203
|
-
/**
|
|
213
|
+
/**
|
|
214
|
+
* {@inheritDoc Chain.getLogs}
|
|
215
|
+
* @throws {@link CCIPLogsAddressRequiredError} if address is not provided
|
|
216
|
+
* @throws {@link CCIPTopicsInvalidError} if topics format is invalid
|
|
217
|
+
*/
|
|
204
218
|
async *getLogs(opts: LogFilter & { versionAsHash?: boolean }) {
|
|
205
|
-
if (!
|
|
206
|
-
|
|
207
|
-
}
|
|
219
|
+
if (!opts.address) throw new CCIPLogsAddressRequiredError()
|
|
220
|
+
|
|
208
221
|
// Extract the event type from topics
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
throw new CCIPVersionFeatureUnavailableError(
|
|
212
|
-
'Event type',
|
|
213
|
-
topic || 'unknown',
|
|
214
|
-
'CommitReportAccepted',
|
|
215
|
-
)
|
|
222
|
+
if (opts.topics?.length !== 1 || typeof opts.topics[0] !== 'string') {
|
|
223
|
+
throw new CCIPTopicsInvalidError(opts.topics!)
|
|
216
224
|
}
|
|
225
|
+
const topic = opts.topics[0]
|
|
217
226
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
: new Date(startTime.getTime() + 1 * 24 * 60 * 60 * 1000) // default to +24h
|
|
222
|
-
|
|
223
|
-
this.logger.info(
|
|
224
|
-
`Fetching Sui events of type ${topic} from ${startTime.toISOString()} to ${endTime.toISOString()}`,
|
|
225
|
-
)
|
|
226
|
-
const events = await getSuiEventsInTimeRange<CommitEvent>(
|
|
227
|
-
this.client,
|
|
228
|
-
this.graphqlClient,
|
|
229
|
-
`${this.contractsDir.offRamp}::offramp::CommitReportAccepted`,
|
|
230
|
-
startTime,
|
|
231
|
-
endTime,
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
for (const event of events) {
|
|
235
|
-
const eventData = event.contents.json
|
|
227
|
+
for await (const event of streamSuiLogs<Record<string, unknown>>(this, opts)) {
|
|
228
|
+
const eventData = event.contents?.json
|
|
229
|
+
if (!eventData) continue
|
|
236
230
|
yield {
|
|
237
|
-
address:
|
|
238
|
-
transactionHash: event.transaction
|
|
239
|
-
index:
|
|
231
|
+
address: opts.address,
|
|
232
|
+
transactionHash: event.transaction!.digest,
|
|
233
|
+
index: Number(event.sequenceNumber) || 0,
|
|
240
234
|
blockNumber: Number(event.transaction?.effects.checkpoint.sequenceNumber || 0),
|
|
241
235
|
data: eventData,
|
|
242
236
|
topics: [topic],
|
|
@@ -244,11 +238,6 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
244
238
|
}
|
|
245
239
|
}
|
|
246
240
|
|
|
247
|
-
/** {@inheritDoc Chain.getMessagesInTx} */
|
|
248
|
-
override async getMessagesInTx(_tx: string | ChainTransaction): Promise<CCIPRequest[]> {
|
|
249
|
-
return Promise.reject(new CCIPNotImplementedError('SuiChain.getMessagesInTx'))
|
|
250
|
-
}
|
|
251
|
-
|
|
252
241
|
/** {@inheritDoc Chain.getMessagesInBatch} */
|
|
253
242
|
override async getMessagesInBatch<
|
|
254
243
|
R extends PickDeep<
|
|
@@ -256,67 +245,96 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
256
245
|
'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
|
|
257
246
|
>,
|
|
258
247
|
>(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
248
|
+
request: R,
|
|
249
|
+
commit: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
|
|
250
|
+
opts?: { page?: number },
|
|
262
251
|
): Promise<R['message'][]> {
|
|
263
|
-
return
|
|
252
|
+
return getMessagesInBatch(this, request, commit, opts)
|
|
264
253
|
}
|
|
265
254
|
|
|
266
|
-
/**
|
|
267
|
-
|
|
268
|
-
|
|
255
|
+
/**
|
|
256
|
+
* {@inheritDoc Chain.typeAndVersion}
|
|
257
|
+
* @throws {@link CCIPDataFormatUnsupportedError} if view call fails
|
|
258
|
+
*/
|
|
259
|
+
async typeAndVersion(address: string) {
|
|
260
|
+
// requires address to have `::<module>` suffix
|
|
261
|
+
address = await getLatestPackageId(address, this.client)
|
|
262
|
+
const target = `${address}::type_and_version`
|
|
263
|
+
|
|
264
|
+
// Use the Transaction builder to create a move call
|
|
265
|
+
const tx = new Transaction()
|
|
266
|
+
// Add move call to the transaction
|
|
267
|
+
tx.moveCall({ target, arguments: [] })
|
|
268
|
+
|
|
269
|
+
// Execute with devInspectTransactionBlock for read-only call
|
|
270
|
+
const result = await this.client.devInspectTransactionBlock({
|
|
271
|
+
sender: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
272
|
+
transactionBlock: tx,
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
if (result.effects.status.status !== 'success' || !result.results?.[0]?.returnValues?.[0]) {
|
|
276
|
+
throw new CCIPDataFormatUnsupportedError(
|
|
277
|
+
`Failed to call ${target}: ${result.effects.status.error || 'No return value'}`,
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const [data] = result.results[0].returnValues[0]
|
|
282
|
+
const res = bcs.String.parse(getDataBytes(data))
|
|
283
|
+
return parseTypeAndVersion(res)
|
|
269
284
|
}
|
|
270
285
|
|
|
271
286
|
/** {@inheritDoc Chain.getRouterForOnRamp} */
|
|
272
287
|
async getRouterForOnRamp(onRamp: string, _destChainSelector: bigint): Promise<string> {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
this.contractsDir.onRamp = onRamp
|
|
276
|
-
}
|
|
277
|
-
return Promise.resolve(this.contractsDir.onRamp)
|
|
288
|
+
// In Sui, the router is the onRamp package itself
|
|
289
|
+
return Promise.resolve(onRamp)
|
|
278
290
|
}
|
|
279
291
|
|
|
280
|
-
/**
|
|
292
|
+
/**
|
|
293
|
+
* {@inheritDoc Chain.getRouterForOffRamp}
|
|
294
|
+
* @throws {@link CCIPContractNotRouterError} always (Sui architecture doesn't have separate router)
|
|
295
|
+
*/
|
|
281
296
|
getRouterForOffRamp(offRamp: string, _sourceChainSelector: bigint): Promise<string> {
|
|
282
297
|
throw new CCIPContractNotRouterError(offRamp, 'unknown')
|
|
283
298
|
}
|
|
284
299
|
|
|
285
300
|
/** {@inheritDoc Chain.getNativeTokenForRouter} */
|
|
286
|
-
getNativeTokenForRouter(
|
|
301
|
+
getNativeTokenForRouter(): Promise<string> {
|
|
287
302
|
// SUI native token is always 0x2::sui::SUI
|
|
288
303
|
return Promise.resolve('0x2::sui::SUI')
|
|
289
304
|
}
|
|
290
305
|
|
|
291
306
|
/** {@inheritDoc Chain.getOffRampsForRouter} */
|
|
292
307
|
async getOffRampsForRouter(router: string, _sourceChainSelector: bigint): Promise<string[]> {
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
this.contractsDir.ccip = ccip
|
|
308
|
+
router = await getLatestPackageId(router, this.client)
|
|
309
|
+
const ccip = await getCcipStateAddress(router, this.client)
|
|
310
|
+
const offramp = await getOffRampForCcip(ccip, this.client)
|
|
297
311
|
return [offramp]
|
|
298
312
|
}
|
|
299
313
|
|
|
300
314
|
/** {@inheritDoc Chain.getOnRampForRouter} */
|
|
301
|
-
getOnRampForRouter(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
return Promise.resolve(this.contractsDir.onRamp)
|
|
315
|
+
getOnRampForRouter(router: string, _destChainSelector: bigint): Promise<string> {
|
|
316
|
+
// For Sui, the router is the onramp package address
|
|
317
|
+
return Promise.resolve(router)
|
|
306
318
|
}
|
|
307
319
|
|
|
308
|
-
/**
|
|
320
|
+
/**
|
|
321
|
+
* {@inheritDoc Chain.getOnRampForOffRamp}
|
|
322
|
+
* @throws {@link CCIPDataFormatUnsupportedError} if view call fails
|
|
323
|
+
*/
|
|
309
324
|
async getOnRampForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string> {
|
|
310
|
-
|
|
311
|
-
throw new CCIPError(CCIPErrorCode.UNKNOWN, 'CCIP address not set in contracts directory')
|
|
312
|
-
}
|
|
313
|
-
const offrampPackageId = offRamp
|
|
325
|
+
offRamp = await getLatestPackageId(offRamp, this.client)
|
|
314
326
|
const functionName = 'get_source_chain_config'
|
|
315
|
-
|
|
327
|
+
// Preserve module suffix if present, otherwise add it
|
|
328
|
+
const target = offRamp.includes('::')
|
|
329
|
+
? `${offRamp}::${functionName}`
|
|
330
|
+
: `${offRamp}::offramp::${functionName}`
|
|
331
|
+
|
|
332
|
+
// Discover the CCIP package from the offramp
|
|
333
|
+
const ccip = await getCcipStateAddress(offRamp, this.client)
|
|
316
334
|
|
|
317
335
|
// Get the OffRampState object
|
|
318
|
-
const offrampStateObject = await
|
|
319
|
-
const ccipObjectRef = await
|
|
336
|
+
const offrampStateObject = await getObjectRef(offRamp, this.client)
|
|
337
|
+
const ccipObjectRef = await getObjectRef(ccip, this.client)
|
|
320
338
|
// Use the Transaction builder to create a move call
|
|
321
339
|
const tx = new Transaction()
|
|
322
340
|
|
|
@@ -380,44 +398,178 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
380
398
|
return Promise.resolve(offRamp)
|
|
381
399
|
}
|
|
382
400
|
|
|
383
|
-
/**
|
|
384
|
-
|
|
385
|
-
|
|
401
|
+
/**
|
|
402
|
+
* {@inheritDoc Chain.getTokenForTokenPool}
|
|
403
|
+
* @throws {@link CCIPError} if token pool type is invalid or state not found
|
|
404
|
+
* @throws {@link CCIPDataFormatUnsupportedError} if view call fails
|
|
405
|
+
*/
|
|
406
|
+
async getTokenForTokenPool(tokenPool: string): Promise<string> {
|
|
407
|
+
const normalizedTokenPool = normalizeSuiAddress(tokenPool)
|
|
408
|
+
|
|
409
|
+
// Get objects owned by this package (looking for state pointers)
|
|
410
|
+
const objects = await this.client.getOwnedObjects({
|
|
411
|
+
owner: normalizedTokenPool,
|
|
412
|
+
options: { showType: true, showContent: true },
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
const tpType = objects.data
|
|
416
|
+
.find((obj) => obj.data?.type?.includes('token_pool::'))
|
|
417
|
+
?.data?.type?.split('::')[1]
|
|
418
|
+
|
|
419
|
+
const allowedTps = ['managed_token_pool', 'burn_mint_token_pool', 'lock_release_token_pool']
|
|
420
|
+
if (!tpType || !allowedTps.includes(tpType)) {
|
|
421
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, `Invalid token pool type: ${tpType}`)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Find the state pointer object
|
|
425
|
+
let stateObjectPointerId: string | undefined
|
|
426
|
+
for (const obj of objects.data) {
|
|
427
|
+
const content = obj.data?.content
|
|
428
|
+
if (content?.dataType !== 'moveObject') continue
|
|
429
|
+
|
|
430
|
+
const fields = content.fields as Record<string, unknown>
|
|
431
|
+
// Look for a pointer field that references the state object
|
|
432
|
+
stateObjectPointerId = fields[`${tpType}_object_id`] as string
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!stateObjectPointerId) {
|
|
436
|
+
throw new CCIPError(
|
|
437
|
+
CCIPErrorCode.UNKNOWN,
|
|
438
|
+
`No token pool state pointer found for ${tokenPool}`,
|
|
439
|
+
)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const stateNamesPerTP: Record<string, string> = {
|
|
443
|
+
managed_token_pool: 'ManagedTokenPoolState',
|
|
444
|
+
burn_mint_token_pool: 'BurnMintTokenPoolState',
|
|
445
|
+
lock_release_token_pool: 'LockReleaseTokenPoolState',
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const poolStateObject = deriveObjectID(
|
|
449
|
+
stateObjectPointerId,
|
|
450
|
+
new TextEncoder().encode(stateNamesPerTP[tpType]),
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
// Get object info to get the coin type
|
|
454
|
+
const info = await this.client.getObject({
|
|
455
|
+
id: poolStateObject,
|
|
456
|
+
options: { showType: true, showContent: true },
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
const type = info.data?.type
|
|
460
|
+
if (!type) {
|
|
461
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, 'Error loading token pool state object type')
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Extract the type parameter T from ManagedTokenPoolState<T>
|
|
465
|
+
const typeMatch = type.match(/(?:Managed|BurnMint|LockRelease)TokenPoolState<(.+)>$/)
|
|
466
|
+
if (!typeMatch || !typeMatch[1]) {
|
|
467
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, `Invalid pool state type format: ${type}`)
|
|
468
|
+
}
|
|
469
|
+
const tokenType = typeMatch[1]
|
|
470
|
+
|
|
471
|
+
// Call get_token function from managed_token_pool contract with the type parameter
|
|
472
|
+
const target = type.split('<')[0]?.split('::').slice(0, 2).join('::') + '::get_token'
|
|
473
|
+
if (!target) {
|
|
474
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, `Invalid pool state type format: ${type}`)
|
|
475
|
+
}
|
|
476
|
+
const tx = new Transaction()
|
|
477
|
+
tx.moveCall({
|
|
478
|
+
target,
|
|
479
|
+
typeArguments: [tokenType],
|
|
480
|
+
arguments: [tx.object(poolStateObject)],
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
const result = await this.client.devInspectTransactionBlock({
|
|
484
|
+
sender: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
485
|
+
transactionBlock: tx,
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
if (result.effects.status.status !== 'success' || !result.results?.[0]?.returnValues?.[0]) {
|
|
489
|
+
throw new CCIPDataFormatUnsupportedError(
|
|
490
|
+
`Failed to call ${target}: ${result.effects.status.error || 'No return value'}`,
|
|
491
|
+
)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Parse the return value to get the coin metadata address (32 bytes)
|
|
495
|
+
const returnValue = result.results[0].returnValues[0]
|
|
496
|
+
const [data] = returnValue
|
|
497
|
+
const coinMetadataBytes = new Uint8Array(data)
|
|
498
|
+
const coinMetadataAddress = normalizeSuiAddress(hexlify(coinMetadataBytes))
|
|
499
|
+
|
|
500
|
+
return coinMetadataAddress
|
|
386
501
|
}
|
|
387
502
|
|
|
388
|
-
/**
|
|
503
|
+
/**
|
|
504
|
+
* {@inheritDoc Chain.getTokenInfo}
|
|
505
|
+
* @throws {@link CCIPError} if token address is invalid or metadata cannot be loaded
|
|
506
|
+
*/
|
|
389
507
|
async getTokenInfo(token: string): Promise<{ symbol: string; decimals: number }> {
|
|
390
|
-
|
|
391
|
-
if (
|
|
392
|
-
|
|
508
|
+
const normalizedTokenAddress = normalizeSuiAddress(token)
|
|
509
|
+
if (!isValidSuiAddress(normalizedTokenAddress)) {
|
|
510
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, 'Error loading Sui token metadata')
|
|
393
511
|
}
|
|
394
512
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
513
|
+
const objectResponse = await this.client.getObject({
|
|
514
|
+
id: normalizedTokenAddress,
|
|
515
|
+
options: { showType: true },
|
|
516
|
+
})
|
|
399
517
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
518
|
+
const getCoinFromMetadata = (metadata: string) => {
|
|
519
|
+
// Extract the type parameter from CoinMetadata<...>
|
|
520
|
+
const match = metadata.match(/CoinMetadata<(.+)>$/)
|
|
521
|
+
|
|
522
|
+
if (!match || !match[1]) {
|
|
523
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, `Invalid metadata format: ${metadata}`)
|
|
405
524
|
}
|
|
406
|
-
|
|
407
|
-
|
|
525
|
+
|
|
526
|
+
return match[1]
|
|
408
527
|
}
|
|
409
528
|
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
529
|
+
let coinType: string
|
|
530
|
+
const objectType = objectResponse.data?.type
|
|
531
|
+
|
|
532
|
+
// Check if this is a CoinMetadata object or a coin type string
|
|
533
|
+
if (objectType?.includes('CoinMetadata')) {
|
|
534
|
+
coinType = getCoinFromMetadata(objectType)
|
|
535
|
+
} else if (token.includes('::')) {
|
|
536
|
+
// This is a coin type string (e.g., "0xabc::coin::COIN")
|
|
537
|
+
coinType = token
|
|
538
|
+
} else {
|
|
539
|
+
// This is a package address or unknown format
|
|
540
|
+
throw new CCIPError(
|
|
541
|
+
CCIPErrorCode.UNKNOWN,
|
|
542
|
+
`Token address ${token} is not a CoinMetadata object or coin type. Expected format: package::module::Type`,
|
|
543
|
+
)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (coinType.split('::').length < 3) {
|
|
547
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, 'Error loading Sui token metadata')
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
let metadata = null
|
|
551
|
+
try {
|
|
552
|
+
metadata = await this.client.getCoinMetadata({ coinType })
|
|
553
|
+
} catch (e) {
|
|
554
|
+
console.error('Error fetching coin metadata:', e)
|
|
555
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, 'Error loading Sui token metadata')
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (!metadata) {
|
|
559
|
+
throw new CCIPError(CCIPErrorCode.UNKNOWN, 'Error loading Sui token metadata')
|
|
560
|
+
}
|
|
413
561
|
|
|
414
562
|
return {
|
|
415
|
-
symbol: symbol
|
|
416
|
-
decimals:
|
|
563
|
+
symbol: metadata.symbol,
|
|
564
|
+
decimals: metadata.decimals,
|
|
417
565
|
}
|
|
418
566
|
}
|
|
419
567
|
|
|
420
|
-
/** {@inheritDoc Chain.
|
|
568
|
+
/** {@inheritDoc Chain.getBalance} */
|
|
569
|
+
async getBalance(_opts: GetBalanceOpts): Promise<bigint> {
|
|
570
|
+
return Promise.reject(new CCIPNotImplementedError('SuiChain.getBalance'))
|
|
571
|
+
}
|
|
572
|
+
|
|
421
573
|
/** {@inheritDoc Chain.getTokenAdminRegistryFor} */
|
|
422
574
|
getTokenAdminRegistryFor(_address: string): Promise<string> {
|
|
423
575
|
return Promise.reject(new CCIPNotImplementedError())
|
|
@@ -426,11 +578,23 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
426
578
|
// Static methods for decoding
|
|
427
579
|
/**
|
|
428
580
|
* Decodes a CCIP message from a Sui log event.
|
|
429
|
-
* @param
|
|
581
|
+
* @param log - Log event data.
|
|
430
582
|
* @returns Decoded CCIPMessage or undefined if not valid.
|
|
583
|
+
* @throws {@link CCIPSuiLogInvalidError} if log data format is invalid
|
|
431
584
|
*/
|
|
432
|
-
static decodeMessage(
|
|
433
|
-
|
|
585
|
+
static decodeMessage(log: Log_): CCIPMessage | undefined {
|
|
586
|
+
const { data } = log
|
|
587
|
+
if (
|
|
588
|
+
(typeof data !== 'string' || !data.startsWith('{')) &&
|
|
589
|
+
(typeof data !== 'object' || isBytesLike(data))
|
|
590
|
+
)
|
|
591
|
+
throw new CCIPSuiLogInvalidError(util.inspect(log))
|
|
592
|
+
// offload massaging to generic decodeJsonMessage
|
|
593
|
+
try {
|
|
594
|
+
return decodeMessage(data)
|
|
595
|
+
} catch (_) {
|
|
596
|
+
// return undefined
|
|
597
|
+
}
|
|
434
598
|
}
|
|
435
599
|
|
|
436
600
|
/**
|
|
@@ -451,6 +615,7 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
451
615
|
* Encodes extra arguments for CCIP messages.
|
|
452
616
|
* @param _extraArgs - Extra arguments to encode.
|
|
453
617
|
* @returns Encoded extra arguments as a hex string.
|
|
618
|
+
* @throws {@link CCIPNotImplementedError} always (not yet implemented)
|
|
454
619
|
*/
|
|
455
620
|
static encodeExtraArgs(_extraArgs: ExtraArgs): string {
|
|
456
621
|
throw new CCIPNotImplementedError()
|
|
@@ -459,30 +624,36 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
459
624
|
/**
|
|
460
625
|
* Decodes commit reports from a log entry.
|
|
461
626
|
* @param log - The log entry to decode.
|
|
462
|
-
* @param
|
|
627
|
+
* @param lane - Optional lane information.
|
|
463
628
|
* @returns Array of decoded commit reports or undefined.
|
|
464
629
|
*/
|
|
465
|
-
static decodeCommits(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (!
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
return
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
630
|
+
static decodeCommits(
|
|
631
|
+
{ data, topics }: SetOptional<Pick<Log_, 'data' | 'topics'>, 'topics'>,
|
|
632
|
+
lane?: Lane,
|
|
633
|
+
): CommitReport[] | undefined {
|
|
634
|
+
// Check if this is an CommitReportAccepted event
|
|
635
|
+
if (topics?.[0] && topics[0] !== 'CommitReportAccepted') return
|
|
636
|
+
|
|
637
|
+
// Basic log data structure validation
|
|
638
|
+
if (!data || typeof data !== 'object' || !('unblessed_merkle_roots' in data)) return
|
|
639
|
+
|
|
640
|
+
const eventData = data as CommitEvent
|
|
641
|
+
const rootsRaw = eventData.blessed_merkle_roots.concat(eventData.unblessed_merkle_roots)
|
|
642
|
+
return rootsRaw
|
|
643
|
+
.map((root) => {
|
|
644
|
+
return {
|
|
645
|
+
sourceChainSelector: BigInt(root.source_chain_selector),
|
|
646
|
+
onRampAddress: decodeOnRampAddress(root.on_ramp_address),
|
|
647
|
+
minSeqNr: BigInt(root.min_seq_nr),
|
|
648
|
+
maxSeqNr: BigInt(root.max_seq_nr),
|
|
649
|
+
merkleRoot: hexlify(getDataBytes(root.merkle_root)),
|
|
650
|
+
}
|
|
651
|
+
})
|
|
652
|
+
.filter((r) =>
|
|
653
|
+
lane
|
|
654
|
+
? r.sourceChainSelector === lane.sourceChainSelector && r.onRampAddress === lane.onRamp
|
|
655
|
+
: true,
|
|
656
|
+
)
|
|
486
657
|
}
|
|
487
658
|
|
|
488
659
|
/**
|
|
@@ -490,52 +661,32 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
490
661
|
* @param log - The log entry to decode.
|
|
491
662
|
* @returns Decoded execution receipt or undefined.
|
|
492
663
|
*/
|
|
493
|
-
static decodeReceipt(
|
|
664
|
+
static decodeReceipt({
|
|
665
|
+
data,
|
|
666
|
+
topics,
|
|
667
|
+
}: SetOptional<Pick<Log_, 'data' | 'topics'>, 'topics'>): ExecutionReceipt | undefined {
|
|
494
668
|
// Check if this is an ExecutionStateChanged event
|
|
495
|
-
|
|
496
|
-
if (topic !== 'ExecutionStateChanged') {
|
|
497
|
-
return undefined
|
|
498
|
-
}
|
|
669
|
+
if (topics?.[0] && topics[0] !== 'ExecutionStateChanged') return
|
|
499
670
|
|
|
500
|
-
//
|
|
501
|
-
if (!
|
|
502
|
-
return
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
const eventData = log.data as {
|
|
506
|
-
message_hash?: number[]
|
|
507
|
-
message_id?: number[]
|
|
508
|
-
sequence_number?: string
|
|
509
|
-
source_chain_selector?: string
|
|
510
|
-
state?: number
|
|
671
|
+
// Basic log data structure validation
|
|
672
|
+
if (!data || typeof data !== 'object' || !('message_id' in data) || !('state' in data)) {
|
|
673
|
+
return
|
|
511
674
|
}
|
|
512
675
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
) {
|
|
520
|
-
return undefined
|
|
676
|
+
const eventData = data as {
|
|
677
|
+
message_hash: BytesLike
|
|
678
|
+
message_id: BytesLike
|
|
679
|
+
sequence_number: string
|
|
680
|
+
source_chain_selector: string
|
|
681
|
+
state: number
|
|
521
682
|
}
|
|
522
683
|
|
|
523
|
-
const toHex = (bytes: BytesLike | number[]) => hexlify(bytesToBuffer(bytes))
|
|
524
|
-
|
|
525
|
-
// Convert message_id bytes array to hex string
|
|
526
|
-
const messageId = toHex(eventData.message_id)
|
|
527
|
-
|
|
528
|
-
// Convert message_hash bytes array to hex string (if present)
|
|
529
|
-
const messageHash = eventData.message_hash ? toHex(eventData.message_hash) : undefined
|
|
530
|
-
|
|
531
684
|
return {
|
|
532
|
-
messageId,
|
|
685
|
+
messageId: hexlify(getDataBytes(eventData.message_id)),
|
|
533
686
|
sequenceNumber: BigInt(eventData.sequence_number),
|
|
534
|
-
state: eventData.state as ExecutionState,
|
|
535
|
-
sourceChainSelector: eventData.source_chain_selector
|
|
536
|
-
|
|
537
|
-
: undefined,
|
|
538
|
-
messageHash,
|
|
687
|
+
state: Number(eventData.state) as ExecutionState,
|
|
688
|
+
sourceChainSelector: BigInt(eventData.source_chain_selector),
|
|
689
|
+
messageHash: hexlify(getDataBytes(eventData.message_hash)),
|
|
539
690
|
}
|
|
540
691
|
}
|
|
541
692
|
|
|
@@ -544,15 +695,17 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
544
695
|
* @param bytes - Bytes to convert.
|
|
545
696
|
* @returns Sui address.
|
|
546
697
|
*/
|
|
547
|
-
static getAddress(bytes: BytesLike): string {
|
|
698
|
+
static getAddress(bytes: BytesLike | readonly number[]): string {
|
|
548
699
|
return AptosChain.getAddress(bytes)
|
|
549
700
|
}
|
|
550
701
|
|
|
551
702
|
/**
|
|
552
703
|
* Validates a transaction hash format for Sui
|
|
553
704
|
*/
|
|
554
|
-
static isTxHash(
|
|
555
|
-
return false
|
|
705
|
+
static isTxHash(v: unknown): v is string {
|
|
706
|
+
if (typeof v !== 'string') return false
|
|
707
|
+
// check in both hex and base58 formats
|
|
708
|
+
return isHexString(v, 32) || isValidTransactionDigest(v)
|
|
556
709
|
}
|
|
557
710
|
|
|
558
711
|
/**
|
|
@@ -583,9 +736,6 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
583
736
|
|
|
584
737
|
/** {@inheritDoc Chain.getOffchainTokenData} */
|
|
585
738
|
getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]> {
|
|
586
|
-
if (!('receiverObjectIds' in request.message)) {
|
|
587
|
-
throw new CCIPSuiMessageVersionInvalidError()
|
|
588
|
-
}
|
|
589
739
|
// default offchain token data
|
|
590
740
|
return Promise.resolve(request.message.tokenAmounts.map(() => undefined))
|
|
591
741
|
}
|
|
@@ -597,25 +747,27 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
597
747
|
return Promise.reject(new CCIPNotImplementedError('SuiChain.generateUnsignedExecuteReport'))
|
|
598
748
|
}
|
|
599
749
|
|
|
600
|
-
/**
|
|
750
|
+
/**
|
|
751
|
+
* {@inheritDoc Chain.executeReport}
|
|
752
|
+
* @throws {@link CCIPError} if transaction submission fails
|
|
753
|
+
* @throws {@link CCIPExecTxRevertedError} if transaction reverts
|
|
754
|
+
*/
|
|
601
755
|
async executeReport(
|
|
602
756
|
opts: Parameters<Chain['executeReport']>[0] & {
|
|
603
757
|
receiverObjectIds?: string[]
|
|
604
758
|
},
|
|
605
759
|
): Promise<CCIPExecution> {
|
|
606
|
-
const { execReport } = opts
|
|
607
|
-
if (!this.contractsDir.offRamp || !this.contractsDir.ccip) {
|
|
608
|
-
throw new CCIPContractNotRouterError(
|
|
609
|
-
'OffRamp or CCIP address not set in contracts directory',
|
|
610
|
-
'Sui',
|
|
611
|
-
)
|
|
612
|
-
}
|
|
760
|
+
const { execReport, offRamp } = opts
|
|
613
761
|
const wallet = opts.wallet as Keypair
|
|
614
|
-
|
|
615
|
-
|
|
762
|
+
|
|
763
|
+
// Discover the CCIP package from the offramp
|
|
764
|
+
const ccip = await getCcipStateAddress(offRamp, this.client)
|
|
765
|
+
|
|
766
|
+
const ccipObjectRef = await getObjectRef(ccip, this.client)
|
|
767
|
+
const offrampStateObject = await getObjectRef(offRamp, this.client)
|
|
616
768
|
const receiverConfig = await getReceiverModule(
|
|
617
769
|
this.client,
|
|
618
|
-
|
|
770
|
+
ccip,
|
|
619
771
|
ccipObjectRef,
|
|
620
772
|
execReport.message.receiver,
|
|
621
773
|
)
|
|
@@ -623,7 +775,7 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
623
775
|
if (execReport.message.tokenAmounts.length !== 0) {
|
|
624
776
|
tokenConfigs = await fetchTokenConfigs(
|
|
625
777
|
this.client,
|
|
626
|
-
|
|
778
|
+
ccip,
|
|
627
779
|
ccipObjectRef,
|
|
628
780
|
execReport.message.tokenAmounts as CCIPMessage<typeof CCIPVersion.V1_6>['tokenAmounts'],
|
|
629
781
|
)
|
|
@@ -631,8 +783,8 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
631
783
|
|
|
632
784
|
const input: SuiManuallyExecuteInput = {
|
|
633
785
|
executionReport: execReport as ExecutionReport<CCIPMessage_V1_6_Sui>,
|
|
634
|
-
offrampAddress:
|
|
635
|
-
ccipAddress:
|
|
786
|
+
offrampAddress: offRamp,
|
|
787
|
+
ccipAddress: ccip,
|
|
636
788
|
ccipObjectRef,
|
|
637
789
|
offrampStateObject,
|
|
638
790
|
receiverConfig,
|
|
@@ -714,9 +866,9 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
714
866
|
return Promise.reject(new CCIPNotImplementedError('SuiChain.getRegistryTokenConfig'))
|
|
715
867
|
}
|
|
716
868
|
|
|
717
|
-
/** {@inheritDoc Chain.
|
|
718
|
-
async
|
|
719
|
-
return Promise.reject(new CCIPNotImplementedError('SuiChain.
|
|
869
|
+
/** {@inheritDoc Chain.getTokenPoolConfig} */
|
|
870
|
+
async getTokenPoolConfig(_tokenPool: string): Promise<never> {
|
|
871
|
+
return Promise.reject(new CCIPNotImplementedError('SuiChain.getTokenPoolConfig'))
|
|
720
872
|
}
|
|
721
873
|
|
|
722
874
|
/** {@inheritDoc Chain.getTokenPoolRemotes} */
|
|
@@ -748,7 +900,8 @@ export class SuiChain extends Chain<typeof ChainFamily.Sui> {
|
|
|
748
900
|
const tokenReceiver =
|
|
749
901
|
message.extraArgs &&
|
|
750
902
|
'tokenReceiver' in message.extraArgs &&
|
|
751
|
-
message.extraArgs.tokenReceiver != null
|
|
903
|
+
message.extraArgs.tokenReceiver != null &&
|
|
904
|
+
typeof message.extraArgs.tokenReceiver === 'string'
|
|
752
905
|
? message.extraArgs.tokenReceiver
|
|
753
906
|
: message.tokenAmounts?.length
|
|
754
907
|
? this.getAddress(message.receiver)
|