@chainlink/ccip-sdk 0.95.0 → 0.97.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 +31 -19
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +46 -25
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +24 -30
- package/dist/api/types.d.ts.map +1 -1
- package/dist/aptos/exec.d.ts +2 -2
- package/dist/aptos/exec.d.ts.map +1 -1
- package/dist/aptos/exec.js.map +1 -1
- package/dist/aptos/hasher.d.ts.map +1 -1
- package/dist/aptos/hasher.js +1 -1
- package/dist/aptos/hasher.js.map +1 -1
- package/dist/aptos/index.d.ts +43 -15
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +112 -105
- package/dist/aptos/index.js.map +1 -1
- package/dist/aptos/types.d.ts +2 -19
- package/dist/aptos/types.d.ts.map +1 -1
- package/dist/aptos/types.js +0 -11
- package/dist/aptos/types.js.map +1 -1
- package/dist/chain.d.ts +734 -174
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +216 -31
- package/dist/chain.js.map +1 -1
- package/dist/commits.d.ts +4 -6
- package/dist/commits.d.ts.map +1 -1
- package/dist/commits.js +4 -4
- package/dist/commits.js.map +1 -1
- package/dist/errors/CCIPError.d.ts +33 -4
- package/dist/errors/CCIPError.d.ts.map +1 -1
- package/dist/errors/CCIPError.js +33 -4
- package/dist/errors/CCIPError.js.map +1 -1
- package/dist/errors/codes.d.ts +5 -0
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +5 -1
- package/dist/errors/codes.js.map +1 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +2 -2
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/recovery.d.ts.map +1 -1
- package/dist/errors/recovery.js +6 -1
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +1702 -121
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +1729 -125
- package/dist/errors/specialized.js.map +1 -1
- package/dist/errors/utils.d.ts.map +1 -1
- package/dist/errors/utils.js +0 -1
- package/dist/errors/utils.js.map +1 -1
- package/dist/evm/abi/OffRamp_2_0.d.ts +764 -0
- package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -0
- package/dist/evm/abi/OffRamp_2_0.js +744 -0
- package/dist/evm/abi/OffRamp_2_0.js.map +1 -0
- package/dist/evm/abi/OnRamp_2_0.d.ts +925 -0
- package/dist/evm/abi/OnRamp_2_0.d.ts.map +1 -0
- package/dist/evm/abi/OnRamp_2_0.js +992 -0
- package/dist/evm/abi/OnRamp_2_0.js.map +1 -0
- package/dist/evm/const.d.ts +12 -2
- package/dist/evm/const.d.ts.map +1 -1
- package/dist/evm/const.js +8 -2
- package/dist/evm/const.js.map +1 -1
- package/dist/evm/errors.d.ts.map +1 -1
- package/dist/evm/errors.js +7 -2
- package/dist/evm/errors.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 +309 -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/hasher.d.ts.map +1 -1
- package/dist/evm/hasher.js +23 -13
- package/dist/evm/hasher.js.map +1 -1
- package/dist/evm/index.d.ts +140 -35
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +306 -226
- package/dist/evm/index.js.map +1 -1
- package/dist/evm/messages.d.ts +59 -5
- package/dist/evm/messages.d.ts.map +1 -1
- package/dist/evm/messages.js +210 -0
- package/dist/evm/messages.js.map +1 -1
- package/dist/evm/offchain.js.map +1 -1
- package/dist/evm/types.d.ts +7 -2
- package/dist/evm/types.d.ts.map +1 -1
- package/dist/evm/types.js +22 -1
- package/dist/evm/types.js.map +1 -1
- package/dist/execution.d.ts +62 -22
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +102 -51
- package/dist/execution.js.map +1 -1
- package/dist/extra-args.d.ts +113 -4
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +38 -3
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts +31 -5
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +43 -9
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +11 -10
- 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 +101 -22
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +115 -24
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +24 -0
- package/dist/selectors.js.map +1 -1
- package/dist/shared/bcs-codecs.d.ts +61 -0
- package/dist/shared/bcs-codecs.d.ts.map +1 -0
- package/dist/shared/bcs-codecs.js +102 -0
- package/dist/shared/bcs-codecs.js.map +1 -0
- package/dist/shared/constants.d.ts +3 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +3 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/solana/exec.d.ts +2 -2
- package/dist/solana/exec.d.ts.map +1 -1
- package/dist/solana/exec.js.map +1 -1
- package/dist/solana/index.d.ts +148 -30
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +137 -44
- package/dist/solana/index.js.map +1 -1
- package/dist/sui/hasher.d.ts.map +1 -1
- package/dist/sui/hasher.js +1 -1
- package/dist/sui/hasher.js.map +1 -1
- package/dist/sui/index.d.ts +49 -19
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +76 -43
- package/dist/sui/index.js.map +1 -1
- package/dist/sui/manuallyExec/encoder.d.ts +2 -2
- package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
- package/dist/sui/manuallyExec/encoder.js.map +1 -1
- package/dist/sui/manuallyExec/index.d.ts +2 -2
- package/dist/sui/manuallyExec/index.d.ts.map +1 -1
- package/dist/ton/exec.d.ts +2 -2
- package/dist/ton/exec.d.ts.map +1 -1
- package/dist/ton/exec.js.map +1 -1
- package/dist/ton/index.d.ts +66 -27
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +172 -47
- 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/types.d.ts +2 -2
- package/dist/ton/types.d.ts.map +1 -1
- package/dist/ton/types.js.map +1 -1
- package/dist/types.d.ts +148 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +79 -4
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +92 -7
- package/dist/utils.js.map +1 -1
- package/package.json +16 -11
- package/src/all-chains.ts +26 -0
- package/src/api/index.ts +58 -34
- package/src/api/types.ts +24 -31
- package/src/aptos/exec.ts +2 -2
- package/src/aptos/hasher.ts +1 -1
- package/src/aptos/index.ts +127 -129
- package/src/aptos/types.ts +2 -15
- package/src/chain.ts +837 -191
- package/src/commits.ts +9 -9
- package/src/errors/CCIPError.ts +33 -4
- package/src/errors/codes.ts +5 -1
- package/src/errors/index.ts +2 -1
- package/src/errors/recovery.ts +9 -1
- package/src/errors/specialized.ts +1745 -132
- package/src/errors/utils.ts +0 -1
- package/src/evm/abi/OffRamp_2_0.ts +743 -0
- package/src/evm/abi/OnRamp_2_0.ts +991 -0
- package/src/evm/const.ts +10 -3
- package/src/evm/errors.ts +6 -2
- package/src/evm/extra-args.ts +360 -0
- package/src/evm/gas.ts +14 -13
- package/src/evm/hasher.ts +30 -18
- package/src/evm/index.ts +376 -281
- package/src/evm/messages.ts +323 -11
- package/src/evm/offchain.ts +2 -2
- package/src/evm/types.ts +20 -2
- package/src/execution.ts +126 -71
- package/src/extra-args.ts +118 -4
- package/src/gas.ts +44 -11
- package/src/index.ts +14 -11
- package/src/requests.ts +128 -24
- package/src/selectors.ts +24 -0
- package/src/shared/bcs-codecs.ts +132 -0
- package/src/shared/constants.ts +2 -0
- package/src/solana/exec.ts +4 -4
- package/src/solana/index.ts +170 -82
- package/src/sui/hasher.ts +1 -1
- package/src/sui/index.ts +88 -56
- package/src/sui/manuallyExec/encoder.ts +2 -2
- package/src/sui/manuallyExec/index.ts +2 -2
- package/src/ton/exec.ts +2 -2
- package/src/ton/index.ts +220 -58
- package/src/ton/send.ts +222 -0
- package/src/ton/types.ts +2 -2
- package/src/types.ts +173 -30
- package/src/utils.ts +91 -7
- package/dist/aptos/utils.d.ts +0 -12
- package/dist/aptos/utils.d.ts.map +0 -1
- package/dist/aptos/utils.js +0 -15
- package/dist/aptos/utils.js.map +0 -1
- package/src/aptos/utils.ts +0 -24
package/src/chain.ts
CHANGED
|
@@ -3,37 +3,41 @@ import type { PickDeep, SetOptional } from 'type-fest'
|
|
|
3
3
|
|
|
4
4
|
import { type LaneLatencyResponse, CCIPAPIClient } from './api/index.ts'
|
|
5
5
|
import type { UnsignedAptosTx } from './aptos/types.ts'
|
|
6
|
-
import {
|
|
6
|
+
import { getOnchainCommitReport } from './commits.ts'
|
|
7
7
|
import {
|
|
8
8
|
CCIPApiClientNotAvailableError,
|
|
9
9
|
CCIPChainFamilyMismatchError,
|
|
10
10
|
CCIPExecTxRevertedError,
|
|
11
|
+
CCIPTokenPoolChainConfigNotFoundError,
|
|
11
12
|
CCIPTransactionNotFinalizedError,
|
|
12
13
|
} from './errors/index.ts'
|
|
13
|
-
import { DEFAULT_GAS_LIMIT } from './evm/const.ts'
|
|
14
14
|
import type { UnsignedEVMTx } from './evm/types.ts'
|
|
15
|
+
import { calculateManualExecProof } from './execution.ts'
|
|
15
16
|
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'
|
|
22
24
|
import type { LeafHasher } from './hasher/common.ts'
|
|
23
25
|
import { getMessagesInTx } from './requests.ts'
|
|
26
|
+
import { DEFAULT_GAS_LIMIT } from './shared/constants.ts'
|
|
24
27
|
import type { UnsignedSolanaTx } from './solana/types.ts'
|
|
25
28
|
import type { UnsignedTONTx } from './ton/types.ts'
|
|
26
29
|
import {
|
|
27
30
|
type AnyMessage,
|
|
28
|
-
type CCIPCommit,
|
|
29
31
|
type CCIPExecution,
|
|
30
32
|
type CCIPMessage,
|
|
31
33
|
type CCIPRequest,
|
|
34
|
+
type CCIPVerifications,
|
|
35
|
+
type CCIPVersion,
|
|
32
36
|
type ChainFamily,
|
|
33
37
|
type ChainTransaction,
|
|
34
38
|
type CommitReport,
|
|
39
|
+
type ExecutionInput,
|
|
35
40
|
type ExecutionReceipt,
|
|
36
|
-
type ExecutionReport,
|
|
37
41
|
type Lane,
|
|
38
42
|
type Log_,
|
|
39
43
|
type Logger,
|
|
@@ -43,7 +47,24 @@ import {
|
|
|
43
47
|
type WithLogger,
|
|
44
48
|
ExecutionState,
|
|
45
49
|
} from './types.ts'
|
|
46
|
-
import { util, withRetry } from './utils.ts'
|
|
50
|
+
import { networkInfo, util, withRetry } from './utils.ts'
|
|
51
|
+
|
|
52
|
+
/** Field names unique to GenericExtraArgsV3 (not present in V2). */
|
|
53
|
+
const V3_ONLY_FIELDS = [
|
|
54
|
+
'blockConfirmations',
|
|
55
|
+
'ccvs',
|
|
56
|
+
'ccvArgs',
|
|
57
|
+
'executor',
|
|
58
|
+
'executorArgs',
|
|
59
|
+
'tokenReceiver',
|
|
60
|
+
'tokenArgs',
|
|
61
|
+
] as const
|
|
62
|
+
|
|
63
|
+
/** Check if extraArgs contains any V3-only fields. */
|
|
64
|
+
function hasV3ExtraArgs(extraArgs: Partial<ExtraArgs> | undefined): boolean {
|
|
65
|
+
if (!extraArgs) return false
|
|
66
|
+
return V3_ONLY_FIELDS.some((field) => field in extraArgs)
|
|
67
|
+
}
|
|
47
68
|
|
|
48
69
|
/**
|
|
49
70
|
* Context for Chain class initialization.
|
|
@@ -57,7 +78,7 @@ import { util, withRetry } from './utils.ts'
|
|
|
57
78
|
*
|
|
58
79
|
* @example Custom API endpoint
|
|
59
80
|
* ```typescript
|
|
60
|
-
* const api =
|
|
81
|
+
* const api = CCIPAPIClient.fromUrl('https://staging-api.example.com', { logger })
|
|
61
82
|
* const chain = await EVMChain.fromUrl(rpcUrl, { apiClient: api, logger })
|
|
62
83
|
* ```
|
|
63
84
|
*
|
|
@@ -71,8 +92,7 @@ export type ChainContext = WithLogger & {
|
|
|
71
92
|
/**
|
|
72
93
|
* CCIP API client instance for lane information queries.
|
|
73
94
|
*
|
|
74
|
-
* - `undefined` (default): Creates CCIPAPIClient with
|
|
75
|
-
* (https://api.ccip.chain.link)
|
|
95
|
+
* - `undefined` (default): Creates CCIPAPIClient with {@link DEFAULT_API_BASE_URL}
|
|
76
96
|
* - `CCIPAPIClient`: Uses provided instance (allows custom URL, fetch, etc.)
|
|
77
97
|
* - `null`: Disables API client entirely (getLaneLatency() will throw)
|
|
78
98
|
*
|
|
@@ -164,24 +184,51 @@ export type GetBalanceOpts = {
|
|
|
164
184
|
|
|
165
185
|
/**
|
|
166
186
|
* Rate limiter state for token pool configurations.
|
|
167
|
-
*
|
|
187
|
+
*
|
|
188
|
+
* @remarks
|
|
189
|
+
* - Returns the rate limiter bucket state when rate limiting is **enabled**
|
|
190
|
+
* - Returns `null` when rate limiting is **disabled** (unlimited throughput)
|
|
191
|
+
*
|
|
192
|
+
* @example Handling nullable state
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const remote = await chain.getTokenPoolRemotes(poolAddress)
|
|
195
|
+
* const state = remote['ethereum-mainnet'].inboundRateLimiterState
|
|
196
|
+
*
|
|
197
|
+
* if (state === null) {
|
|
198
|
+
* console.log('Rate limiting disabled - unlimited throughput')
|
|
199
|
+
* } else {
|
|
200
|
+
* console.log(`Capacity: ${state.capacity}, Available: ${state.tokens}`)
|
|
201
|
+
* }
|
|
202
|
+
* ```
|
|
168
203
|
*/
|
|
169
204
|
export type RateLimiterState = {
|
|
170
205
|
/** Current token balance in the rate limiter bucket. */
|
|
171
206
|
tokens: bigint
|
|
172
207
|
/** Maximum capacity of the rate limiter bucket. */
|
|
173
208
|
capacity: bigint
|
|
174
|
-
/** Rate at which tokens are replenished. */
|
|
209
|
+
/** Rate at which tokens are replenished (tokens per second). */
|
|
175
210
|
rate: bigint
|
|
176
211
|
} | null
|
|
177
212
|
|
|
178
213
|
/**
|
|
179
|
-
* Remote token pool configuration for a specific chain.
|
|
214
|
+
* Remote token pool configuration for a specific destination chain.
|
|
215
|
+
*
|
|
216
|
+
* @remarks
|
|
217
|
+
* Each entry represents the configuration needed to transfer tokens
|
|
218
|
+
* from the current chain to a specific destination chain.
|
|
180
219
|
*/
|
|
181
220
|
export type TokenPoolRemote = {
|
|
182
221
|
/** Address of the remote token on the destination chain. */
|
|
183
222
|
remoteToken: string
|
|
184
|
-
/**
|
|
223
|
+
/**
|
|
224
|
+
* Addresses of remote token pools on the destination chain.
|
|
225
|
+
*
|
|
226
|
+
* @remarks
|
|
227
|
+
* Multiple pools may exist for:
|
|
228
|
+
* - Redundancy (failover if one pool is unavailable)
|
|
229
|
+
* - Capacity aggregation across pools
|
|
230
|
+
* - Version management (different pool implementations)
|
|
231
|
+
*/
|
|
185
232
|
remotePools: string[]
|
|
186
233
|
/** Inbound rate limiter state for tokens coming into this chain. */
|
|
187
234
|
inboundRateLimiterState: RateLimiterState
|
|
@@ -189,6 +236,43 @@ export type TokenPoolRemote = {
|
|
|
189
236
|
outboundRateLimiterState: RateLimiterState
|
|
190
237
|
}
|
|
191
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Token pool configuration returned by {@link Chain.getTokenPoolConfig}.
|
|
241
|
+
*
|
|
242
|
+
* @remarks
|
|
243
|
+
* Contains the core configuration of a token pool including the token it manages,
|
|
244
|
+
* the router it's registered with, and optionally its version identifier.
|
|
245
|
+
*/
|
|
246
|
+
export type TokenPoolConfig = {
|
|
247
|
+
/** Address of the token managed by this pool. */
|
|
248
|
+
token: string
|
|
249
|
+
/** Address of the CCIP router this pool is registered with. */
|
|
250
|
+
router: string
|
|
251
|
+
/**
|
|
252
|
+
* Version identifier string (e.g., "BurnMintTokenPool 1.5.1").
|
|
253
|
+
*
|
|
254
|
+
* @remarks
|
|
255
|
+
* May be undefined for older pool implementations that don't expose this method.
|
|
256
|
+
*/
|
|
257
|
+
typeAndVersion?: string
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Token configuration from a TokenAdminRegistry, returned by {@link Chain.getRegistryTokenConfig}.
|
|
262
|
+
*
|
|
263
|
+
* @remarks
|
|
264
|
+
* The TokenAdminRegistry tracks which administrator controls each token
|
|
265
|
+
* and which pool is authorized to handle transfers.
|
|
266
|
+
*/
|
|
267
|
+
export type RegistryTokenConfig = {
|
|
268
|
+
/** Address of the current administrator for this token. */
|
|
269
|
+
administrator: string
|
|
270
|
+
/** Address of pending administrator (if ownership transfer is in progress). */
|
|
271
|
+
pendingAdministrator?: string
|
|
272
|
+
/** Address of the token pool authorized to handle this token's transfers. */
|
|
273
|
+
tokenPool?: string
|
|
274
|
+
}
|
|
275
|
+
|
|
192
276
|
/**
|
|
193
277
|
* Maps chain family to respective unsigned transaction type.
|
|
194
278
|
*/
|
|
@@ -202,7 +286,7 @@ export type UnsignedTx = {
|
|
|
202
286
|
}
|
|
203
287
|
|
|
204
288
|
/**
|
|
205
|
-
* Common options for
|
|
289
|
+
* Common options for {@link Chain.getFee}, {@link Chain.generateUnsignedSendMessage} and {@link Chain.sendMessage} methods.
|
|
206
290
|
*/
|
|
207
291
|
export type SendMessageOpts = {
|
|
208
292
|
/** Router address on this chain */
|
|
@@ -216,13 +300,23 @@ export type SendMessageOpts = {
|
|
|
216
300
|
}
|
|
217
301
|
|
|
218
302
|
/**
|
|
219
|
-
* Common options for
|
|
303
|
+
* Common options for {@link Chain.generateUnsignedExecute} and {@link Chain.execute} methods.
|
|
220
304
|
*/
|
|
221
|
-
export type
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
305
|
+
export type ExecuteOpts = (
|
|
306
|
+
| {
|
|
307
|
+
/** address of the OffRamp contract */
|
|
308
|
+
offRamp: string
|
|
309
|
+
/** input payload to execute message; contains proofs for v1 and verifications for v2 */
|
|
310
|
+
input: ExecutionInput
|
|
311
|
+
}
|
|
312
|
+
| {
|
|
313
|
+
/**
|
|
314
|
+
* messageId of message to execute; requires `apiClient`.
|
|
315
|
+
* @remarks Currently throws CCIPNotImplementedError - API endpoint pending.
|
|
316
|
+
*/
|
|
317
|
+
messageId: string
|
|
318
|
+
}
|
|
319
|
+
) & {
|
|
226
320
|
/** gasLimit or computeUnits limit override for the ccipReceive call */
|
|
227
321
|
gasLimit?: number
|
|
228
322
|
/** For EVM, overrides gasLimit on tokenPool call */
|
|
@@ -249,6 +343,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
249
343
|
* Base constructor for Chain class.
|
|
250
344
|
* @param network - NetworkInfo object for the Chain instance
|
|
251
345
|
* @param ctx - Optional context with logger and API client configuration
|
|
346
|
+
* @throws {@link CCIPChainFamilyMismatchError} if network family doesn't match the Chain subclass
|
|
252
347
|
*/
|
|
253
348
|
constructor(network: NetworkInfo, ctx?: ChainContext) {
|
|
254
349
|
const { logger = console, apiClient, apiRetryConfig } = ctx ?? {}
|
|
@@ -270,7 +365,7 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
270
365
|
this.apiClient = apiClient // Use provided instance
|
|
271
366
|
this.apiRetryConfig = { ...DEFAULT_API_RETRY_CONFIG, ...apiRetryConfig }
|
|
272
367
|
} else {
|
|
273
|
-
this.apiClient =
|
|
368
|
+
this.apiClient = CCIPAPIClient.fromUrl(undefined, { logger }) // Default
|
|
274
369
|
this.apiRetryConfig = { ...DEFAULT_API_RETRY_CONFIG, ...apiRetryConfig }
|
|
275
370
|
}
|
|
276
371
|
}
|
|
@@ -284,20 +379,63 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
284
379
|
}
|
|
285
380
|
|
|
286
381
|
/**
|
|
287
|
-
* Fetch the timestamp of a given block
|
|
288
|
-
*
|
|
289
|
-
* @
|
|
382
|
+
* Fetch the timestamp of a given block.
|
|
383
|
+
*
|
|
384
|
+
* @param block - Positive block number, negative finality depth, or 'finalized' tag
|
|
385
|
+
* @returns Promise resolving to timestamp of the block, in seconds
|
|
386
|
+
*
|
|
387
|
+
* @throws {@link CCIPBlockNotFoundError} if block does not exist
|
|
388
|
+
*
|
|
389
|
+
* @example Get finalized block timestamp
|
|
390
|
+
* ```typescript
|
|
391
|
+
* const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
|
|
392
|
+
* const timestamp = await chain.getBlockTimestamp('finalized')
|
|
393
|
+
* console.log(`Finalized at: ${new Date(timestamp * 1000).toISOString()}`)
|
|
394
|
+
* ```
|
|
290
395
|
*/
|
|
291
396
|
abstract getBlockTimestamp(block: number | 'finalized'): Promise<number>
|
|
292
397
|
/**
|
|
293
|
-
* Fetch a transaction by its hash
|
|
294
|
-
*
|
|
295
|
-
* @
|
|
398
|
+
* Fetch a transaction by its hash.
|
|
399
|
+
*
|
|
400
|
+
* @param hash - Transaction hash
|
|
401
|
+
* @returns Promise resolving to generic transaction details
|
|
402
|
+
*
|
|
403
|
+
* @throws {@link CCIPTransactionNotFoundError} if transaction does not exist (transient)
|
|
404
|
+
*
|
|
405
|
+
* @example Fetch transaction details
|
|
406
|
+
* ```typescript
|
|
407
|
+
* const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
|
|
408
|
+
* try {
|
|
409
|
+
* const tx = await chain.getTransaction('0xabc123...')
|
|
410
|
+
* console.log(`Block: ${tx.blockNumber}, Timestamp: ${tx.timestamp}`)
|
|
411
|
+
* } catch (err) {
|
|
412
|
+
* if (err instanceof CCIPTransactionNotFoundError && err.isTransient) {
|
|
413
|
+
* // Transaction may be pending
|
|
414
|
+
* }
|
|
415
|
+
* }
|
|
416
|
+
* ```
|
|
296
417
|
*/
|
|
297
418
|
abstract getTransaction(hash: string): Promise<ChainTransaction>
|
|
298
419
|
/**
|
|
299
|
-
* Confirm a log tx is finalized or wait for it to be finalized
|
|
300
|
-
*
|
|
420
|
+
* Confirm a log tx is finalized or wait for it to be finalized.
|
|
421
|
+
*
|
|
422
|
+
* @param opts - Options containing the request, finality level, and optional cancel promise
|
|
423
|
+
* @returns true when the transaction is finalized
|
|
424
|
+
*
|
|
425
|
+
* @throws {@link CCIPTransactionNotFinalizedError} if the transaction is not included (e.g., due to a reorg)
|
|
426
|
+
*
|
|
427
|
+
* @example Wait for message finality
|
|
428
|
+
* ```typescript
|
|
429
|
+
* const request = await source.getMessagesInTx(txHash)
|
|
430
|
+
* try {
|
|
431
|
+
* await source.waitFinalized({ request: request[0] })
|
|
432
|
+
* console.log('Transaction finalized')
|
|
433
|
+
* } catch (err) {
|
|
434
|
+
* if (err instanceof CCIPTransactionNotFinalizedError) {
|
|
435
|
+
* console.log('Transaction not yet finalized')
|
|
436
|
+
* }
|
|
437
|
+
* }
|
|
438
|
+
* ```
|
|
301
439
|
*/
|
|
302
440
|
async waitFinalized({
|
|
303
441
|
request: { log, tx },
|
|
@@ -359,14 +497,30 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
359
497
|
* - `page`: if provided, try to use this page/range for batches
|
|
360
498
|
* - `watch`: true or cancellation promise, getLogs continuously after initial fetch
|
|
361
499
|
* @returns An async iterable iterator of logs.
|
|
500
|
+
* @throws {@link CCIPLogsWatchRequiresFinalityError} if watch mode is used without a finality endBlock tag
|
|
501
|
+
* @throws {@link CCIPLogsWatchRequiresStartError} if watch mode is used without startBlock or startTime
|
|
502
|
+
* @throws {@link CCIPLogsAddressRequiredError} if address is required but not provided (chain-specific)
|
|
362
503
|
*/
|
|
363
504
|
abstract getLogs(opts: LogFilter): AsyncIterableIterator<Log_>
|
|
364
505
|
|
|
365
506
|
/**
|
|
366
|
-
* Fetch all CCIP requests in a transaction
|
|
507
|
+
* Fetch all CCIP requests in a transaction.
|
|
508
|
+
*
|
|
367
509
|
* @param tx - ChainTransaction or txHash to fetch requests from
|
|
368
|
-
* @returns CCIP messages in the transaction (at least one)
|
|
369
|
-
|
|
510
|
+
* @returns Promise resolving to CCIP messages in the transaction (at least one)
|
|
511
|
+
*
|
|
512
|
+
* @throws {@link CCIPTransactionNotFoundError} if transaction does not exist
|
|
513
|
+
* @throws {@link CCIPMessageNotFoundInTxError} if no CCIPSendRequested events in tx
|
|
514
|
+
*
|
|
515
|
+
* @example Get messages from transaction
|
|
516
|
+
* ```typescript
|
|
517
|
+
* const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
|
|
518
|
+
* const requests = await chain.getMessagesInTx('0xabc123...')
|
|
519
|
+
* for (const req of requests) {
|
|
520
|
+
* console.log(`Message ID: ${req.message.messageId}`)
|
|
521
|
+
* }
|
|
522
|
+
* ```
|
|
523
|
+
*/
|
|
370
524
|
async getMessagesInTx(tx: string | ChainTransaction): Promise<CCIPRequest[]> {
|
|
371
525
|
const txHash = typeof tx === 'string' ? tx : tx.hash
|
|
372
526
|
try {
|
|
@@ -396,13 +550,33 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
396
550
|
}
|
|
397
551
|
|
|
398
552
|
/**
|
|
399
|
-
* Fetch a message by ID.
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
|
|
553
|
+
* Fetch a CCIP message by its unique message ID.
|
|
554
|
+
*
|
|
555
|
+
* @remarks
|
|
556
|
+
* Uses the CCIP API to retrieve message details. The returned request includes
|
|
557
|
+
* a `metadata` field with API-specific information.
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* ```typescript
|
|
561
|
+
* const request = await chain.getMessageById(messageId)
|
|
562
|
+
* console.log(`Sender: ${request.message.sender}`)
|
|
563
|
+
*
|
|
564
|
+
* if (request.metadata) {
|
|
565
|
+
* console.log(`Status: ${request.metadata.status}`)
|
|
566
|
+
* if (request.metadata.deliveryTime) {
|
|
567
|
+
* console.log(`Delivered in ${request.metadata.deliveryTime}ms`)
|
|
568
|
+
* }
|
|
569
|
+
* }
|
|
570
|
+
* ```
|
|
571
|
+
*
|
|
572
|
+
* @param messageId - The unique message ID (0x + 64 hex chars)
|
|
573
|
+
* @param _opts - Optional: `onRamp` hint for non-EVM chains
|
|
574
|
+
* @returns CCIPRequest with `metadata` populated from API
|
|
575
|
+
* @throws {@link CCIPApiClientNotAvailableError} if API disabled
|
|
576
|
+
* @throws {@link CCIPMessageIdNotFoundError} if message not found
|
|
577
|
+
* @throws {@link CCIPOnRampRequiredError} if onRamp is required but not provided
|
|
578
|
+
* @throws {@link CCIPHttpError} if API request fails
|
|
579
|
+
*/
|
|
406
580
|
async getMessageById(
|
|
407
581
|
messageId: string,
|
|
408
582
|
_opts?: { page?: number; onRamp?: string },
|
|
@@ -417,93 +591,213 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
417
591
|
|
|
418
592
|
/**
|
|
419
593
|
* Fetches all CCIP messages contained in a given commit batch.
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
* @param
|
|
594
|
+
* To be implemented for chains supporting CCIPVersion <= v1.6.0
|
|
595
|
+
*
|
|
596
|
+
* @param request - CCIPRequest to fetch batch for
|
|
597
|
+
* @param range - batch range \{ minSeqnr, maxSeqNr \}, e.g. from [[CommitReport]]
|
|
598
|
+
* @param opts - Optional parameters (e.g., `page` for pagination width)
|
|
599
|
+
* @returns Array of messages in the batch
|
|
600
|
+
*
|
|
601
|
+
* @throws {@link CCIPMessageBatchIncompleteError} if not all messages in range could be fetched
|
|
602
|
+
*
|
|
603
|
+
* @example Get all messages in a batch
|
|
604
|
+
* ```typescript
|
|
605
|
+
* const verifications = await dest.getVerifications({ offRamp, request })
|
|
606
|
+
* const messages = await source.getMessagesInBatch(request, verifications.report)
|
|
607
|
+
* console.log(`Found ${messages.length} messages in batch`)
|
|
608
|
+
* ```
|
|
423
609
|
*/
|
|
424
|
-
|
|
610
|
+
getMessagesInBatch?<
|
|
425
611
|
R extends PickDeep<
|
|
426
612
|
CCIPRequest,
|
|
427
613
|
'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
|
|
428
614
|
>,
|
|
429
615
|
>(
|
|
430
616
|
request: R,
|
|
431
|
-
|
|
617
|
+
range: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
|
|
432
618
|
opts?: { page?: number },
|
|
433
619
|
): Promise<R['message'][]>
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Fetch input data needed for executing messages
|
|
623
|
+
* Should be called on the *source* instance
|
|
624
|
+
* @param opts - getExecutionInput options containing request and verifications
|
|
625
|
+
* @returns `input` payload to be passed to [[execute]]
|
|
626
|
+
* @see {@link execute} - method to execute a message
|
|
627
|
+
*/
|
|
628
|
+
async getExecutionInput({
|
|
629
|
+
request,
|
|
630
|
+
verifications,
|
|
631
|
+
...opts
|
|
632
|
+
}: {
|
|
633
|
+
request: CCIPRequest
|
|
634
|
+
verifications: CCIPVerifications
|
|
635
|
+
} & Pick<LogFilter, 'page'>): Promise<ExecutionInput> {
|
|
636
|
+
if ('verifications' in verifications) {
|
|
637
|
+
// >=v2 verifications is enough for execution
|
|
638
|
+
return {
|
|
639
|
+
encodedMessage: (request.message as CCIPMessage<typeof CCIPVersion.V2_0>).encodedMessage,
|
|
640
|
+
...verifications,
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
// other messages in same batch are available from `source` side;
|
|
644
|
+
// not needed for chain families supporting only >=v2
|
|
645
|
+
const messagesInBatch = await this.getMessagesInBatch!(request, verifications.report, opts)
|
|
646
|
+
const execReportProof = calculateManualExecProof(
|
|
647
|
+
messagesInBatch,
|
|
648
|
+
request.lane,
|
|
649
|
+
request.message.messageId,
|
|
650
|
+
verifications.report.merkleRoot,
|
|
651
|
+
this,
|
|
652
|
+
)
|
|
653
|
+
const offchainTokenData = await this.getOffchainTokenData(request)
|
|
654
|
+
return {
|
|
655
|
+
...execReportProof,
|
|
656
|
+
message: request.message,
|
|
657
|
+
offchainTokenData,
|
|
658
|
+
} as ExecutionInput
|
|
659
|
+
}
|
|
434
660
|
/**
|
|
435
|
-
* Fetch typeAndVersion for a given CCIP contract address
|
|
661
|
+
* Fetch typeAndVersion for a given CCIP contract address.
|
|
662
|
+
*
|
|
436
663
|
* @param address - CCIP contract address
|
|
437
|
-
* @returns
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
664
|
+
* @returns Promise resolving to tuple:
|
|
665
|
+
* - `type` - Parsed type of the contract, e.g. `OnRamp`
|
|
666
|
+
* - `version` - Parsed version of the contract, e.g. `1.6.0`
|
|
667
|
+
* - `typeAndVersion` - Original (unparsed) typeAndVersion() string
|
|
668
|
+
* - `suffix` - Suffix of the version, if any (e.g. `-dev`)
|
|
669
|
+
*
|
|
670
|
+
* @throws {@link CCIPTypeVersionInvalidError} if typeAndVersion string cannot be parsed
|
|
671
|
+
*
|
|
672
|
+
* @example Check contract version
|
|
673
|
+
* ```typescript
|
|
674
|
+
* const [type, version] = await chain.typeAndVersion(contractAddress)
|
|
675
|
+
* console.log(`Contract: ${type} v${version}`)
|
|
676
|
+
* if (version < '1.6.0') {
|
|
677
|
+
* console.log('Legacy contract detected')
|
|
678
|
+
* }
|
|
679
|
+
* ```
|
|
441
680
|
*/
|
|
442
681
|
abstract typeAndVersion(
|
|
443
682
|
address: string,
|
|
444
683
|
): Promise<[type: string, version: string, typeAndVersion: string, suffix?: string]>
|
|
445
684
|
|
|
446
685
|
/**
|
|
447
|
-
* Fetch the Router address set in OnRamp config
|
|
448
|
-
* Used to discover OffRamp connected to OnRamp
|
|
686
|
+
* Fetch the Router address set in OnRamp config.
|
|
687
|
+
* Used to discover OffRamp connected to OnRamp.
|
|
688
|
+
*
|
|
449
689
|
* @param onRamp - OnRamp contract address
|
|
450
|
-
* @param destChainSelector -
|
|
451
|
-
* @returns Router address
|
|
690
|
+
* @param destChainSelector - Destination chain selector
|
|
691
|
+
* @returns Promise resolving to Router address
|
|
692
|
+
*
|
|
693
|
+
* @throws {@link CCIPContractTypeInvalidError} if address is not an OnRamp
|
|
694
|
+
*
|
|
695
|
+
* @example Get router from onRamp
|
|
696
|
+
* ```typescript
|
|
697
|
+
* const router = await chain.getRouterForOnRamp(onRampAddress, destSelector)
|
|
698
|
+
* console.log(`Router: ${router}`)
|
|
699
|
+
* ```
|
|
452
700
|
*/
|
|
453
701
|
abstract getRouterForOnRamp(onRamp: string, destChainSelector: bigint): Promise<string>
|
|
454
702
|
/**
|
|
455
|
-
* Fetch the Router address set in OffRamp config
|
|
703
|
+
* Fetch the Router address set in OffRamp config.
|
|
704
|
+
*
|
|
456
705
|
* @param offRamp - OffRamp contract address
|
|
457
|
-
* @param sourceChainSelector -
|
|
458
|
-
* @returns Router address
|
|
706
|
+
* @param sourceChainSelector - Source chain selector
|
|
707
|
+
* @returns Promise resolving to Router address
|
|
708
|
+
*
|
|
709
|
+
* @throws {@link CCIPContractTypeInvalidError} if address is not an OffRamp
|
|
710
|
+
*
|
|
711
|
+
* @example Get router from offRamp
|
|
712
|
+
* ```typescript
|
|
713
|
+
* const router = await chain.getRouterForOffRamp(offRampAddress, sourceSelector)
|
|
714
|
+
* console.log(`Router: ${router}`)
|
|
715
|
+
* ```
|
|
459
716
|
*/
|
|
460
717
|
abstract getRouterForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string>
|
|
461
718
|
/**
|
|
462
|
-
* Get the native token address for a Router
|
|
463
|
-
*
|
|
464
|
-
* @
|
|
719
|
+
* Get the native token address for a Router.
|
|
720
|
+
*
|
|
721
|
+
* @param router - Router contract address
|
|
722
|
+
* @returns Promise resolving to native token address (usually wrapped)
|
|
723
|
+
*
|
|
724
|
+
* @example Get wrapped native token
|
|
725
|
+
* ```typescript
|
|
726
|
+
* const weth = await chain.getNativeTokenForRouter(routerAddress)
|
|
727
|
+
* console.log(`Wrapped native: ${weth}`)
|
|
728
|
+
* ```
|
|
465
729
|
*/
|
|
466
730
|
abstract getNativeTokenForRouter(router: string): Promise<string>
|
|
467
731
|
/**
|
|
468
|
-
* Fetch the OffRamps allowlisted in a Router
|
|
469
|
-
* Used to discover OffRamp connected to an OnRamp
|
|
732
|
+
* Fetch the OffRamps allowlisted in a Router.
|
|
733
|
+
* Used to discover OffRamp connected to an OnRamp.
|
|
734
|
+
*
|
|
470
735
|
* @param router - Router contract address
|
|
471
|
-
* @param sourceChainSelector -
|
|
472
|
-
* @returns array of OffRamp addresses
|
|
736
|
+
* @param sourceChainSelector - Source chain selector
|
|
737
|
+
* @returns Promise resolving to array of OffRamp addresses
|
|
738
|
+
*
|
|
739
|
+
* @example Get offRamps for a source chain
|
|
740
|
+
* ```typescript
|
|
741
|
+
* const offRamps = await dest.getOffRampsForRouter(routerAddress, sourceSelector)
|
|
742
|
+
* console.log(`Found ${offRamps.length} offRamp(s)`)
|
|
743
|
+
* ```
|
|
473
744
|
*/
|
|
474
745
|
abstract getOffRampsForRouter(router: string, sourceChainSelector: bigint): Promise<string[]>
|
|
475
746
|
/**
|
|
476
|
-
* Fetch the OnRamp registered in a Router for a destination chain
|
|
747
|
+
* Fetch the OnRamp registered in a Router for a destination chain.
|
|
748
|
+
*
|
|
477
749
|
* @param router - Router contract address
|
|
478
|
-
* @param destChainSelector -
|
|
479
|
-
* @returns OnRamp
|
|
750
|
+
* @param destChainSelector - Destination chain selector
|
|
751
|
+
* @returns Promise resolving to OnRamp address
|
|
752
|
+
*
|
|
753
|
+
* @throws {@link CCIPLaneNotFoundError} if no lane exists to destination
|
|
754
|
+
*
|
|
755
|
+
* @example Get onRamp for destination
|
|
756
|
+
* ```typescript
|
|
757
|
+
* const onRamp = await source.getOnRampForRouter(routerAddress, destSelector)
|
|
758
|
+
* console.log(`OnRamp: ${onRamp}`)
|
|
759
|
+
* ```
|
|
480
760
|
*/
|
|
481
761
|
abstract getOnRampForRouter(router: string, destChainSelector: bigint): Promise<string>
|
|
482
762
|
/**
|
|
483
|
-
* Fetch the
|
|
484
|
-
* Used to discover OffRamp connected to an OnRamp
|
|
763
|
+
* Fetch the OnRamps addresses set in OffRamp config.
|
|
764
|
+
* Used to discover OffRamp connected to an OnRamp.
|
|
765
|
+
*
|
|
485
766
|
* @param offRamp - OffRamp contract address
|
|
486
|
-
* @param sourceChainSelector -
|
|
487
|
-
* @returns
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
* @returns CommitStore address.
|
|
767
|
+
* @param sourceChainSelector - Source chain selector
|
|
768
|
+
* @returns Promise resolving to OnRamps addresses
|
|
769
|
+
*
|
|
770
|
+
* @example Get onRamp from offRamp config
|
|
771
|
+
* ```typescript
|
|
772
|
+
* const [onRamp] = await dest.getOnRampsForOffRamp(offRampAddress, sourceSelector)
|
|
773
|
+
* console.log(`OnRamp: ${onRamp}`)
|
|
774
|
+
* ```
|
|
495
775
|
*/
|
|
496
|
-
abstract
|
|
776
|
+
abstract getOnRampsForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string[]>
|
|
497
777
|
/**
|
|
498
|
-
* Fetch the TokenPool's token/mint
|
|
778
|
+
* Fetch the TokenPool's token/mint.
|
|
779
|
+
*
|
|
499
780
|
* @param tokenPool - TokenPool address
|
|
500
|
-
* @returns
|
|
781
|
+
* @returns Promise resolving to token or mint address
|
|
782
|
+
*
|
|
783
|
+
* @example Get token for pool
|
|
784
|
+
* ```typescript
|
|
785
|
+
* const token = await chain.getTokenForTokenPool(tokenPoolAddress)
|
|
786
|
+
* console.log(`Token: ${token}`)
|
|
787
|
+
* ```
|
|
501
788
|
*/
|
|
502
789
|
abstract getTokenForTokenPool(tokenPool: string): Promise<string>
|
|
503
790
|
/**
|
|
504
|
-
* Fetch token metadata
|
|
791
|
+
* Fetch token metadata.
|
|
792
|
+
*
|
|
505
793
|
* @param token - Token address
|
|
506
|
-
* @returns
|
|
794
|
+
* @returns Promise resolving to token symbol, decimals, and optionally name
|
|
795
|
+
*
|
|
796
|
+
* @example Get token info
|
|
797
|
+
* ```typescript
|
|
798
|
+
* const info = await chain.getTokenInfo(tokenAddress)
|
|
799
|
+
* console.log(`${info.symbol}: ${info.decimals} decimals`)
|
|
800
|
+
* ```
|
|
507
801
|
*/
|
|
508
802
|
abstract getTokenInfo(token: string): Promise<TokenInfo>
|
|
509
803
|
/**
|
|
@@ -515,14 +809,14 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
515
809
|
*
|
|
516
810
|
* @example Query native token balance
|
|
517
811
|
* ```typescript
|
|
518
|
-
* const balance = await chain.getBalance({
|
|
812
|
+
* const balance = await chain.getBalance({ holder: '0x123...' })
|
|
519
813
|
* console.log(`Native balance: ${balance}`) // balance in wei
|
|
520
814
|
* ```
|
|
521
815
|
*
|
|
522
816
|
* @example Query ERC20 token balance
|
|
523
817
|
* ```typescript
|
|
524
818
|
* const balance = await chain.getBalance({
|
|
525
|
-
*
|
|
819
|
+
* holder: '0x123...',
|
|
526
820
|
* token: '0xLINK...'
|
|
527
821
|
* })
|
|
528
822
|
* console.log(`LINK balance: ${balance}`) // balance in smallest units
|
|
@@ -530,20 +824,52 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
530
824
|
*/
|
|
531
825
|
abstract getBalance(opts: GetBalanceOpts): Promise<bigint>
|
|
532
826
|
/**
|
|
533
|
-
* Fetch TokenAdminRegistry configured in a given OnRamp, Router, etc
|
|
534
|
-
* Needed to map a source token to its dest counterparts
|
|
535
|
-
*
|
|
827
|
+
* Fetch TokenAdminRegistry configured in a given OnRamp, Router, etc.
|
|
828
|
+
* Needed to map a source token to its dest counterparts.
|
|
829
|
+
*
|
|
830
|
+
* @param address - Contract address (OnRamp, Router, etc.)
|
|
831
|
+
* @returns Promise resolving to TokenAdminRegistry address
|
|
832
|
+
*
|
|
833
|
+
* @example Get token registry
|
|
834
|
+
* ```typescript
|
|
835
|
+
* const registry = await chain.getTokenAdminRegistryFor(onRampAddress)
|
|
836
|
+
* console.log(`Registry: ${registry}`)
|
|
837
|
+
* ```
|
|
536
838
|
*/
|
|
537
839
|
abstract getTokenAdminRegistryFor(address: string): Promise<string>
|
|
538
840
|
/**
|
|
539
|
-
* Fetch the current fee for a given intended message
|
|
841
|
+
* Fetch the current fee for a given intended message.
|
|
842
|
+
*
|
|
540
843
|
* @param opts - {@link SendMessageOpts} without approveMax
|
|
844
|
+
* @returns Fee amount in the feeToken's smallest units
|
|
845
|
+
*
|
|
846
|
+
* @example Calculate message fee
|
|
847
|
+
* ```typescript
|
|
848
|
+
* const fee = await chain.getFee({
|
|
849
|
+
* router: routerAddress,
|
|
850
|
+
* destChainSelector: destSelector,
|
|
851
|
+
* message: { receiver: '0x...', data: '0x' },
|
|
852
|
+
* })
|
|
853
|
+
* console.log(`Fee: ${fee} wei`)
|
|
854
|
+
* ```
|
|
541
855
|
*/
|
|
542
856
|
abstract getFee(opts: Omit<SendMessageOpts, 'approveMax'>): Promise<bigint>
|
|
543
857
|
/**
|
|
544
|
-
* Generate unsigned txs for ccipSend'ing a message
|
|
858
|
+
* Generate unsigned txs for ccipSend'ing a message.
|
|
859
|
+
*
|
|
545
860
|
* @param opts - {@link SendMessageOpts} with sender address
|
|
546
|
-
* @returns chain-family specific unsigned txs
|
|
861
|
+
* @returns Promise resolving to chain-family specific unsigned txs
|
|
862
|
+
*
|
|
863
|
+
* @example Generate unsigned transaction
|
|
864
|
+
* ```typescript
|
|
865
|
+
* const unsignedTx = await chain.generateUnsignedSendMessage({
|
|
866
|
+
* router: routerAddress,
|
|
867
|
+
* destChainSelector: destSelector,
|
|
868
|
+
* message: { receiver: '0x...', data: '0x1337' },
|
|
869
|
+
* sender: walletAddress,
|
|
870
|
+
* })
|
|
871
|
+
* // Sign and send with external wallet
|
|
872
|
+
* ```
|
|
547
873
|
*/
|
|
548
874
|
abstract generateUnsignedSendMessage(
|
|
549
875
|
opts: SendMessageOpts & {
|
|
@@ -553,10 +879,14 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
553
879
|
): Promise<UnsignedTx[F]>
|
|
554
880
|
/**
|
|
555
881
|
* Send a CCIP message through a router using provided wallet.
|
|
882
|
+
*
|
|
556
883
|
* @param opts - {@link SendMessageOpts} with chain-specific wallet for signing
|
|
557
|
-
* @returns CCIP request
|
|
884
|
+
* @returns Promise resolving to CCIP request with message details
|
|
558
885
|
*
|
|
559
|
-
* @
|
|
886
|
+
* @throws {@link CCIPWalletNotSignerError} if wallet is not a valid signer
|
|
887
|
+
* @throws {@link CCIPLaneNotFoundError} if no lane exists to destination
|
|
888
|
+
*
|
|
889
|
+
* @example Send cross-chain message
|
|
560
890
|
* ```typescript
|
|
561
891
|
* const request = await chain.sendMessage({
|
|
562
892
|
* router: '0x...',
|
|
@@ -579,72 +909,101 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
579
909
|
},
|
|
580
910
|
): Promise<CCIPRequest>
|
|
581
911
|
/**
|
|
582
|
-
* Fetch supported offchain token data for a request from this network
|
|
912
|
+
* Fetch supported offchain token data for a request from this network.
|
|
913
|
+
*
|
|
583
914
|
* @param request - CCIP request, with tx, logs and message
|
|
584
|
-
* @returns array with one offchain token data for each token transfer
|
|
915
|
+
* @returns Promise resolving to array with one offchain token data for each token transfer
|
|
916
|
+
*
|
|
917
|
+
* @throws {@link CCIPUsdcAttestationError} if USDC attestation fetch fails (transient)
|
|
918
|
+
* @throws {@link CCIPLbtcAttestationError} if LBTC attestation fetch fails (transient)
|
|
919
|
+
*
|
|
920
|
+
* @example Get offchain token data for USDC transfer
|
|
921
|
+
* ```typescript
|
|
922
|
+
* const offchainData = await source.getOffchainTokenData(request)
|
|
923
|
+
* // Use in execution report
|
|
924
|
+
* ```
|
|
585
925
|
*/
|
|
586
926
|
abstract getOffchainTokenData(request: CCIPRequest): Promise<OffchainTokenData[]>
|
|
587
927
|
/**
|
|
588
|
-
* Generate unsigned tx to manuallyExecute a message
|
|
589
|
-
*
|
|
590
|
-
* @
|
|
928
|
+
* Generate unsigned tx to manuallyExecute a message.
|
|
929
|
+
*
|
|
930
|
+
* @param opts - {@link ExecuteOpts} with payer address which will send the exec tx
|
|
931
|
+
* @returns Promise resolving to chain-family specific unsigned txs
|
|
932
|
+
*
|
|
933
|
+
* @example Generate unsigned execution tx
|
|
934
|
+
* ```typescript
|
|
935
|
+
* const unsignedTx = await dest.generateUnsignedExecute({
|
|
936
|
+
* offRamp: offRampAddress,
|
|
937
|
+
* execReport,
|
|
938
|
+
* payer: walletAddress,
|
|
939
|
+
* })
|
|
940
|
+
* // Sign and send with external wallet
|
|
941
|
+
* ```
|
|
591
942
|
*/
|
|
592
|
-
abstract
|
|
593
|
-
opts:
|
|
943
|
+
abstract generateUnsignedExecute(
|
|
944
|
+
opts: ExecuteOpts & {
|
|
594
945
|
/** address which will be used to send the report tx */
|
|
595
946
|
payer: string
|
|
596
947
|
},
|
|
597
948
|
): Promise<UnsignedTx[F]>
|
|
598
949
|
/**
|
|
599
|
-
* Execute messages in report in an offRamp
|
|
600
|
-
* @param opts - {@link ExecuteReportOpts} with chain-specific wallet to sign and send tx
|
|
601
|
-
* @returns transaction of the execution
|
|
950
|
+
* Execute messages in report in an offRamp.
|
|
602
951
|
*
|
|
603
|
-
* @
|
|
952
|
+
* @param opts - {@link ExecuteOpts} with chain-specific wallet to sign and send tx
|
|
953
|
+
* @returns Promise resolving to transaction of the execution
|
|
954
|
+
*
|
|
955
|
+
* @throws {@link CCIPWalletNotSignerError} if wallet is not a valid signer
|
|
956
|
+
* @throws {@link CCIPExecTxRevertedError} if execution transaction reverts
|
|
957
|
+
* @throws {@link CCIPMerkleRootMismatchError} if merkle proof is invalid
|
|
958
|
+
*
|
|
959
|
+
* @example Manual execution of pending message
|
|
604
960
|
* ```typescript
|
|
605
|
-
* const
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
* request.message.messageId,
|
|
609
|
-
* commit.report.merkleRoot,
|
|
610
|
-
* dest,
|
|
611
|
-
* )
|
|
612
|
-
* const receipt = await dest.executeReport({
|
|
613
|
-
* offRamp,
|
|
614
|
-
* execReport: {
|
|
615
|
-
* ...execReportProof,
|
|
616
|
-
* message: request.message,
|
|
617
|
-
* offchainTokenData: await source.getOffchainTokenData(request),
|
|
618
|
-
* },
|
|
619
|
-
* wallet,
|
|
620
|
-
* })
|
|
621
|
-
* console.log(`Message ID: ${request.message.messageId}`)
|
|
961
|
+
* const input = await source.getExecutionInput({ request, verifications })
|
|
962
|
+
* const receipt = await dest.execute({ offRamp, input, wallet })
|
|
963
|
+
* console.log(`Executed: ${receipt.log.transactionHash}`)
|
|
622
964
|
* ```
|
|
965
|
+
* @throws {@link CCIPWalletNotSignerError} if wallet cannot sign transactions
|
|
966
|
+
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
|
|
623
967
|
*/
|
|
624
|
-
abstract
|
|
625
|
-
opts:
|
|
968
|
+
abstract execute(
|
|
969
|
+
opts: ExecuteOpts & {
|
|
626
970
|
// Signer instance (chain-dependent)
|
|
627
971
|
wallet: unknown
|
|
628
972
|
},
|
|
629
973
|
): Promise<CCIPExecution>
|
|
630
974
|
|
|
631
975
|
/**
|
|
632
|
-
* Look for a CommitReport at dest for given CCIP request
|
|
633
|
-
* May be specialized by some subclasses
|
|
634
|
-
*
|
|
635
|
-
* @
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
976
|
+
* Look for a CommitReport at dest for given CCIP request.
|
|
977
|
+
* May be specialized by some subclasses.
|
|
978
|
+
*
|
|
979
|
+
* @param opts - getVerifications options
|
|
980
|
+
* @returns CCIPCommit info
|
|
981
|
+
*
|
|
982
|
+
* @throws {@link CCIPCommitNotFoundError} if no commit found for the request (transient)
|
|
983
|
+
*
|
|
984
|
+
* @example Get commit for a request
|
|
985
|
+
* ```typescript
|
|
986
|
+
* const verifications = await dest.getVerifications({
|
|
987
|
+
* offRamp: offRampAddress,
|
|
988
|
+
* request,
|
|
989
|
+
* })
|
|
990
|
+
* console.log(`Committed at block: ${verifications.log.blockNumber}`)
|
|
991
|
+
* ```
|
|
992
|
+
*/
|
|
993
|
+
async getVerifications({
|
|
994
|
+
offRamp,
|
|
639
995
|
request,
|
|
640
996
|
...hints
|
|
641
997
|
}: {
|
|
642
|
-
/** address of
|
|
643
|
-
|
|
998
|
+
/** address of offRamp or commitStore contract */
|
|
999
|
+
offRamp: string
|
|
644
1000
|
/** CCIPRequest subset object */
|
|
645
|
-
request: PickDeep<
|
|
646
|
-
|
|
647
|
-
|
|
1001
|
+
request: PickDeep<
|
|
1002
|
+
CCIPRequest,
|
|
1003
|
+
'lane' | `message.${'sequenceNumber' | 'messageId'}` | 'tx.timestamp'
|
|
1004
|
+
>
|
|
1005
|
+
} & Pick<LogFilter, 'page' | 'watch' | 'startBlock'>): Promise<CCIPVerifications> {
|
|
1006
|
+
return getOnchainCommitReport(this, offRamp, request, hints)
|
|
648
1007
|
}
|
|
649
1008
|
|
|
650
1009
|
/**
|
|
@@ -687,15 +1046,29 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
687
1046
|
}
|
|
688
1047
|
|
|
689
1048
|
/**
|
|
690
|
-
* Default/generic implementation of getExecutionReceipts
|
|
1049
|
+
* Default/generic implementation of getExecutionReceipts.
|
|
1050
|
+
* Yields execution receipts for a given offRamp.
|
|
1051
|
+
*
|
|
691
1052
|
* @param opts - getExecutionReceipts options
|
|
692
1053
|
* @returns Async generator of CCIPExecution receipts
|
|
1054
|
+
*
|
|
1055
|
+
* @example Watch for execution receipts
|
|
1056
|
+
* ```typescript
|
|
1057
|
+
* for await (const exec of dest.getExecutionReceipts({
|
|
1058
|
+
* offRamp: offRampAddress,
|
|
1059
|
+
* messageId: request.message.messageId,
|
|
1060
|
+
* startBlock: commit.log.blockNumber,
|
|
1061
|
+
* })) {
|
|
1062
|
+
* console.log(`State: ${exec.receipt.state}`)
|
|
1063
|
+
* if (exec.receipt.state === ExecutionState.Success) break
|
|
1064
|
+
* }
|
|
1065
|
+
* ```
|
|
693
1066
|
*/
|
|
694
1067
|
async *getExecutionReceipts({
|
|
695
1068
|
offRamp,
|
|
696
1069
|
messageId,
|
|
697
1070
|
sourceChainSelector,
|
|
698
|
-
|
|
1071
|
+
verifications,
|
|
699
1072
|
...hints
|
|
700
1073
|
}: {
|
|
701
1074
|
/** address of OffRamp contract */
|
|
@@ -705,12 +1078,12 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
705
1078
|
/** filter: yield only executions for this source chain */
|
|
706
1079
|
sourceChainSelector?: bigint
|
|
707
1080
|
/** optional commit associated with the request, can be used for optimizations in some families */
|
|
708
|
-
|
|
1081
|
+
verifications?: CCIPVerifications
|
|
709
1082
|
} & Pick<
|
|
710
1083
|
LogFilter,
|
|
711
1084
|
'page' | 'watch' | 'startBlock' | 'startTime'
|
|
712
1085
|
>): AsyncIterableIterator<CCIPExecution> {
|
|
713
|
-
hints.startBlock ??=
|
|
1086
|
+
if (verifications && 'log' in verifications) hints.startBlock ??= verifications.log.blockNumber
|
|
714
1087
|
const onlyLast = !hints.startTime && !hints.startBlock // backwards
|
|
715
1088
|
for await (const log of this.getLogs({
|
|
716
1089
|
address: offRamp,
|
|
@@ -736,9 +1109,18 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
736
1109
|
|
|
737
1110
|
/**
|
|
738
1111
|
* Fetch first execution receipt inside a transaction.
|
|
1112
|
+
*
|
|
739
1113
|
* @internal
|
|
740
|
-
* @param tx -
|
|
1114
|
+
* @param tx - Transaction hash or transaction object
|
|
741
1115
|
* @returns CCIP execution object
|
|
1116
|
+
*
|
|
1117
|
+
* @throws {@link CCIPExecTxRevertedError} if no execution receipt found in transaction
|
|
1118
|
+
*
|
|
1119
|
+
* @example Get receipt from execution tx
|
|
1120
|
+
* ```typescript
|
|
1121
|
+
* const exec = await dest.getExecutionReceiptInTx(execTxHash)
|
|
1122
|
+
* console.log(`State: ${exec.receipt.state}`)
|
|
1123
|
+
* ```
|
|
742
1124
|
*/
|
|
743
1125
|
async getExecutionReceiptInTx(tx: string | ChainTransaction): Promise<CCIPExecution> {
|
|
744
1126
|
if (typeof tx === 'string') tx = await this.getTransaction(tx)
|
|
@@ -754,63 +1136,198 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
754
1136
|
|
|
755
1137
|
/**
|
|
756
1138
|
* List tokens supported by given TokenAdminRegistry contract.
|
|
1139
|
+
*
|
|
757
1140
|
* @param address - Usually TokenAdminRegistry, but chain may support receiving Router, OnRamp, etc.
|
|
758
|
-
* @param opts - Optional parameters (e.g., `page` for pagination range)
|
|
759
|
-
* @returns
|
|
1141
|
+
* @param opts - Optional parameters (e.g., `page` for pagination range)
|
|
1142
|
+
* @returns Promise resolving to array of supported token addresses
|
|
1143
|
+
*
|
|
1144
|
+
* @example Get all supported tokens
|
|
1145
|
+
* ```typescript
|
|
1146
|
+
* const tokens = await chain.getSupportedTokens(registryAddress)
|
|
1147
|
+
* console.log(`${tokens.length} tokens supported`)
|
|
1148
|
+
* ```
|
|
760
1149
|
*/
|
|
761
1150
|
abstract getSupportedTokens(address: string, opts?: { page?: number }): Promise<string[]>
|
|
762
1151
|
|
|
763
1152
|
/**
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
* @
|
|
1153
|
+
* Fetch token configuration from a TokenAdminRegistry.
|
|
1154
|
+
*
|
|
1155
|
+
* @remarks
|
|
1156
|
+
* The TokenAdminRegistry is a contract that tracks token administrators and their
|
|
1157
|
+
* associated pools. Each token has an administrator who can update pool configurations.
|
|
1158
|
+
*
|
|
1159
|
+
* @example Query a token's registry configuration
|
|
1160
|
+
* ```typescript
|
|
1161
|
+
* const config = await chain.getRegistryTokenConfig(registryAddress, tokenAddress)
|
|
1162
|
+
* console.log(`Administrator: ${config.administrator}`)
|
|
1163
|
+
* if (config.tokenPool) {
|
|
1164
|
+
* console.log(`Pool: ${config.tokenPool}`)
|
|
1165
|
+
* }
|
|
1166
|
+
* ```
|
|
1167
|
+
*
|
|
1168
|
+
* @param registry - TokenAdminRegistry contract address.
|
|
1169
|
+
* @param token - Token address to query.
|
|
1170
|
+
* @returns {@link RegistryTokenConfig} containing administrator and pool information.
|
|
1171
|
+
* @throws {@link CCIPTokenNotInRegistryError} if token is not registered.
|
|
767
1172
|
*/
|
|
768
|
-
abstract getRegistryTokenConfig(
|
|
769
|
-
registry: string,
|
|
770
|
-
token: string,
|
|
771
|
-
): Promise<{
|
|
772
|
-
administrator: string
|
|
773
|
-
pendingAdministrator?: string
|
|
774
|
-
tokenPool?: string
|
|
775
|
-
}>
|
|
1173
|
+
abstract getRegistryTokenConfig(registry: string, token: string): Promise<RegistryTokenConfig>
|
|
776
1174
|
|
|
777
1175
|
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
1176
|
+
* Fetch configuration of a token pool.
|
|
1177
|
+
*
|
|
1178
|
+
* @remarks
|
|
1179
|
+
* Return type varies by chain:
|
|
1180
|
+
* - **EVM**: `typeAndVersion` is always present (required)
|
|
1181
|
+
* - **Solana**: Includes extra `tokenPoolProgram` field
|
|
1182
|
+
* - **Aptos**: Standard fields only
|
|
1183
|
+
* - **Sui/TON**: Throws {@link CCIPNotImplementedError}
|
|
1184
|
+
*
|
|
1185
|
+
* @example Type-safe access to chain-specific fields
|
|
1186
|
+
* ```typescript
|
|
1187
|
+
* // Use instanceof to narrow the chain type
|
|
1188
|
+
* if (chain instanceof SolanaChain) {
|
|
1189
|
+
* const config = await chain.getTokenPoolConfig(poolAddress)
|
|
1190
|
+
* console.log(config.tokenPoolProgram) // TypeScript knows this exists!
|
|
1191
|
+
* } else if (chain instanceof EVMChain) {
|
|
1192
|
+
* const config = await chain.getTokenPoolConfig(poolAddress)
|
|
1193
|
+
* console.log(config.typeAndVersion) // TypeScript knows this is required!
|
|
1194
|
+
* }
|
|
1195
|
+
* ```
|
|
1196
|
+
*
|
|
1197
|
+
* @param tokenPool - Token pool contract address.
|
|
1198
|
+
* @returns {@link TokenPoolConfig} containing token, router, and version info.
|
|
1199
|
+
* @throws {@link CCIPNotImplementedError} on Sui or TON chains
|
|
780
1200
|
*/
|
|
781
|
-
abstract
|
|
782
|
-
token: string
|
|
783
|
-
router: string
|
|
784
|
-
typeAndVersion?: string
|
|
785
|
-
}>
|
|
1201
|
+
abstract getTokenPoolConfig(tokenPool: string): Promise<TokenPoolConfig>
|
|
786
1202
|
|
|
787
1203
|
/**
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
* @
|
|
791
|
-
*
|
|
1204
|
+
* Fetch remote chain configurations for a token pool.
|
|
1205
|
+
*
|
|
1206
|
+
* @remarks
|
|
1207
|
+
* A token pool maintains configurations for each destination chain it supports.
|
|
1208
|
+
* The returned Record maps chain names to their respective configurations.
|
|
1209
|
+
*
|
|
1210
|
+
* @example Get all supported destinations
|
|
1211
|
+
* ```typescript
|
|
1212
|
+
* const remotes = await chain.getTokenPoolRemotes(poolAddress)
|
|
1213
|
+
* // Returns: {
|
|
1214
|
+
* // "ethereum-mainnet": { remoteToken: "0x...", remotePools: [...], ... },
|
|
1215
|
+
* // "ethereum-mainnet-arbitrum-1": { remoteToken: "0x...", remotePools: [...], ... },
|
|
1216
|
+
* // "solana-mainnet": { remoteToken: "...", remotePools: [...], ... }
|
|
1217
|
+
* // }
|
|
1218
|
+
*
|
|
1219
|
+
* // Access a specific chain's config
|
|
1220
|
+
* const arbConfig = remotes['ethereum-mainnet']
|
|
1221
|
+
* console.log(`Remote token: ${arbConfig.remoteToken}`)
|
|
1222
|
+
* ```
|
|
1223
|
+
*
|
|
1224
|
+
* @example Filter to a specific destination
|
|
1225
|
+
* ```typescript
|
|
1226
|
+
* import { networkInfo } from '@chainlink/ccip-sdk'
|
|
1227
|
+
*
|
|
1228
|
+
* const arbitrumSelector = 4949039107694359620n
|
|
1229
|
+
* const remotes = await chain.getTokenPoolRemotes(poolAddress, arbitrumSelector)
|
|
1230
|
+
* // Returns only: { "arbitrum-mainnet": { ... } }
|
|
1231
|
+
*
|
|
1232
|
+
* const chainName = networkInfo(arbitrumSelector).name
|
|
1233
|
+
* const config = remotes[chainName]
|
|
1234
|
+
* ```
|
|
1235
|
+
*
|
|
1236
|
+
* @param tokenPool - Token pool address on the current chain.
|
|
1237
|
+
* @param remoteChainSelector - Optional chain selector to filter results to a single destination.
|
|
1238
|
+
* @returns Record where keys are chain names (e.g., "ethereum-mainnet") and values are {@link TokenPoolRemote} configs.
|
|
1239
|
+
* @throws {@link CCIPTokenPoolChainConfigNotFoundError} if remoteChainSelector is specified but not configured.
|
|
792
1240
|
*/
|
|
793
1241
|
abstract getTokenPoolRemotes(
|
|
794
1242
|
tokenPool: string,
|
|
795
1243
|
remoteChainSelector?: bigint,
|
|
796
1244
|
): Promise<Record<string, TokenPoolRemote>>
|
|
1245
|
+
/**
|
|
1246
|
+
* Fetch remote chain configuration for a token pool for a specific destination.
|
|
1247
|
+
*
|
|
1248
|
+
* @remarks
|
|
1249
|
+
* Convenience wrapper around {@link getTokenPoolRemotes} that returns a single
|
|
1250
|
+
* configuration instead of a Record. Use this when you need configuration for
|
|
1251
|
+
* a specific destination chain.
|
|
1252
|
+
*
|
|
1253
|
+
* @example
|
|
1254
|
+
* ```typescript
|
|
1255
|
+
* const arbitrumSelector = 4949039107694359620n
|
|
1256
|
+
* const remote = await chain.getTokenPoolRemote(poolAddress, arbitrumSelector)
|
|
1257
|
+
* console.log(`Remote token: ${remote.remoteToken}`)
|
|
1258
|
+
* console.log(`Remote pools: ${remote.remotePools.join(', ')}`)
|
|
1259
|
+
* ```
|
|
1260
|
+
*
|
|
1261
|
+
* @param tokenPool - Token pool address on the current chain.
|
|
1262
|
+
* @param remoteChainSelector - Chain selector of the desired remote chain.
|
|
1263
|
+
* @returns TokenPoolRemote config for the specified remote chain.
|
|
1264
|
+
* @throws {@link CCIPTokenPoolChainConfigNotFoundError} if no configuration found for the specified remote chain.
|
|
1265
|
+
*/
|
|
1266
|
+
async getTokenPoolRemote(
|
|
1267
|
+
tokenPool: string,
|
|
1268
|
+
remoteChainSelector: bigint,
|
|
1269
|
+
): Promise<TokenPoolRemote> {
|
|
1270
|
+
const remotes = await this.getTokenPoolRemotes(tokenPool, remoteChainSelector)
|
|
1271
|
+
const network = networkInfo(remoteChainSelector)
|
|
1272
|
+
const remoteConfig = remotes[network.name]
|
|
1273
|
+
if (!remoteConfig) {
|
|
1274
|
+
throw new CCIPTokenPoolChainConfigNotFoundError(tokenPool, tokenPool, network.name)
|
|
1275
|
+
}
|
|
1276
|
+
return remoteConfig
|
|
1277
|
+
}
|
|
797
1278
|
|
|
798
1279
|
/**
|
|
799
1280
|
* Fetch list and info of supported feeTokens.
|
|
800
|
-
*
|
|
801
|
-
* @
|
|
1281
|
+
*
|
|
1282
|
+
* @param router - Router address on this chain
|
|
1283
|
+
* @returns Promise resolving to mapping of token addresses to TokenInfo objects
|
|
1284
|
+
*
|
|
1285
|
+
* @example Get available fee tokens
|
|
1286
|
+
* ```typescript
|
|
1287
|
+
* const feeTokens = await chain.getFeeTokens(routerAddress)
|
|
1288
|
+
* for (const [addr, info] of Object.entries(feeTokens)) {
|
|
1289
|
+
* console.log(`${info.symbol}: ${addr}`)
|
|
1290
|
+
* }
|
|
1291
|
+
* ```
|
|
802
1292
|
*/
|
|
803
1293
|
abstract getFeeTokens(router: string): Promise<Record<string, TokenInfo>>
|
|
804
1294
|
|
|
805
|
-
/**
|
|
1295
|
+
/**
|
|
1296
|
+
* Returns a copy of a message, populating missing fields like `extraArgs` with defaults.
|
|
1297
|
+
* It's expected to return a message suitable at least for basic token transfers.
|
|
1298
|
+
*
|
|
1299
|
+
* @param message - AnyMessage (from source), containing at least `receiver`
|
|
1300
|
+
* @returns A message suitable for `sendMessage` to this destination chain family
|
|
1301
|
+
*/
|
|
806
1302
|
static buildMessageForDest(
|
|
807
1303
|
message: Parameters<ChainStatic['buildMessageForDest']>[0],
|
|
808
1304
|
): AnyMessage {
|
|
809
|
-
|
|
1305
|
+
const gasLimit = message.data && dataLength(message.data) ? DEFAULT_GAS_LIMIT : 0n
|
|
1306
|
+
|
|
1307
|
+
// Detect if user wants V3 by checking for any V3-only field
|
|
1308
|
+
if (hasV3ExtraArgs(message.extraArgs)) {
|
|
1309
|
+
// V3 defaults (GenericExtraArgsV3)
|
|
1310
|
+
return {
|
|
1311
|
+
...message,
|
|
1312
|
+
extraArgs: {
|
|
1313
|
+
gasLimit,
|
|
1314
|
+
blockConfirmations: 0,
|
|
1315
|
+
ccvs: [],
|
|
1316
|
+
ccvArgs: [],
|
|
1317
|
+
executor: '',
|
|
1318
|
+
executorArgs: '0x',
|
|
1319
|
+
tokenReceiver: '',
|
|
1320
|
+
tokenArgs: '0x',
|
|
1321
|
+
...message.extraArgs,
|
|
1322
|
+
},
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// Default to V2 (GenericExtraArgsV2, aka EVMExtraArgsV2)
|
|
810
1327
|
return {
|
|
811
1328
|
...message,
|
|
812
1329
|
extraArgs: {
|
|
813
|
-
gasLimit
|
|
1330
|
+
gasLimit,
|
|
814
1331
|
allowOutOfOrderExecution: true,
|
|
815
1332
|
...message.extraArgs,
|
|
816
1333
|
},
|
|
@@ -838,87 +1355,216 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
838
1355
|
}): Promise<number>
|
|
839
1356
|
}
|
|
840
1357
|
|
|
841
|
-
/**
|
|
1358
|
+
/**
|
|
1359
|
+
* Static methods and properties available on Chain class constructors.
|
|
1360
|
+
*
|
|
1361
|
+
* @example Using static methods
|
|
1362
|
+
* ```typescript
|
|
1363
|
+
* // Create chain from URL
|
|
1364
|
+
* const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
|
|
1365
|
+
*
|
|
1366
|
+
* // Decode message from log
|
|
1367
|
+
* const message = EVMChain.decodeMessage(log)
|
|
1368
|
+
*
|
|
1369
|
+
* // Validate address format
|
|
1370
|
+
* const normalized = EVMChain.getAddress('0xABC...')
|
|
1371
|
+
* ```
|
|
1372
|
+
*/
|
|
842
1373
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
843
1374
|
export type ChainStatic<F extends ChainFamily = ChainFamily> = Function & {
|
|
844
1375
|
readonly family: F
|
|
845
1376
|
readonly decimals: number
|
|
846
1377
|
/**
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
* @param
|
|
1378
|
+
* Async constructor: builds a Chain from an RPC endpoint URL.
|
|
1379
|
+
*
|
|
1380
|
+
* @param url - RPC endpoint URL
|
|
1381
|
+
* @param ctx - Optional context with logger and API client configuration
|
|
1382
|
+
* @returns Promise resolving to Chain instance
|
|
1383
|
+
*
|
|
1384
|
+
* @throws {@link CCIPChainNotFoundError} if chain cannot be identified
|
|
1385
|
+
*
|
|
1386
|
+
* @example Create chain from RPC
|
|
1387
|
+
* ```typescript
|
|
1388
|
+
* const chain = await EVMChain.fromUrl('https://eth-mainnet.example.com')
|
|
1389
|
+
* console.log(`Connected to: ${chain.network.name}`)
|
|
1390
|
+
* ```
|
|
850
1391
|
*/
|
|
851
1392
|
fromUrl(url: string, ctx?: ChainContext): Promise<Chain<F>>
|
|
852
1393
|
/**
|
|
853
|
-
* Try to decode a CCIP message
|
|
854
|
-
* but
|
|
855
|
-
*
|
|
856
|
-
* e.g: EVM-born (abi.encoded) bytearray may output message.computeUnits for Solana
|
|
1394
|
+
* Try to decode a CCIP message from a log/event originated from this source chain.
|
|
1395
|
+
* The parsing is specific to this chain family, but content may target other chains.
|
|
1396
|
+
*
|
|
857
1397
|
* @param log - Chain generic log
|
|
858
|
-
* @returns
|
|
1398
|
+
* @returns Decoded CCIP message with merged extraArgs, or undefined if not a CCIP message
|
|
1399
|
+
*
|
|
1400
|
+
* @example Decode message from log
|
|
1401
|
+
* ```typescript
|
|
1402
|
+
* const message = EVMChain.decodeMessage(log)
|
|
1403
|
+
* if (message) {
|
|
1404
|
+
* console.log(`Message ID: ${message.messageId}`)
|
|
1405
|
+
* }
|
|
1406
|
+
* ```
|
|
859
1407
|
*/
|
|
860
1408
|
decodeMessage(log: Pick<Log_, 'data'>): CCIPMessage | undefined
|
|
861
1409
|
/**
|
|
862
|
-
* Try to decode an extraArgs array serialized for this chain family
|
|
863
|
-
*
|
|
864
|
-
* @
|
|
1410
|
+
* Try to decode an extraArgs array serialized for this chain family.
|
|
1411
|
+
*
|
|
1412
|
+
* @param extraArgs - Extra args bytes (Uint8Array, HexString or base64)
|
|
1413
|
+
* @returns Object containing decoded extraArgs and their tag, or undefined
|
|
1414
|
+
*
|
|
1415
|
+
* @throws {@link CCIPExtraArgsParseError} if bytes cannot be decoded
|
|
1416
|
+
*
|
|
1417
|
+
* @example Decode extra args
|
|
1418
|
+
* ```typescript
|
|
1419
|
+
* const decoded = EVMChain.decodeExtraArgs(message.extraArgs)
|
|
1420
|
+
* if (decoded?._tag === 'EVMExtraArgsV2') {
|
|
1421
|
+
* console.log(`Gas limit: ${decoded.gasLimit}`)
|
|
1422
|
+
* }
|
|
1423
|
+
* ```
|
|
865
1424
|
*/
|
|
866
1425
|
decodeExtraArgs(
|
|
867
1426
|
extraArgs: BytesLike,
|
|
868
1427
|
):
|
|
869
1428
|
| (EVMExtraArgsV1 & { _tag: 'EVMExtraArgsV1' })
|
|
870
1429
|
| (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
|
|
1430
|
+
| (GenericExtraArgsV3 & { _tag: 'GenericExtraArgsV3' })
|
|
871
1431
|
| (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
|
|
872
1432
|
| (SuiExtraArgsV1 & { _tag: 'SuiExtraArgsV1' })
|
|
873
1433
|
| undefined
|
|
1434
|
+
/**
|
|
1435
|
+
* Encode extraArgs for this chain family.
|
|
1436
|
+
*
|
|
1437
|
+
* @param extraArgs - Extra args object to encode
|
|
1438
|
+
* @returns Encoded hex string
|
|
1439
|
+
*
|
|
1440
|
+
* @example Encode extra args
|
|
1441
|
+
* ```typescript
|
|
1442
|
+
* const encoded = EVMChain.encodeExtraArgs({
|
|
1443
|
+
* gasLimit: 200000n,
|
|
1444
|
+
* strict: false,
|
|
1445
|
+
* })
|
|
1446
|
+
* ```
|
|
1447
|
+
*/
|
|
874
1448
|
encodeExtraArgs(extraArgs: ExtraArgs): string
|
|
875
1449
|
/**
|
|
876
|
-
* Decode a commit (CommitReportAccepted) event
|
|
1450
|
+
* Decode a commit (CommitReportAccepted) event.
|
|
1451
|
+
*
|
|
877
1452
|
* @param log - Chain generic log
|
|
878
|
-
* @param lane -
|
|
879
|
-
* @returns Array of commit reports contained in the log
|
|
1453
|
+
* @param lane - If passed, filter or validate reports by lane
|
|
1454
|
+
* @returns Array of commit reports contained in the log, or undefined
|
|
1455
|
+
*
|
|
1456
|
+
* @example Decode commit from log
|
|
1457
|
+
* ```typescript
|
|
1458
|
+
* const commits = EVMChain.decodeCommits(log, lane)
|
|
1459
|
+
* if (commits) {
|
|
1460
|
+
* console.log(`Found ${commits.length} commit(s)`)
|
|
1461
|
+
* }
|
|
1462
|
+
* ```
|
|
880
1463
|
*/
|
|
881
1464
|
decodeCommits(log: Pick<Log_, 'data'>, lane?: Lane): CommitReport[] | undefined
|
|
882
1465
|
/**
|
|
883
|
-
* Decode a receipt (
|
|
1466
|
+
* Decode a receipt (ExecutionStateChanged) event.
|
|
1467
|
+
*
|
|
884
1468
|
* @param log - Chain generic log
|
|
885
1469
|
* @returns ExecutionReceipt or undefined if not a recognized receipt
|
|
1470
|
+
*
|
|
1471
|
+
* @example Decode execution receipt
|
|
1472
|
+
* ```typescript
|
|
1473
|
+
* const receipt = EVMChain.decodeReceipt(log)
|
|
1474
|
+
* if (receipt) {
|
|
1475
|
+
* console.log(`State: ${receipt.state}, Message: ${receipt.messageId}`)
|
|
1476
|
+
* }
|
|
1477
|
+
* ```
|
|
886
1478
|
*/
|
|
887
1479
|
decodeReceipt(log: Pick<Log_, 'data'>): ExecutionReceipt | undefined
|
|
888
1480
|
/**
|
|
889
|
-
* Receive a bytes array and try to decode and normalize it as an address of this chain family
|
|
1481
|
+
* Receive a bytes array and try to decode and normalize it as an address of this chain family.
|
|
1482
|
+
*
|
|
890
1483
|
* @param bytes - Bytes array (Uint8Array, HexString or Base64)
|
|
891
1484
|
* @returns Address in this chain family's format
|
|
1485
|
+
*
|
|
1486
|
+
* @throws {@link CCIPAddressInvalidEvmError} if invalid EVM address
|
|
1487
|
+
* @throws {@link CCIPDataFormatUnsupportedError} if invalid Aptos/Sui address
|
|
1488
|
+
*
|
|
1489
|
+
* @example Normalize address
|
|
1490
|
+
* ```typescript
|
|
1491
|
+
* const normalized = EVMChain.getAddress('0xABC123...')
|
|
1492
|
+
* console.log(normalized) // checksummed address
|
|
1493
|
+
* ```
|
|
892
1494
|
*/
|
|
893
1495
|
getAddress(bytes: BytesLike): string
|
|
894
1496
|
/**
|
|
895
|
-
* Validates a transaction hash format for this chain family
|
|
1497
|
+
* Validates a transaction hash format for this chain family.
|
|
1498
|
+
*
|
|
1499
|
+
* @param v - Value to validate
|
|
1500
|
+
* @returns True if value is a valid transaction hash format
|
|
1501
|
+
*
|
|
1502
|
+
* @example Validate transaction hash
|
|
1503
|
+
* ```typescript
|
|
1504
|
+
* if (EVMChain.isTxHash(userInput)) {
|
|
1505
|
+
* const tx = await chain.getTransaction(userInput)
|
|
1506
|
+
* }
|
|
1507
|
+
* ```
|
|
896
1508
|
*/
|
|
897
1509
|
isTxHash(v: unknown): v is string
|
|
898
1510
|
/**
|
|
899
1511
|
* Format an address for human-friendly display.
|
|
900
1512
|
* Defaults to getAddress if not overridden.
|
|
1513
|
+
*
|
|
901
1514
|
* @param address - Address string in any recognized format
|
|
902
1515
|
* @returns Human-friendly address string for display
|
|
1516
|
+
*
|
|
1517
|
+
* @example Format address for display
|
|
1518
|
+
* ```typescript
|
|
1519
|
+
* const display = EVMChain.formatAddress?.(rawAddress) ?? rawAddress
|
|
1520
|
+
* console.log(display)
|
|
1521
|
+
* ```
|
|
903
1522
|
*/
|
|
904
1523
|
formatAddress?(address: string): string
|
|
905
1524
|
/**
|
|
906
1525
|
* Format a transaction hash for human-friendly display.
|
|
1526
|
+
*
|
|
907
1527
|
* @param hash - Transaction hash string
|
|
908
1528
|
* @returns Human-friendly hash string for display
|
|
1529
|
+
*
|
|
1530
|
+
* @example Format tx hash for display
|
|
1531
|
+
* ```typescript
|
|
1532
|
+
* const display = EVMChain.formatTxHash?.(rawHash) ?? rawHash
|
|
1533
|
+
* console.log(display)
|
|
1534
|
+
* ```
|
|
909
1535
|
*/
|
|
910
1536
|
formatTxHash?(hash: string): string
|
|
911
1537
|
/**
|
|
912
|
-
* Create a leaf hasher for this dest chain and lane
|
|
913
|
-
*
|
|
914
|
-
* @param
|
|
915
|
-
* @
|
|
1538
|
+
* Create a leaf hasher for this dest chain and lane.
|
|
1539
|
+
*
|
|
1540
|
+
* @param lane - Source, dest and onramp lane info
|
|
1541
|
+
* @param ctx - Context object containing logger
|
|
1542
|
+
* @returns LeafHasher function that takes a message and returns its hash
|
|
1543
|
+
*
|
|
1544
|
+
* @throws {@link CCIPHasherVersionUnsupportedError} if hasher version unsupported
|
|
1545
|
+
*
|
|
1546
|
+
* @example Create leaf hasher
|
|
1547
|
+
* ```typescript
|
|
1548
|
+
* const hasher = EVMChain.getDestLeafHasher(lane, { logger })
|
|
1549
|
+
* const leafHash = hasher(message)
|
|
1550
|
+
* ```
|
|
916
1551
|
*/
|
|
917
1552
|
getDestLeafHasher(lane: Lane, ctx?: WithLogger): LeafHasher
|
|
918
1553
|
/**
|
|
919
|
-
* Try to parse an error or bytearray generated by this chain family
|
|
1554
|
+
* Try to parse an error or bytearray generated by this chain family.
|
|
1555
|
+
*
|
|
920
1556
|
* @param data - Caught object, string or bytearray
|
|
921
|
-
* @returns Ordered record with messages/properties, or undefined if not
|
|
1557
|
+
* @returns Ordered record with messages/properties, or undefined/null if not recognized
|
|
1558
|
+
*
|
|
1559
|
+
* @example Parse contract error
|
|
1560
|
+
* ```typescript
|
|
1561
|
+
* try {
|
|
1562
|
+
* await chain.sendMessage(opts)
|
|
1563
|
+
* } catch (err) {
|
|
1564
|
+
* const parsed = EVMChain.parse?.(err)
|
|
1565
|
+
* if (parsed) console.log('Contract error:', parsed)
|
|
1566
|
+
* }
|
|
1567
|
+
* ```
|
|
922
1568
|
*/
|
|
923
1569
|
parse?(data: unknown): Record<string, unknown> | undefined | null
|
|
924
1570
|
/**
|