@chainlink/ccip-sdk 0.95.0 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +15 -12
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +20 -16
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +25 -29
- package/dist/api/types.d.ts.map +1 -1
- package/dist/aptos/index.d.ts +33 -8
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +74 -41
- package/dist/aptos/index.js.map +1 -1
- package/dist/chain.d.ts +220 -41
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +105 -15
- package/dist/chain.js.map +1 -1
- package/dist/errors/codes.d.ts +2 -0
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +2 -0
- package/dist/errors/codes.js.map +1 -1
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/recovery.d.ts.map +1 -1
- package/dist/errors/recovery.js +2 -0
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +12 -6
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +19 -7
- 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.map +1 -1
- package/dist/evm/gas.js +7 -12
- package/dist/evm/gas.js.map +1 -1
- package/dist/evm/index.d.ts +70 -24
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +72 -91
- package/dist/evm/index.js.map +1 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +16 -2
- 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 +6 -3
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +14 -6
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +10 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/requests.d.ts +17 -9
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +17 -9
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +12 -0
- package/dist/selectors.js.map +1 -1
- package/dist/solana/index.d.ts +70 -15
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +72 -16
- package/dist/solana/index.js.map +1 -1
- package/dist/sui/index.d.ts +37 -9
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +40 -11
- package/dist/sui/index.js.map +1 -1
- package/dist/ton/index.d.ts +65 -19
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +155 -25
- 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/types.d.ts +102 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +15 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +19 -6
- package/dist/utils.js.map +1 -1
- package/package.json +12 -7
- package/src/all-chains.ts +26 -0
- package/src/api/index.ts +26 -25
- package/src/api/types.ts +25 -30
- package/src/aptos/index.ts +79 -43
- package/src/chain.ts +274 -46
- package/src/errors/codes.ts +2 -0
- package/src/errors/index.ts +1 -1
- package/src/errors/recovery.ts +2 -0
- package/src/errors/specialized.ts +24 -7
- package/src/evm/extra-args.ts +377 -0
- package/src/evm/gas.ts +14 -13
- package/src/evm/index.ts +76 -125
- package/src/execution.ts +18 -2
- package/src/extra-args.ts +108 -4
- package/src/gas.ts +16 -9
- package/src/index.ts +12 -9
- package/src/requests.ts +17 -9
- package/src/selectors.ts +12 -0
- package/src/solana/index.ts +72 -16
- package/src/sui/index.ts +40 -11
- package/src/ton/index.ts +192 -27
- package/src/ton/send.ts +222 -0
- package/src/types.ts +103 -1
- package/src/utils.ts +19 -6
package/src/chain.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
CCIPApiClientNotAvailableError,
|
|
9
9
|
CCIPChainFamilyMismatchError,
|
|
10
10
|
CCIPExecTxRevertedError,
|
|
11
|
+
CCIPTokenPoolChainConfigNotFoundError,
|
|
11
12
|
CCIPTransactionNotFinalizedError,
|
|
12
13
|
} from './errors/index.ts'
|
|
13
14
|
import { DEFAULT_GAS_LIMIT } from './evm/const.ts'
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
EVMExtraArgsV1,
|
|
17
18
|
EVMExtraArgsV2,
|
|
18
19
|
ExtraArgs,
|
|
20
|
+
GenericExtraArgsV3,
|
|
19
21
|
SVMExtraArgsV1,
|
|
20
22
|
SuiExtraArgsV1,
|
|
21
23
|
} from './extra-args.ts'
|
|
@@ -43,7 +45,24 @@ import {
|
|
|
43
45
|
type WithLogger,
|
|
44
46
|
ExecutionState,
|
|
45
47
|
} from './types.ts'
|
|
46
|
-
import { util, withRetry } from './utils.ts'
|
|
48
|
+
import { networkInfo, util, withRetry } from './utils.ts'
|
|
49
|
+
|
|
50
|
+
/** Field names unique to GenericExtraArgsV3 (not present in V2). */
|
|
51
|
+
const V3_ONLY_FIELDS = [
|
|
52
|
+
'blockConfirmations',
|
|
53
|
+
'ccvs',
|
|
54
|
+
'ccvArgs',
|
|
55
|
+
'executor',
|
|
56
|
+
'executorArgs',
|
|
57
|
+
'tokenReceiver',
|
|
58
|
+
'tokenArgs',
|
|
59
|
+
] as const
|
|
60
|
+
|
|
61
|
+
/** Check if extraArgs contains any V3-only fields. */
|
|
62
|
+
function hasV3ExtraArgs(extraArgs: Partial<ExtraArgs> | undefined): boolean {
|
|
63
|
+
if (!extraArgs) return false
|
|
64
|
+
return V3_ONLY_FIELDS.some((field) => field in extraArgs)
|
|
65
|
+
}
|
|
47
66
|
|
|
48
67
|
/**
|
|
49
68
|
* Context for Chain class initialization.
|
|
@@ -71,8 +90,7 @@ export type ChainContext = WithLogger & {
|
|
|
71
90
|
/**
|
|
72
91
|
* CCIP API client instance for lane information queries.
|
|
73
92
|
*
|
|
74
|
-
* - `undefined` (default): Creates CCIPAPIClient with
|
|
75
|
-
* (https://api.ccip.chain.link)
|
|
93
|
+
* - `undefined` (default): Creates CCIPAPIClient with {@link DEFAULT_API_BASE_URL}
|
|
76
94
|
* - `CCIPAPIClient`: Uses provided instance (allows custom URL, fetch, etc.)
|
|
77
95
|
* - `null`: Disables API client entirely (getLaneLatency() will throw)
|
|
78
96
|
*
|
|
@@ -164,24 +182,51 @@ export type GetBalanceOpts = {
|
|
|
164
182
|
|
|
165
183
|
/**
|
|
166
184
|
* Rate limiter state for token pool configurations.
|
|
167
|
-
*
|
|
185
|
+
*
|
|
186
|
+
* @remarks
|
|
187
|
+
* - Returns the rate limiter bucket state when rate limiting is **enabled**
|
|
188
|
+
* - Returns `null` when rate limiting is **disabled** (unlimited throughput)
|
|
189
|
+
*
|
|
190
|
+
* @example Handling nullable state
|
|
191
|
+
* ```typescript
|
|
192
|
+
* const remote = await chain.getTokenPoolRemotes(poolAddress)
|
|
193
|
+
* const state = remote['ethereum-mainnet'].inboundRateLimiterState
|
|
194
|
+
*
|
|
195
|
+
* if (state === null) {
|
|
196
|
+
* console.log('Rate limiting disabled - unlimited throughput')
|
|
197
|
+
* } else {
|
|
198
|
+
* console.log(`Capacity: ${state.capacity}, Available: ${state.tokens}`)
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
168
201
|
*/
|
|
169
202
|
export type RateLimiterState = {
|
|
170
203
|
/** Current token balance in the rate limiter bucket. */
|
|
171
204
|
tokens: bigint
|
|
172
205
|
/** Maximum capacity of the rate limiter bucket. */
|
|
173
206
|
capacity: bigint
|
|
174
|
-
/** Rate at which tokens are replenished. */
|
|
207
|
+
/** Rate at which tokens are replenished (tokens per second). */
|
|
175
208
|
rate: bigint
|
|
176
209
|
} | null
|
|
177
210
|
|
|
178
211
|
/**
|
|
179
|
-
* Remote token pool configuration for a specific chain.
|
|
212
|
+
* Remote token pool configuration for a specific destination chain.
|
|
213
|
+
*
|
|
214
|
+
* @remarks
|
|
215
|
+
* Each entry represents the configuration needed to transfer tokens
|
|
216
|
+
* from the current chain to a specific destination chain.
|
|
180
217
|
*/
|
|
181
218
|
export type TokenPoolRemote = {
|
|
182
219
|
/** Address of the remote token on the destination chain. */
|
|
183
220
|
remoteToken: string
|
|
184
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* Addresses of remote token pools on the destination chain.
|
|
223
|
+
*
|
|
224
|
+
* @remarks
|
|
225
|
+
* Multiple pools may exist for:
|
|
226
|
+
* - Redundancy (failover if one pool is unavailable)
|
|
227
|
+
* - Capacity aggregation across pools
|
|
228
|
+
* - Version management (different pool implementations)
|
|
229
|
+
*/
|
|
185
230
|
remotePools: string[]
|
|
186
231
|
/** Inbound rate limiter state for tokens coming into this chain. */
|
|
187
232
|
inboundRateLimiterState: RateLimiterState
|
|
@@ -189,6 +234,43 @@ export type TokenPoolRemote = {
|
|
|
189
234
|
outboundRateLimiterState: RateLimiterState
|
|
190
235
|
}
|
|
191
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Token pool configuration returned by {@link Chain.getTokenPoolConfig}.
|
|
239
|
+
*
|
|
240
|
+
* @remarks
|
|
241
|
+
* Contains the core configuration of a token pool including the token it manages,
|
|
242
|
+
* the router it's registered with, and optionally its version identifier.
|
|
243
|
+
*/
|
|
244
|
+
export type TokenPoolConfig = {
|
|
245
|
+
/** Address of the token managed by this pool. */
|
|
246
|
+
token: string
|
|
247
|
+
/** Address of the CCIP router this pool is registered with. */
|
|
248
|
+
router: string
|
|
249
|
+
/**
|
|
250
|
+
* Version identifier string (e.g., "BurnMintTokenPool 1.5.1").
|
|
251
|
+
*
|
|
252
|
+
* @remarks
|
|
253
|
+
* May be undefined for older pool implementations that don't expose this method.
|
|
254
|
+
*/
|
|
255
|
+
typeAndVersion?: string
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Token configuration from a TokenAdminRegistry, returned by {@link Chain.getRegistryTokenConfig}.
|
|
260
|
+
*
|
|
261
|
+
* @remarks
|
|
262
|
+
* The TokenAdminRegistry tracks which administrator controls each token
|
|
263
|
+
* and which pool is authorized to handle transfers.
|
|
264
|
+
*/
|
|
265
|
+
export type RegistryTokenConfig = {
|
|
266
|
+
/** Address of the current administrator for this token. */
|
|
267
|
+
administrator: string
|
|
268
|
+
/** Address of pending administrator (if ownership transfer is in progress). */
|
|
269
|
+
pendingAdministrator?: string
|
|
270
|
+
/** Address of the token pool authorized to handle this token's transfers. */
|
|
271
|
+
tokenPool?: string
|
|
272
|
+
}
|
|
273
|
+
|
|
192
274
|
/**
|
|
193
275
|
* Maps chain family to respective unsigned transaction type.
|
|
194
276
|
*/
|
|
@@ -202,7 +284,7 @@ export type UnsignedTx = {
|
|
|
202
284
|
}
|
|
203
285
|
|
|
204
286
|
/**
|
|
205
|
-
* Common options for
|
|
287
|
+
* Common options for {@link Chain.getFee}, {@link Chain.generateUnsignedSendMessage} and {@link Chain.sendMessage} methods.
|
|
206
288
|
*/
|
|
207
289
|
export type SendMessageOpts = {
|
|
208
290
|
/** Router address on this chain */
|
|
@@ -216,7 +298,7 @@ export type SendMessageOpts = {
|
|
|
216
298
|
}
|
|
217
299
|
|
|
218
300
|
/**
|
|
219
|
-
* Common options for
|
|
301
|
+
* Common options for {@link Chain.generateUnsignedExecuteReport} and {@link Chain.executeReport} methods.
|
|
220
302
|
*/
|
|
221
303
|
export type ExecuteReportOpts = {
|
|
222
304
|
/** address of the OffRamp contract */
|
|
@@ -249,6 +331,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
249
331
|
* Base constructor for Chain class.
|
|
250
332
|
* @param network - NetworkInfo object for the Chain instance
|
|
251
333
|
* @param ctx - Optional context with logger and API client configuration
|
|
334
|
+
* @throws {@link CCIPChainFamilyMismatchError} if network family doesn't match the Chain subclass
|
|
252
335
|
*/
|
|
253
336
|
constructor(network: NetworkInfo, ctx?: ChainContext) {
|
|
254
337
|
const { logger = console, apiClient, apiRetryConfig } = ctx ?? {}
|
|
@@ -287,17 +370,21 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
287
370
|
* Fetch the timestamp of a given block
|
|
288
371
|
* @param block - positive block number, negative finality depth or 'finalized' tag
|
|
289
372
|
* @returns timestamp of the block, in seconds
|
|
373
|
+
* @throws {@link CCIPBlockNotFoundError} if block does not exist
|
|
290
374
|
*/
|
|
291
375
|
abstract getBlockTimestamp(block: number | 'finalized'): Promise<number>
|
|
292
376
|
/**
|
|
293
377
|
* Fetch a transaction by its hash
|
|
294
378
|
* @param hash - transaction hash
|
|
295
379
|
* @returns generic transaction details
|
|
380
|
+
* @throws {@link CCIPTransactionNotFoundError} if transaction not found
|
|
296
381
|
*/
|
|
297
382
|
abstract getTransaction(hash: string): Promise<ChainTransaction>
|
|
298
383
|
/**
|
|
299
|
-
* Confirm a log tx is finalized or wait for it to be finalized
|
|
300
|
-
*
|
|
384
|
+
* Confirm a log tx is finalized or wait for it to be finalized.
|
|
385
|
+
* @param opts - Options containing the request, finality level, and optional cancel promise
|
|
386
|
+
* @returns true when the transaction is finalized
|
|
387
|
+
* @throws {@link CCIPTransactionNotFinalizedError} if the transaction is not included (e.g., due to a reorg)
|
|
301
388
|
*/
|
|
302
389
|
async waitFinalized({
|
|
303
390
|
request: { log, tx },
|
|
@@ -359,6 +446,9 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
359
446
|
* - `page`: if provided, try to use this page/range for batches
|
|
360
447
|
* - `watch`: true or cancellation promise, getLogs continuously after initial fetch
|
|
361
448
|
* @returns An async iterable iterator of logs.
|
|
449
|
+
* @throws {@link CCIPLogsWatchRequiresFinalityError} if watch mode is used without a finality endBlock tag
|
|
450
|
+
* @throws {@link CCIPLogsWatchRequiresStartError} if watch mode is used without startBlock or startTime
|
|
451
|
+
* @throws {@link CCIPLogsAddressRequiredError} if address is required but not provided (chain-specific)
|
|
362
452
|
*/
|
|
363
453
|
abstract getLogs(opts: LogFilter): AsyncIterableIterator<Log_>
|
|
364
454
|
|
|
@@ -366,7 +456,8 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
366
456
|
* Fetch all CCIP requests in a transaction
|
|
367
457
|
* @param tx - ChainTransaction or txHash to fetch requests from
|
|
368
458
|
* @returns CCIP messages in the transaction (at least one)
|
|
369
|
-
|
|
459
|
+
* @throws {@link CCIPMessageNotFoundInTxError} if no CCIP messages found in transaction
|
|
460
|
+
*/
|
|
370
461
|
async getMessagesInTx(tx: string | ChainTransaction): Promise<CCIPRequest[]> {
|
|
371
462
|
const txHash = typeof tx === 'string' ? tx : tx.hash
|
|
372
463
|
try {
|
|
@@ -396,12 +487,31 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
396
487
|
}
|
|
397
488
|
|
|
398
489
|
/**
|
|
399
|
-
* Fetch a message by ID.
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
490
|
+
* Fetch a CCIP message by its unique message ID.
|
|
491
|
+
*
|
|
492
|
+
* @remarks
|
|
493
|
+
* Uses the CCIP API to retrieve message details. The returned request includes
|
|
494
|
+
* a `metadata` field with API-specific information.
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* ```typescript
|
|
498
|
+
* const request = await chain.getMessageById(messageId)
|
|
499
|
+
* console.log(`Sender: ${request.message.sender}`)
|
|
500
|
+
*
|
|
501
|
+
* if (request.metadata) {
|
|
502
|
+
* console.log(`Status: ${request.metadata.status}`)
|
|
503
|
+
* if (request.metadata.deliveryTime) {
|
|
504
|
+
* console.log(`Delivered in ${request.metadata.deliveryTime}ms`)
|
|
505
|
+
* }
|
|
506
|
+
* }
|
|
507
|
+
* ```
|
|
508
|
+
*
|
|
509
|
+
* @param messageId - The unique message ID (0x + 64 hex chars)
|
|
510
|
+
* @param _opts - Optional: `onRamp` hint for non-EVM chains
|
|
511
|
+
* @returns CCIPRequest with `metadata` populated from API
|
|
512
|
+
* @throws {@link CCIPApiClientNotAvailableError} if API disabled
|
|
513
|
+
* @throws {@link CCIPMessageIdNotFoundError} if message not found
|
|
514
|
+
* @throws {@link CCIPHttpError} if API request fails
|
|
405
515
|
**/
|
|
406
516
|
async getMessageById(
|
|
407
517
|
messageId: string,
|
|
@@ -420,6 +530,8 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
420
530
|
* @param request - CCIPRequest to fetch batch for.
|
|
421
531
|
* @param commit - CommitReport range (min, max).
|
|
422
532
|
* @param opts - Optional parameters (e.g., `page` for pagination width).
|
|
533
|
+
* @returns Array of messages in the batch.
|
|
534
|
+
* @throws {@link CCIPMessageBatchIncompleteError} if not all messages in range could be fetched
|
|
423
535
|
*/
|
|
424
536
|
abstract getMessagesInBatch<
|
|
425
537
|
R extends PickDeep<
|
|
@@ -438,6 +550,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
438
550
|
* @returns version - parsed version of the contract, e.g. `1.6.0`
|
|
439
551
|
* @returns typeAndVersion - original (unparsed) typeAndVersion() string
|
|
440
552
|
* @returns suffix - suffix of the version, if any (e.g. `-dev`)
|
|
553
|
+
* @throws {@link CCIPTypeVersionInvalidError} if contract doesn't have valid typeAndVersion
|
|
441
554
|
*/
|
|
442
555
|
abstract typeAndVersion(
|
|
443
556
|
address: string,
|
|
@@ -532,12 +645,14 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
532
645
|
/**
|
|
533
646
|
* Fetch TokenAdminRegistry configured in a given OnRamp, Router, etc
|
|
534
647
|
* Needed to map a source token to its dest counterparts
|
|
535
|
-
* @param
|
|
648
|
+
* @param address - Some contract for which we can fetch a TokenAdminRegistry (OnRamp, Router, etc.)
|
|
649
|
+
* @returns TokenAdminRegistry address
|
|
536
650
|
*/
|
|
537
651
|
abstract getTokenAdminRegistryFor(address: string): Promise<string>
|
|
538
652
|
/**
|
|
539
653
|
* Fetch the current fee for a given intended message
|
|
540
654
|
* @param opts - {@link SendMessageOpts} without approveMax
|
|
655
|
+
* @returns Fee amount in the feeToken's smallest units
|
|
541
656
|
*/
|
|
542
657
|
abstract getFee(opts: Omit<SendMessageOpts, 'approveMax'>): Promise<bigint>
|
|
543
658
|
/**
|
|
@@ -555,6 +670,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
555
670
|
* Send a CCIP message through a router using provided wallet.
|
|
556
671
|
* @param opts - {@link SendMessageOpts} with chain-specific wallet for signing
|
|
557
672
|
* @returns CCIP request
|
|
673
|
+
* @throws {@link CCIPWalletNotSignerError} if wallet cannot sign transactions
|
|
558
674
|
*
|
|
559
675
|
* @example
|
|
560
676
|
* ```typescript
|
|
@@ -620,6 +736,8 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
620
736
|
* })
|
|
621
737
|
* console.log(`Message ID: ${request.message.messageId}`)
|
|
622
738
|
* ```
|
|
739
|
+
* @throws {@link CCIPWalletNotSignerError} if wallet cannot sign transactions
|
|
740
|
+
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
|
|
623
741
|
*/
|
|
624
742
|
abstract executeReport(
|
|
625
743
|
opts: ExecuteReportOpts & {
|
|
@@ -632,8 +750,9 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
632
750
|
* Look for a CommitReport at dest for given CCIP request
|
|
633
751
|
* May be specialized by some subclasses
|
|
634
752
|
* @param opts - getCommitReport options
|
|
635
|
-
* @returns CCIPCommit info
|
|
636
|
-
|
|
753
|
+
* @returns CCIPCommit info
|
|
754
|
+
* @throws {@link CCIPCommitNotFoundError} if no commit found for the request
|
|
755
|
+
*/
|
|
637
756
|
async getCommitReport({
|
|
638
757
|
commitStore,
|
|
639
758
|
request,
|
|
@@ -739,6 +858,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
739
858
|
* @internal
|
|
740
859
|
* @param tx - transaction hash or transaction object
|
|
741
860
|
* @returns CCIP execution object
|
|
861
|
+
* @throws {@link CCIPExecTxRevertedError} if no execution receipt found in transaction
|
|
742
862
|
*/
|
|
743
863
|
async getExecutionReceiptInTx(tx: string | ChainTransaction): Promise<CCIPExecution> {
|
|
744
864
|
if (typeof tx === 'string') tx = await this.getTransaction(tx)
|
|
@@ -761,39 +881,125 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
761
881
|
abstract getSupportedTokens(address: string, opts?: { page?: number }): Promise<string[]>
|
|
762
882
|
|
|
763
883
|
/**
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
* @
|
|
884
|
+
* Fetch token configuration from a TokenAdminRegistry.
|
|
885
|
+
*
|
|
886
|
+
* @remarks
|
|
887
|
+
* The TokenAdminRegistry is a contract that tracks token administrators and their
|
|
888
|
+
* associated pools. Each token has an administrator who can update pool configurations.
|
|
889
|
+
*
|
|
890
|
+
* @example Query a token's registry configuration
|
|
891
|
+
* ```typescript
|
|
892
|
+
* const config = await chain.getRegistryTokenConfig(registryAddress, tokenAddress)
|
|
893
|
+
* console.log(`Administrator: ${config.administrator}`)
|
|
894
|
+
* if (config.tokenPool) {
|
|
895
|
+
* console.log(`Pool: ${config.tokenPool}`)
|
|
896
|
+
* }
|
|
897
|
+
* ```
|
|
898
|
+
*
|
|
899
|
+
* @param registry - TokenAdminRegistry contract address.
|
|
900
|
+
* @param token - Token address to query.
|
|
901
|
+
* @returns {@link RegistryTokenConfig} containing administrator and pool information.
|
|
902
|
+
* @throws {@link CCIPTokenNotInRegistryError} if token is not registered.
|
|
767
903
|
*/
|
|
768
|
-
abstract getRegistryTokenConfig(
|
|
769
|
-
registry: string,
|
|
770
|
-
token: string,
|
|
771
|
-
): Promise<{
|
|
772
|
-
administrator: string
|
|
773
|
-
pendingAdministrator?: string
|
|
774
|
-
tokenPool?: string
|
|
775
|
-
}>
|
|
904
|
+
abstract getRegistryTokenConfig(registry: string, token: string): Promise<RegistryTokenConfig>
|
|
776
905
|
|
|
777
906
|
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
907
|
+
* Fetch configuration of a token pool.
|
|
908
|
+
*
|
|
909
|
+
* @remarks
|
|
910
|
+
* Returns the core configuration of a token pool including which token it manages
|
|
911
|
+
* and which router it's registered with.
|
|
912
|
+
*
|
|
913
|
+
* @example Query pool configuration
|
|
914
|
+
* ```typescript
|
|
915
|
+
* const config = await chain.getTokenPoolConfig(poolAddress)
|
|
916
|
+
* console.log(`Manages token: ${config.token}`)
|
|
917
|
+
* console.log(`Router: ${config.router}`)
|
|
918
|
+
* if (config.typeAndVersion) {
|
|
919
|
+
* console.log(`Version: ${config.typeAndVersion}`)
|
|
920
|
+
* }
|
|
921
|
+
* ```
|
|
922
|
+
*
|
|
923
|
+
* @param tokenPool - Token pool contract address.
|
|
924
|
+
* @returns {@link TokenPoolConfig} containing token, router, and version info.
|
|
780
925
|
*/
|
|
781
|
-
abstract
|
|
782
|
-
token: string
|
|
783
|
-
router: string
|
|
784
|
-
typeAndVersion?: string
|
|
785
|
-
}>
|
|
926
|
+
abstract getTokenPoolConfig(tokenPool: string): Promise<TokenPoolConfig>
|
|
786
927
|
|
|
787
928
|
/**
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
* @
|
|
791
|
-
*
|
|
929
|
+
* Fetch remote chain configurations for a token pool.
|
|
930
|
+
*
|
|
931
|
+
* @remarks
|
|
932
|
+
* A token pool maintains configurations for each destination chain it supports.
|
|
933
|
+
* The returned Record maps chain names to their respective configurations.
|
|
934
|
+
*
|
|
935
|
+
* @example Get all supported destinations
|
|
936
|
+
* ```typescript
|
|
937
|
+
* const remotes = await chain.getTokenPoolRemotes(poolAddress)
|
|
938
|
+
* // Returns: {
|
|
939
|
+
* // "ethereum-mainnet": { remoteToken: "0x...", remotePools: [...], ... },
|
|
940
|
+
* // "ethereum-mainnet-arbitrum-1": { remoteToken: "0x...", remotePools: [...], ... },
|
|
941
|
+
* // "solana-mainnet": { remoteToken: "...", remotePools: [...], ... }
|
|
942
|
+
* // }
|
|
943
|
+
*
|
|
944
|
+
* // Access a specific chain's config
|
|
945
|
+
* const arbConfig = remotes['ethereum-mainnet']
|
|
946
|
+
* console.log(`Remote token: ${arbConfig.remoteToken}`)
|
|
947
|
+
* ```
|
|
948
|
+
*
|
|
949
|
+
* @example Filter to a specific destination
|
|
950
|
+
* ```typescript
|
|
951
|
+
* import { networkInfo } from '@chainlink/ccip-sdk'
|
|
952
|
+
*
|
|
953
|
+
* const arbitrumSelector = 4949039107694359620n
|
|
954
|
+
* const remotes = await chain.getTokenPoolRemotes(poolAddress, arbitrumSelector)
|
|
955
|
+
* // Returns only: { "arbitrum-mainnet": { ... } }
|
|
956
|
+
*
|
|
957
|
+
* const chainName = networkInfo(arbitrumSelector).name
|
|
958
|
+
* const config = remotes[chainName]
|
|
959
|
+
* ```
|
|
960
|
+
*
|
|
961
|
+
* @param tokenPool - Token pool address on the current chain.
|
|
962
|
+
* @param remoteChainSelector - Optional chain selector to filter results to a single destination.
|
|
963
|
+
* @returns Record where keys are chain names (e.g., "ethereum-mainnet") and values are {@link TokenPoolRemote} configs.
|
|
964
|
+
* @throws {@link CCIPTokenPoolChainConfigNotFoundError} if remoteChainSelector is specified but not configured.
|
|
792
965
|
*/
|
|
793
966
|
abstract getTokenPoolRemotes(
|
|
794
967
|
tokenPool: string,
|
|
795
968
|
remoteChainSelector?: bigint,
|
|
796
969
|
): Promise<Record<string, TokenPoolRemote>>
|
|
970
|
+
/**
|
|
971
|
+
* Fetch remote chain configuration for a token pool for a specific destination.
|
|
972
|
+
*
|
|
973
|
+
* @remarks
|
|
974
|
+
* Convenience wrapper around {@link getTokenPoolRemotes} that returns a single
|
|
975
|
+
* configuration instead of a Record. Use this when you need configuration for
|
|
976
|
+
* a specific destination chain.
|
|
977
|
+
*
|
|
978
|
+
* @example
|
|
979
|
+
* ```typescript
|
|
980
|
+
* const arbitrumSelector = 4949039107694359620n
|
|
981
|
+
* const remote = await chain.getTokenPoolRemote(poolAddress, arbitrumSelector)
|
|
982
|
+
* console.log(`Remote token: ${remote.remoteToken}`)
|
|
983
|
+
* console.log(`Remote pools: ${remote.remotePools.join(', ')}`)
|
|
984
|
+
* ```
|
|
985
|
+
*
|
|
986
|
+
* @param tokenPool - Token pool address on the current chain.
|
|
987
|
+
* @param remoteChainSelector - Chain selector of the desired remote chain.
|
|
988
|
+
* @returns TokenPoolRemote config for the specified remote chain.
|
|
989
|
+
* @throws {@link CCIPTokenPoolChainConfigNotFoundError} if no configuration found for the specified remote chain.
|
|
990
|
+
*/
|
|
991
|
+
async getTokenPoolRemote(
|
|
992
|
+
tokenPool: string,
|
|
993
|
+
remoteChainSelector: bigint,
|
|
994
|
+
): Promise<TokenPoolRemote> {
|
|
995
|
+
const remotes = await this.getTokenPoolRemotes(tokenPool, remoteChainSelector)
|
|
996
|
+
const network = networkInfo(remoteChainSelector)
|
|
997
|
+
const remoteConfig = remotes[network.name]
|
|
998
|
+
if (!remoteConfig) {
|
|
999
|
+
throw new CCIPTokenPoolChainConfigNotFoundError(tokenPool, tokenPool, network.name)
|
|
1000
|
+
}
|
|
1001
|
+
return remoteConfig
|
|
1002
|
+
}
|
|
797
1003
|
|
|
798
1004
|
/**
|
|
799
1005
|
* Fetch list and info of supported feeTokens.
|
|
@@ -806,11 +1012,32 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
806
1012
|
static buildMessageForDest(
|
|
807
1013
|
message: Parameters<ChainStatic['buildMessageForDest']>[0],
|
|
808
1014
|
): AnyMessage {
|
|
809
|
-
|
|
1015
|
+
const gasLimit = message.data && dataLength(message.data) ? DEFAULT_GAS_LIMIT : 0n
|
|
1016
|
+
|
|
1017
|
+
// Detect if user wants V3 by checking for any V3-only field
|
|
1018
|
+
if (hasV3ExtraArgs(message.extraArgs)) {
|
|
1019
|
+
// V3 defaults (GenericExtraArgsV3)
|
|
1020
|
+
return {
|
|
1021
|
+
...message,
|
|
1022
|
+
extraArgs: {
|
|
1023
|
+
gasLimit,
|
|
1024
|
+
blockConfirmations: 0,
|
|
1025
|
+
ccvs: [],
|
|
1026
|
+
ccvArgs: [],
|
|
1027
|
+
executor: '',
|
|
1028
|
+
executorArgs: '0x',
|
|
1029
|
+
tokenReceiver: '',
|
|
1030
|
+
tokenArgs: '0x',
|
|
1031
|
+
...message.extraArgs,
|
|
1032
|
+
},
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// Default to V2 (GenericExtraArgsV2, aka EVMExtraArgsV2)
|
|
810
1037
|
return {
|
|
811
1038
|
...message,
|
|
812
1039
|
extraArgs: {
|
|
813
|
-
gasLimit
|
|
1040
|
+
gasLimit,
|
|
814
1041
|
allowOutOfOrderExecution: true,
|
|
815
1042
|
...message.extraArgs,
|
|
816
1043
|
},
|
|
@@ -868,6 +1095,7 @@ export type ChainStatic<F extends ChainFamily = ChainFamily> = Function & {
|
|
|
868
1095
|
):
|
|
869
1096
|
| (EVMExtraArgsV1 & { _tag: 'EVMExtraArgsV1' })
|
|
870
1097
|
| (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
|
|
1098
|
+
| (GenericExtraArgsV3 & { _tag: 'GenericExtraArgsV3' })
|
|
871
1099
|
| (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
|
|
872
1100
|
| (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
|
|
873
1101
|
| undefined
|
|
@@ -880,7 +1108,7 @@ export type ChainStatic<F extends ChainFamily = ChainFamily> = Function & {
|
|
|
880
1108
|
*/
|
|
881
1109
|
decodeCommits(log: Pick<Log_, 'data'>, lane?: Lane): CommitReport[] | undefined
|
|
882
1110
|
/**
|
|
883
|
-
* Decode a receipt (
|
|
1111
|
+
* Decode a receipt (ExecutionStateChanged) event
|
|
884
1112
|
* @param log - Chain generic log
|
|
885
1113
|
* @returns ExecutionReceipt or undefined if not a recognized receipt
|
|
886
1114
|
*/
|
package/src/errors/codes.ts
CHANGED
|
@@ -80,6 +80,7 @@ export const CCIPErrorCode = {
|
|
|
80
80
|
TOKEN_NOT_IN_REGISTRY: 'TOKEN_NOT_IN_REGISTRY',
|
|
81
81
|
TOKEN_NOT_CONFIGURED: 'TOKEN_NOT_CONFIGURED',
|
|
82
82
|
TOKEN_NOT_REGISTERED: 'TOKEN_NOT_REGISTERED',
|
|
83
|
+
TOKEN_REMOTE_NOT_CONFIGURED: 'TOKEN_REMOTE_NOT_CONFIGURED',
|
|
83
84
|
TOKEN_DECIMALS_INSUFFICIENT: 'TOKEN_DECIMALS_INSUFFICIENT',
|
|
84
85
|
TOKEN_INVALID_SPL: 'TOKEN_INVALID_SPL',
|
|
85
86
|
TOKEN_DATA_PARSE_FAILED: 'TOKEN_DATA_PARSE_FAILED',
|
|
@@ -153,6 +154,7 @@ export const CCIPErrorCode = {
|
|
|
153
154
|
|
|
154
155
|
// CLI & Validation
|
|
155
156
|
ARGUMENT_INVALID: 'ARGUMENT_INVALID',
|
|
157
|
+
INSUFFICIENT_BALANCE: 'INSUFFICIENT_BALANCE',
|
|
156
158
|
|
|
157
159
|
// Internal
|
|
158
160
|
NOT_IMPLEMENTED: 'NOT_IMPLEMENTED',
|
package/src/errors/index.ts
CHANGED
|
@@ -179,7 +179,7 @@ export { CCIPAddressInvalidEvmError } from './specialized.ts'
|
|
|
179
179
|
export { CCIPSourceChainUnsupportedError } from './specialized.ts'
|
|
180
180
|
|
|
181
181
|
// Specialized errors - CLI & Validation
|
|
182
|
-
export { CCIPArgumentInvalidError } from './specialized.ts'
|
|
182
|
+
export { CCIPArgumentInvalidError, CCIPInsufficientBalanceError } from './specialized.ts'
|
|
183
183
|
|
|
184
184
|
// HTTP Status codes (re-exported from root)
|
|
185
185
|
export { HttpStatus, isServerError, isTransientHttpStatus } from '../http-status.ts'
|
package/src/errors/recovery.ts
CHANGED
|
@@ -96,6 +96,7 @@ export const DEFAULT_RECOVERY_HINTS: Partial<Record<CCIPErrorCode, string>> = {
|
|
|
96
96
|
TOKEN_NOT_IN_REGISTRY: 'Token not found in TokenAdminRegistry.',
|
|
97
97
|
TOKEN_NOT_CONFIGURED: 'Token is not configured in the registry.',
|
|
98
98
|
TOKEN_NOT_REGISTERED: 'Token is not registered in the TokenAdminRegistry.',
|
|
99
|
+
TOKEN_REMOTE_NOT_CONFIGURED: 'Remote network is not registered in TokenPool.',
|
|
99
100
|
TOKEN_DECIMALS_INSUFFICIENT: 'Destination token has insufficient decimals.',
|
|
100
101
|
TOKEN_INVALID_SPL: 'Invalid SPL token or Token-2022.',
|
|
101
102
|
TOKEN_DATA_PARSE_FAILED:
|
|
@@ -178,6 +179,7 @@ export const DEFAULT_RECOVERY_HINTS: Partial<Record<CCIPErrorCode, string>> = {
|
|
|
178
179
|
BORSH_METHOD_UNKNOWN: 'Unknown Borsh method.',
|
|
179
180
|
|
|
180
181
|
ARGUMENT_INVALID: 'Check the command-line argument format and requirements.',
|
|
182
|
+
INSUFFICIENT_BALANCE: 'Fund the wallet to cover the transaction fee.',
|
|
181
183
|
|
|
182
184
|
NOT_IMPLEMENTED: 'This feature is not yet implemented.',
|
|
183
185
|
UNKNOWN: 'An unknown error occurred. Check the error details.',
|
|
@@ -30,10 +30,10 @@ export class CCIPChainFamilyUnsupportedError extends CCIPError {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/** Thrown when some method/operation is not supported on a given
|
|
33
|
+
/** Thrown when some method/operation is not supported on a given implementation class. */
|
|
34
34
|
export class CCIPMethodUnsupportedError extends CCIPError {
|
|
35
35
|
override readonly name = 'CCIPMethodUnsupportedError'
|
|
36
|
-
/** Creates a method
|
|
36
|
+
/** Creates a method unsupported error. */
|
|
37
37
|
constructor(klass: string, method: string, options?: CCIPErrorOptions) {
|
|
38
38
|
super(CCIPErrorCode.METHOD_UNSUPPORTED, `Unsupported method in class: ${klass}.${method}`, {
|
|
39
39
|
...options,
|
|
@@ -776,7 +776,7 @@ export class CCIPLogTopicsNotFoundError extends CCIPError {
|
|
|
776
776
|
/** Thrown when trying to `watch` logs but giving a fixed `endBlock` */
|
|
777
777
|
export class CCIPLogsWatchRequiresFinalityError extends CCIPError {
|
|
778
778
|
override readonly name = 'CCIPLogsWatchRequiresFinalityError'
|
|
779
|
-
/** Creates a
|
|
779
|
+
/** Creates a watch requires finality error. */
|
|
780
780
|
constructor(endBlock?: number | string, options?: CCIPErrorOptions) {
|
|
781
781
|
super(
|
|
782
782
|
CCIPErrorCode.LOGS_WATCH_REQUIRES_FINALITY,
|
|
@@ -786,10 +786,10 @@ export class CCIPLogsWatchRequiresFinalityError extends CCIPError {
|
|
|
786
786
|
}
|
|
787
787
|
}
|
|
788
788
|
|
|
789
|
-
/** Thrown when trying to `watch` logs
|
|
789
|
+
/** Thrown when trying to `watch` logs without a start point. */
|
|
790
790
|
export class CCIPLogsWatchRequiresStartError extends CCIPError {
|
|
791
791
|
override readonly name = 'CCIPLogsWatchRequiresStartError'
|
|
792
|
-
/** Creates a
|
|
792
|
+
/** Creates a watch requires start error. */
|
|
793
793
|
constructor(options?: CCIPErrorOptions) {
|
|
794
794
|
super(CCIPErrorCode.LOGS_WATCH_REQUIRES_START, `Watch mode requires startBlock or startTime`, {
|
|
795
795
|
...options,
|
|
@@ -1255,7 +1255,7 @@ export class CCIPTokenPoolChainConfigNotFoundError extends CCIPError {
|
|
|
1255
1255
|
options?: CCIPErrorOptions,
|
|
1256
1256
|
) {
|
|
1257
1257
|
super(
|
|
1258
|
-
CCIPErrorCode.
|
|
1258
|
+
CCIPErrorCode.TOKEN_REMOTE_NOT_CONFIGURED,
|
|
1259
1259
|
`ChainConfig not found at ${address} for tokenPool=${tokenPool} and remoteNetwork=${remoteNetwork}`,
|
|
1260
1260
|
{
|
|
1261
1261
|
...options,
|
|
@@ -1515,6 +1515,23 @@ export class CCIPTokenNotFoundError extends CCIPError {
|
|
|
1515
1515
|
}
|
|
1516
1516
|
}
|
|
1517
1517
|
|
|
1518
|
+
/** Thrown when account has insufficient balance for operation. */
|
|
1519
|
+
export class CCIPInsufficientBalanceError extends CCIPError {
|
|
1520
|
+
override readonly name = 'CCIPInsufficientBalanceError'
|
|
1521
|
+
/** Creates an insufficient balance error. */
|
|
1522
|
+
constructor(have: string, need: string, symbol: string, options?: CCIPErrorOptions) {
|
|
1523
|
+
super(
|
|
1524
|
+
CCIPErrorCode.INSUFFICIENT_BALANCE,
|
|
1525
|
+
`Insufficient balance: have ${have} ${symbol}, need ${need} ${symbol}`,
|
|
1526
|
+
{
|
|
1527
|
+
...options,
|
|
1528
|
+
isTransient: false,
|
|
1529
|
+
context: { ...options?.context, have, need, symbol },
|
|
1530
|
+
},
|
|
1531
|
+
)
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1518
1535
|
// Solana-specific (additional)
|
|
1519
1536
|
|
|
1520
1537
|
/** Thrown when router config not found at PDA. */
|
|
@@ -1679,7 +1696,7 @@ export class CCIPSuiMessageVersionInvalidError extends CCIPError {
|
|
|
1679
1696
|
/** Thrown when Sui log data is invalid. */
|
|
1680
1697
|
export class CCIPSuiLogInvalidError extends CCIPError {
|
|
1681
1698
|
override readonly name = 'CCIPSuiLogInvalidError'
|
|
1682
|
-
/** Creates
|
|
1699
|
+
/** Creates a Sui log invalid error. */
|
|
1683
1700
|
constructor(log: unknown, options?: CCIPErrorOptions) {
|
|
1684
1701
|
super(CCIPErrorCode.LOG_DATA_INVALID, `Invalid sui log: ${String(log)}`, {
|
|
1685
1702
|
...options,
|