@chainlink/ccip-sdk 1.1.0 → 1.2.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/dist/api/index.d.ts +165 -15
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +236 -61
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +119 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +5 -5
- package/dist/aptos/index.js.map +1 -1
- package/dist/chain.d.ts +65 -24
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +84 -11
- package/dist/chain.js.map +1 -1
- package/dist/errors/codes.d.ts +1 -0
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +1 -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 +1 -0
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +21 -0
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +31 -1
- package/dist/errors/specialized.js.map +1 -1
- package/dist/evm/abi/OffRamp_2_0.d.ts +18 -17
- package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -1
- package/dist/evm/abi/OffRamp_2_0.js +19 -21
- package/dist/evm/abi/OffRamp_2_0.js.map +1 -1
- package/dist/evm/abi/TokenPool_2_0.d.ts +0 -4
- package/dist/evm/abi/TokenPool_2_0.d.ts.map +1 -1
- package/dist/evm/abi/TokenPool_2_0.js +0 -1
- package/dist/evm/abi/TokenPool_2_0.js.map +1 -1
- package/dist/evm/gas.d.ts +14 -4
- package/dist/evm/gas.d.ts.map +1 -1
- package/dist/evm/gas.js +7 -6
- package/dist/evm/gas.js.map +1 -1
- package/dist/evm/index.d.ts +39 -8
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +106 -36
- package/dist/evm/index.js.map +1 -1
- package/dist/extra-args.d.ts +18 -8
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +6 -6
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts +1 -1
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +7 -2
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/requests.d.ts +11 -5
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +4 -7
- package/dist/requests.js.map +1 -1
- package/dist/solana/index.d.ts +2 -2
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +3 -2
- package/dist/solana/index.js.map +1 -1
- package/dist/solana/utils.js +2 -2
- package/dist/solana/utils.js.map +1 -1
- package/dist/sui/exec.d.ts +30 -0
- package/dist/sui/exec.d.ts.map +1 -0
- package/dist/sui/exec.js +92 -0
- package/dist/sui/exec.js.map +1 -0
- package/dist/sui/index.d.ts +7 -2
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +23 -65
- package/dist/sui/index.js.map +1 -1
- package/dist/sui/manuallyExec/index.d.ts.map +1 -1
- package/dist/sui/manuallyExec/index.js +10 -13
- package/dist/sui/manuallyExec/index.js.map +1 -1
- package/dist/sui/objects.d.ts.map +1 -1
- package/dist/sui/objects.js +4 -2
- package/dist/sui/objects.js.map +1 -1
- package/dist/sui/types.d.ts +9 -1
- package/dist/sui/types.d.ts.map +1 -1
- package/dist/sui/types.js.map +1 -1
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +34 -26
- package/dist/ton/index.js.map +1 -1
- package/dist/utils.d.ts +10 -4
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -4
- package/dist/utils.js.map +1 -1
- package/package.json +7 -7
- package/src/api/index.ts +271 -59
- package/src/api/types.ts +126 -1
- package/src/aptos/index.ts +7 -9
- package/src/chain.ts +136 -38
- package/src/errors/codes.ts +1 -0
- package/src/errors/index.ts +1 -0
- package/src/errors/recovery.ts +2 -0
- package/src/errors/specialized.ts +33 -1
- package/src/evm/abi/OffRamp_2_0.ts +19 -21
- package/src/evm/abi/TokenPool_2_0.ts +0 -1
- package/src/evm/gas.ts +18 -20
- package/src/evm/index.ts +126 -34
- package/src/extra-args.ts +18 -8
- package/src/gas.ts +8 -3
- package/src/index.ts +5 -0
- package/src/requests.ts +18 -12
- package/src/solana/index.ts +3 -2
- package/src/solana/utils.ts +2 -2
- package/src/sui/exec.ts +131 -0
- package/src/sui/index.ts +33 -98
- package/src/sui/manuallyExec/index.ts +11 -17
- package/src/sui/objects.ts +4 -2
- package/src/sui/types.ts +10 -1
- package/src/ton/index.ts +47 -26
- package/src/utils.ts +10 -4
package/src/chain.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BytesLike, dataLength } from 'ethers'
|
|
1
|
+
import { type BytesLike, dataLength, keccak256 } from 'ethers'
|
|
2
2
|
import type { PickDeep, SetOptional } from 'type-fest'
|
|
3
3
|
|
|
4
4
|
import { type LaneLatencyResponse, CCIPAPIClient } from './api/index.ts'
|
|
@@ -24,10 +24,12 @@ import type {
|
|
|
24
24
|
SuiExtraArgsV1,
|
|
25
25
|
} from './extra-args.ts'
|
|
26
26
|
import type { LeafHasher } from './hasher/common.ts'
|
|
27
|
+
import { decodeMessageV1 } from './messages.ts'
|
|
27
28
|
import { getOffchainTokenData } from './offchain.ts'
|
|
28
29
|
import { getMessagesInTx } from './requests.ts'
|
|
29
30
|
import { DEFAULT_GAS_LIMIT } from './shared/constants.ts'
|
|
30
31
|
import type { UnsignedSolanaTx } from './solana/types.ts'
|
|
32
|
+
import type { UnsignedSuiTx } from './sui/types.ts'
|
|
31
33
|
import type { UnsignedTONTx } from './ton/types.ts'
|
|
32
34
|
import {
|
|
33
35
|
type AnyMessage,
|
|
@@ -67,7 +69,7 @@ const V3_FIELDS = new Set([
|
|
|
67
69
|
'tokenArgs',
|
|
68
70
|
])
|
|
69
71
|
|
|
70
|
-
/** Throw if any key in extraArgs is not in the allowed set. */
|
|
72
|
+
/** Throw {@link CCIPArgumentInvalidError} if any key in extraArgs is not in the allowed set. */
|
|
71
73
|
function assertNoUnknownFields(
|
|
72
74
|
extraArgs: Partial<ExtraArgs>,
|
|
73
75
|
allowed: Set<string>,
|
|
@@ -200,7 +202,7 @@ export type TokenInfo = {
|
|
|
200
202
|
*/
|
|
201
203
|
export const LaneFeature = {
|
|
202
204
|
/**
|
|
203
|
-
* Minimum block confirmations for Faster
|
|
205
|
+
* Minimum block confirmations for Faster-Than-Finality (FTF).
|
|
204
206
|
* - **absent**: the lane does not support FTF (pre-v2.0 lane).
|
|
205
207
|
* - **0**: the lane supports FTF, but it is not enabled for this
|
|
206
208
|
* token (e.g. the token pool predates FTF, or FTF is configured
|
|
@@ -284,6 +286,11 @@ export type RateLimiterState = {
|
|
|
284
286
|
* @remarks
|
|
285
287
|
* Each entry represents the configuration needed to transfer tokens
|
|
286
288
|
* from the current chain to a specific destination chain.
|
|
289
|
+
*
|
|
290
|
+
* The `customBlockConfirmationsOutboundRateLimiterState` and
|
|
291
|
+
* `customBlockConfirmationsInboundRateLimiterState` fields are present only for
|
|
292
|
+
* TokenPool v2.0+ contracts. These provide separate rate limits applied when
|
|
293
|
+
* Faster-Than-Finality (FTF) custom block confirmations are used.
|
|
287
294
|
*/
|
|
288
295
|
export type TokenPoolRemote = {
|
|
289
296
|
/** Address of the remote token on the destination chain. */
|
|
@@ -332,7 +339,7 @@ export type TokenPoolConfig = {
|
|
|
332
339
|
*/
|
|
333
340
|
typeAndVersion?: string
|
|
334
341
|
/**
|
|
335
|
-
* Min custom block confirmations for Faster
|
|
342
|
+
* Min custom block confirmations for Faster-Than-Finality (FTF),
|
|
336
343
|
* if TokenPool version \>= v2.0.0 and FTF is supported on this lane.
|
|
337
344
|
* `0` indicates FTF is supported but not enabled for this token; `>0` indicates FTF is enabled
|
|
338
345
|
* with this many minimum confirmations.
|
|
@@ -364,7 +371,7 @@ export type UnsignedTx = {
|
|
|
364
371
|
[ChainFamily.Solana]: UnsignedSolanaTx
|
|
365
372
|
[ChainFamily.Aptos]: UnsignedAptosTx
|
|
366
373
|
[ChainFamily.TON]: UnsignedTONTx
|
|
367
|
-
[ChainFamily.Sui]:
|
|
374
|
+
[ChainFamily.Sui]: UnsignedSuiTx
|
|
368
375
|
[ChainFamily.Unknown]: never
|
|
369
376
|
}
|
|
370
377
|
|
|
@@ -395,7 +402,7 @@ export type ExecuteOpts = (
|
|
|
395
402
|
| {
|
|
396
403
|
/**
|
|
397
404
|
* messageId of message to execute; requires `apiClient`.
|
|
398
|
-
*
|
|
405
|
+
* The SDK will fetch execution inputs (offRamp, proofs/verifications) from the CCIP API.
|
|
399
406
|
*/
|
|
400
407
|
messageId: string
|
|
401
408
|
}
|
|
@@ -1011,6 +1018,71 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
1011
1018
|
return getOffchainTokenData(request, this)
|
|
1012
1019
|
}
|
|
1013
1020
|
|
|
1021
|
+
/**
|
|
1022
|
+
* Resolves {@link ExecuteOpts} that may contain a `messageId` (API shorthand) into the
|
|
1023
|
+
* canonical `{ offRamp, input }` form required by {@link generateUnsignedExecute}.
|
|
1024
|
+
*
|
|
1025
|
+
* When `opts` already contains `input` the method is a no-op and returns it unchanged.
|
|
1026
|
+
* When `opts` contains only a `messageId` it calls `apiClient.getExecutionInput` and merges
|
|
1027
|
+
* the result back with any extra opts fields (e.g. `gasLimit`).
|
|
1028
|
+
* If opts.gasLimit is undefined and `estimateReceiveExecution` is available, try to estimate gasLimitOverride
|
|
1029
|
+
*
|
|
1030
|
+
* @throws {@link CCIPApiClientNotAvailableError} if `messageId` is provided but no apiClient
|
|
1031
|
+
*/
|
|
1032
|
+
protected async resolveExecuteOpts(
|
|
1033
|
+
opts: ExecuteOpts,
|
|
1034
|
+
): Promise<Extract<ExecuteOpts, { input: unknown }>> {
|
|
1035
|
+
let opts_: Extract<typeof opts, { input: unknown }>
|
|
1036
|
+
if ('input' in opts) {
|
|
1037
|
+
opts_ = opts
|
|
1038
|
+
} else if (!this.apiClient) throw new CCIPApiClientNotAvailableError()
|
|
1039
|
+
else {
|
|
1040
|
+
const { offRamp, ...input } = await this.apiClient.getExecutionInput(opts.messageId)
|
|
1041
|
+
opts_ = { ...opts, offRamp, input }
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if (
|
|
1045
|
+
opts_.gasLimit == null &&
|
|
1046
|
+
this.estimateReceiveExecution &&
|
|
1047
|
+
(!('message' in opts_.input) ||
|
|
1048
|
+
!opts_.input.message.tokenAmounts.length ||
|
|
1049
|
+
opts_.input.message.tokenAmounts.every((ta) => 'destTokenAddress' in ta))
|
|
1050
|
+
) {
|
|
1051
|
+
let message
|
|
1052
|
+
if ('message' in opts_.input) {
|
|
1053
|
+
message = {
|
|
1054
|
+
...opts_.input.message,
|
|
1055
|
+
// pass `tokenAmount` with `destTokenAddress` to estimate
|
|
1056
|
+
destTokenAmounts: opts_.input.message.tokenAmounts,
|
|
1057
|
+
}
|
|
1058
|
+
} else {
|
|
1059
|
+
const decoded = decodeMessageV1(opts_.input.encodedMessage)
|
|
1060
|
+
message = {
|
|
1061
|
+
...decoded,
|
|
1062
|
+
messageId: keccak256(opts_.input.encodedMessage),
|
|
1063
|
+
destTokenAmounts: decoded.tokenTransfer,
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
try {
|
|
1067
|
+
const estimated = await this.estimateReceiveExecution({
|
|
1068
|
+
offRamp: opts_.offRamp,
|
|
1069
|
+
message,
|
|
1070
|
+
})
|
|
1071
|
+
this.logger.debug('Estimated receiver execution:', estimated)
|
|
1072
|
+
if (
|
|
1073
|
+
('gasLimit' in message && estimated > message.gasLimit) ||
|
|
1074
|
+
('ccipReceiveGasLimit' in message && estimated > message.ccipReceiveGasLimit)
|
|
1075
|
+
)
|
|
1076
|
+
opts_.gasLimit = estimated
|
|
1077
|
+
} catch (err) {
|
|
1078
|
+
// ignore if receiver fails, let estimation of execute method itself throw if needed
|
|
1079
|
+
this.logger.debug('Failed to auto-estimateReceiveExecution for:', opts, err)
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
return opts_
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1014
1086
|
/**
|
|
1015
1087
|
* Generate unsigned tx to manuallyExecute a message.
|
|
1016
1088
|
*
|
|
@@ -1036,21 +1108,24 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
1036
1108
|
/**
|
|
1037
1109
|
* Execute messages in report in an offRamp.
|
|
1038
1110
|
*
|
|
1039
|
-
* @param opts - {@link ExecuteOpts} with chain-specific wallet to sign and send tx
|
|
1040
|
-
* @returns Promise resolving to transaction of the execution
|
|
1111
|
+
* @param opts - {@link ExecuteOpts} with chain-specific wallet to sign and send tx.
|
|
1112
|
+
* @returns Promise resolving to transaction of the execution.
|
|
1041
1113
|
*
|
|
1042
|
-
* @throws {@link CCIPWalletNotSignerError} if wallet is not a valid signer
|
|
1043
|
-
* @throws {@link
|
|
1044
|
-
* @throws {@link
|
|
1114
|
+
* @throws {@link CCIPWalletNotSignerError} if wallet is not a valid signer.
|
|
1115
|
+
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm.
|
|
1116
|
+
* @throws {@link CCIPExecTxRevertedError} if execution transaction reverts.
|
|
1117
|
+
* @throws {@link CCIPMerkleRootMismatchError} if merkle proof is invalid.
|
|
1045
1118
|
*
|
|
1046
|
-
* @example Manual execution
|
|
1119
|
+
* @example Manual execution using message ID (simplified, requires API)
|
|
1120
|
+
* ```typescript
|
|
1121
|
+
* const receipt = await dest.execute({ messageId: '0x...', wallet })
|
|
1122
|
+
* ```
|
|
1123
|
+
*
|
|
1124
|
+
* @example Manual execution using transaction hash
|
|
1047
1125
|
* ```typescript
|
|
1048
1126
|
* const input = await source.getExecutionInput({ request, verifications })
|
|
1049
1127
|
* const receipt = await dest.execute({ offRamp, input, wallet })
|
|
1050
|
-
* console.log(`Executed: ${receipt.log.transactionHash}`)
|
|
1051
1128
|
* ```
|
|
1052
|
-
* @throws {@link CCIPWalletNotSignerError} if wallet cannot sign transactions
|
|
1053
|
-
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
|
|
1054
1129
|
*/
|
|
1055
1130
|
abstract execute(
|
|
1056
1131
|
opts: ExecuteOpts & {
|
|
@@ -1098,10 +1173,10 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
1098
1173
|
* Uses this chain's selector as the source.
|
|
1099
1174
|
*
|
|
1100
1175
|
* @param destChainSelector - Destination CCIP chain selector (bigint)
|
|
1176
|
+
* @param numberOfBlocks - Optional number of block confirmations to use for latency
|
|
1177
|
+
* calculation. When omitted or 0, uses the lane's default finality. When provided
|
|
1178
|
+
* as a positive integer, the API returns latency for that custom finality value.
|
|
1101
1179
|
* @returns Promise resolving to {@link LaneLatencyResponse} containing:
|
|
1102
|
-
* - `lane.sourceNetworkInfo` - Source chain metadata (name, selector, chainId)
|
|
1103
|
-
* - `lane.destNetworkInfo` - Destination chain metadata
|
|
1104
|
-
* - `lane.routerAddress` - Router contract address on source chain
|
|
1105
1180
|
* - `totalMs` - Estimated delivery time in milliseconds
|
|
1106
1181
|
*
|
|
1107
1182
|
* @throws {@link CCIPApiClientNotAvailableError} if apiClient was disabled (set to `null`)
|
|
@@ -1117,19 +1192,31 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
1117
1192
|
* try {
|
|
1118
1193
|
* const latency = await chain.getLaneLatency(4949039107694359620n) // Arbitrum
|
|
1119
1194
|
* console.log(`Estimated delivery: ${Math.round(latency.totalMs / 60000)} minutes`)
|
|
1120
|
-
* console.log(`Router: ${latency.lane.routerAddress}`)
|
|
1121
1195
|
* } catch (err) {
|
|
1122
1196
|
* if (err instanceof CCIPHttpError) {
|
|
1123
1197
|
* console.error(`API error: ${err.context.apiErrorCode}`)
|
|
1124
1198
|
* }
|
|
1125
1199
|
* }
|
|
1126
1200
|
* ```
|
|
1201
|
+
*
|
|
1202
|
+
* @example Get latency with custom block confirmations
|
|
1203
|
+
* ```typescript
|
|
1204
|
+
* const latency = await chain.getLaneLatency(4949039107694359620n, 10)
|
|
1205
|
+
* console.log(`Latency with 10 confirmations: ${Math.round(latency.totalMs / 60000)} minutes`)
|
|
1206
|
+
* ```
|
|
1127
1207
|
*/
|
|
1128
|
-
async getLaneLatency(
|
|
1208
|
+
async getLaneLatency(
|
|
1209
|
+
destChainSelector: bigint,
|
|
1210
|
+
numberOfBlocks?: number,
|
|
1211
|
+
): Promise<LaneLatencyResponse> {
|
|
1129
1212
|
if (!this.apiClient) {
|
|
1130
1213
|
throw new CCIPApiClientNotAvailableError()
|
|
1131
1214
|
}
|
|
1132
|
-
return this.apiClient.getLaneLatency(
|
|
1215
|
+
return this.apiClient.getLaneLatency(
|
|
1216
|
+
this.network.chainSelector,
|
|
1217
|
+
destChainSelector,
|
|
1218
|
+
numberOfBlocks,
|
|
1219
|
+
)
|
|
1133
1220
|
}
|
|
1134
1221
|
|
|
1135
1222
|
/**
|
|
@@ -1418,8 +1505,15 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
1418
1505
|
* Returns a copy of a message, populating missing fields like `extraArgs` with defaults.
|
|
1419
1506
|
* It's expected to return a message suitable at least for basic token transfers.
|
|
1420
1507
|
*
|
|
1421
|
-
* @param message - AnyMessage (from source), containing at least `receiver
|
|
1422
|
-
* @returns A message suitable for `sendMessage` to this destination chain family
|
|
1508
|
+
* @param message - AnyMessage (from source), containing at least `receiver`.
|
|
1509
|
+
* @returns A message suitable for `sendMessage` to this destination chain family.
|
|
1510
|
+
*
|
|
1511
|
+
* @remarks
|
|
1512
|
+
* V3 (GenericExtraArgsV3) is auto-detected when any V3-only field is present
|
|
1513
|
+
* (e.g. `blockConfirmations`, `ccvs`, `ccvArgs`, `executor`, `executorArgs`,
|
|
1514
|
+
* `tokenReceiver`, `tokenArgs`). Otherwise defaults to V2 (EVMExtraArgsV2).
|
|
1515
|
+
*
|
|
1516
|
+
* @throws {@link CCIPArgumentInvalidError} if extraArgs contains unknown fields for the detected version.
|
|
1423
1517
|
*/
|
|
1424
1518
|
static buildMessageForDest(
|
|
1425
1519
|
message: Parameters<ChainStatic['buildMessageForDest']>[0],
|
|
@@ -1461,23 +1555,27 @@ export abstract class Chain<F extends ChainFamily = ChainFamily> {
|
|
|
1461
1555
|
|
|
1462
1556
|
/**
|
|
1463
1557
|
* Estimate `ccipReceive` execution cost (gas, computeUnits) for this *dest*
|
|
1464
|
-
* @param opts - estimation options
|
|
1558
|
+
* @param opts - estimation options, either `messageId` (for api) or `offRamp`, `message` (with `destTokenAmounts`)
|
|
1465
1559
|
* @returns estimated execution cost (gas or computeUnits)
|
|
1466
1560
|
*/
|
|
1467
|
-
estimateReceiveExecution?(
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1561
|
+
estimateReceiveExecution?(
|
|
1562
|
+
opts:
|
|
1563
|
+
| {
|
|
1564
|
+
offRamp: string
|
|
1565
|
+
message: {
|
|
1566
|
+
sourceChainSelector: bigint
|
|
1567
|
+
messageId: string
|
|
1568
|
+
receiver: string
|
|
1569
|
+
sender?: string
|
|
1570
|
+
data?: BytesLike
|
|
1571
|
+
destTokenAmounts?: readonly ((
|
|
1572
|
+
| { token: string }
|
|
1573
|
+
| { destTokenAddress: string; extraData?: string }
|
|
1574
|
+
) & { amount: bigint })[]
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
| { messageId: string },
|
|
1578
|
+
): Promise<number>
|
|
1481
1579
|
}
|
|
1482
1580
|
|
|
1483
1581
|
/**
|
package/src/errors/codes.ts
CHANGED
package/src/errors/index.ts
CHANGED
|
@@ -156,6 +156,7 @@ export { CCIPBorshMethodUnknownError, CCIPBorshTypeUnknownError } from './specia
|
|
|
156
156
|
|
|
157
157
|
// Specialized errors - HTTP & Data
|
|
158
158
|
export {
|
|
159
|
+
CCIPAbortError,
|
|
159
160
|
CCIPBlockBeforeTimestampNotFoundError,
|
|
160
161
|
CCIPDataFormatUnsupportedError,
|
|
161
162
|
CCIPDataParseError,
|
package/src/errors/recovery.ts
CHANGED
|
@@ -170,6 +170,8 @@ export const DEFAULT_RECOVERY_HINTS: Partial<Record<CCIPErrorCode, string>> = {
|
|
|
170
170
|
RPC_NOT_FOUND: 'No RPC endpoint found. Configure an RPC URL.',
|
|
171
171
|
TIMEOUT:
|
|
172
172
|
'Request timed out. Check network connectivity and try again. Consider increasing timeoutMs if the server is slow.',
|
|
173
|
+
ABORT:
|
|
174
|
+
'Request was aborted. This is usually intentional (e.g. user cancellation or component unmount).',
|
|
173
175
|
|
|
174
176
|
VIEM_ADAPTER_ERROR:
|
|
175
177
|
'Check that your viem client has both account and chain defined. For WalletClient, use createWalletClient({ chain, account, ... }).',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CCIPErrorOptions, CCIPError } from './CCIPError.ts'
|
|
2
2
|
import { CCIPErrorCode } from './codes.ts'
|
|
3
3
|
import { isTransientHttpStatus } from '../http-status.ts'
|
|
4
|
+
import { bigIntReplacer } from '../utils.ts'
|
|
4
5
|
|
|
5
6
|
// Chain/Network
|
|
6
7
|
|
|
@@ -166,7 +167,10 @@ export class CCIPMessageInvalidError extends CCIPError {
|
|
|
166
167
|
override readonly name = 'CCIPMessageInvalidError'
|
|
167
168
|
/** Creates a message invalid error. */
|
|
168
169
|
constructor(data: unknown, options?: CCIPErrorOptions) {
|
|
169
|
-
const dataStr =
|
|
170
|
+
const dataStr =
|
|
171
|
+
typeof data === 'object' && data !== null
|
|
172
|
+
? JSON.stringify(data, bigIntReplacer)
|
|
173
|
+
: String(data)
|
|
170
174
|
super(CCIPErrorCode.MESSAGE_INVALID, `Invalid CCIP message format: ${dataStr}`, {
|
|
171
175
|
...options,
|
|
172
176
|
isTransient: false,
|
|
@@ -1203,6 +1207,34 @@ export class CCIPTimeoutError extends CCIPError {
|
|
|
1203
1207
|
}
|
|
1204
1208
|
}
|
|
1205
1209
|
|
|
1210
|
+
/**
|
|
1211
|
+
* Thrown when a request is aborted via an AbortSignal.
|
|
1212
|
+
*
|
|
1213
|
+
* @example
|
|
1214
|
+
* ```typescript
|
|
1215
|
+
* const controller = new AbortController()
|
|
1216
|
+
* setTimeout(() => controller.abort(), 1000)
|
|
1217
|
+
* try {
|
|
1218
|
+
* await api.searchMessages({ sender: '0x...' }, { signal: controller.signal })
|
|
1219
|
+
* } catch (error) {
|
|
1220
|
+
* if (error instanceof CCIPAbortError) {
|
|
1221
|
+
* console.log(`Request was cancelled: ${error.context.operation}`)
|
|
1222
|
+
* }
|
|
1223
|
+
* }
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
export class CCIPAbortError extends CCIPError {
|
|
1227
|
+
override readonly name = 'CCIPAbortError'
|
|
1228
|
+
/** Creates an abort error. */
|
|
1229
|
+
constructor(operation: string, options?: CCIPErrorOptions) {
|
|
1230
|
+
super(CCIPErrorCode.ABORT, `Request aborted: ${operation}`, {
|
|
1231
|
+
...options,
|
|
1232
|
+
isTransient: false,
|
|
1233
|
+
context: { ...options?.context, operation },
|
|
1234
|
+
})
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1206
1238
|
/**
|
|
1207
1239
|
* Thrown for not implemented features.
|
|
1208
1240
|
*
|
|
@@ -222,9 +222,13 @@ export default [
|
|
|
222
222
|
name: 'getAllSourceChainConfigs',
|
|
223
223
|
inputs: [],
|
|
224
224
|
outputs: [
|
|
225
|
-
{ name: '', type: 'uint64[]', internalType: 'uint64[]' },
|
|
226
225
|
{
|
|
227
|
-
name: '',
|
|
226
|
+
name: 'sourceChainSelectors',
|
|
227
|
+
type: 'uint64[]',
|
|
228
|
+
internalType: 'uint64[]',
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'sourceChainConfigs',
|
|
228
232
|
type: 'tuple[]',
|
|
229
233
|
internalType: 'struct OffRamp.SourceChainConfig[]',
|
|
230
234
|
components: [
|
|
@@ -418,25 +422,6 @@ export default [
|
|
|
418
422
|
],
|
|
419
423
|
anonymous: false,
|
|
420
424
|
},
|
|
421
|
-
{
|
|
422
|
-
type: 'event',
|
|
423
|
-
name: 'MaxGasBufferToUpdateStateUpdated',
|
|
424
|
-
inputs: [
|
|
425
|
-
{
|
|
426
|
-
name: 'oldMaxGasBufferToUpdateState',
|
|
427
|
-
type: 'uint32',
|
|
428
|
-
indexed: false,
|
|
429
|
-
internalType: 'uint32',
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
name: 'newMaxGasBufferToUpdateState',
|
|
433
|
-
type: 'uint32',
|
|
434
|
-
indexed: false,
|
|
435
|
-
internalType: 'uint32',
|
|
436
|
-
},
|
|
437
|
-
],
|
|
438
|
-
anonymous: false,
|
|
439
|
-
},
|
|
440
425
|
{
|
|
441
426
|
type: 'event',
|
|
442
427
|
name: 'OwnershipTransferRequested',
|
|
@@ -611,6 +596,19 @@ export default [
|
|
|
611
596
|
name: 'InvalidEncodingVersion',
|
|
612
597
|
inputs: [{ name: 'version', type: 'uint8', internalType: 'uint8' }],
|
|
613
598
|
},
|
|
599
|
+
{
|
|
600
|
+
type: 'error',
|
|
601
|
+
name: 'InvalidFinalityForReceiver',
|
|
602
|
+
inputs: [
|
|
603
|
+
{ name: 'receiver', type: 'address', internalType: 'address' },
|
|
604
|
+
{ name: 'msgBlockDepth', type: 'uint16', internalType: 'uint16' },
|
|
605
|
+
{
|
|
606
|
+
name: 'requiredBlockDepth',
|
|
607
|
+
type: 'uint16',
|
|
608
|
+
internalType: 'uint16',
|
|
609
|
+
},
|
|
610
|
+
],
|
|
611
|
+
},
|
|
614
612
|
{
|
|
615
613
|
type: 'error',
|
|
616
614
|
name: 'InvalidGasLimitOverride',
|
|
@@ -1546,7 +1546,6 @@ export default [
|
|
|
1546
1546
|
name: 'InvalidTransferFeeBps',
|
|
1547
1547
|
inputs: [{ name: 'bps', type: 'uint256', internalType: 'uint256' }],
|
|
1548
1548
|
},
|
|
1549
|
-
{ type: 'error', name: 'MismatchedArrayLengths', inputs: [] },
|
|
1550
1549
|
{ type: 'error', name: 'MustBeProposedOwner', inputs: [] },
|
|
1551
1550
|
{
|
|
1552
1551
|
type: 'error',
|
package/src/evm/gas.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type BytesLike,
|
|
2
3
|
type JsonRpcApiProvider,
|
|
3
4
|
Contract,
|
|
4
5
|
FunctionFragment,
|
|
@@ -14,7 +15,6 @@ import {
|
|
|
14
15
|
import type { TypedContract } from 'ethers-abitype'
|
|
15
16
|
import { memoize } from 'micro-memoize'
|
|
16
17
|
|
|
17
|
-
import type { Chain } from '../chain.ts'
|
|
18
18
|
import TokenABI from './abi/BurnMintERC677Token.ts'
|
|
19
19
|
import RouterABI from './abi/Router.ts'
|
|
20
20
|
import { defaultAbiCoder, interfaces } from './const.ts'
|
|
@@ -77,13 +77,17 @@ const findBalancesSlot = memoize(
|
|
|
77
77
|
{ maxArgs: 1 },
|
|
78
78
|
)
|
|
79
79
|
|
|
80
|
-
type EstimateExecGasOpts =
|
|
81
|
-
Parameters<NonNullable<Chain['estimateReceiveExecution']>>[0],
|
|
82
|
-
'message' | 'receiver'
|
|
83
|
-
> & {
|
|
84
|
-
/* */
|
|
80
|
+
type EstimateExecGasOpts = {
|
|
85
81
|
provider: JsonRpcApiProvider
|
|
86
82
|
router: string
|
|
83
|
+
message: {
|
|
84
|
+
sourceChainSelector: bigint
|
|
85
|
+
messageId: string
|
|
86
|
+
receiver: string
|
|
87
|
+
sender?: string
|
|
88
|
+
data?: BytesLike
|
|
89
|
+
destTokenAmounts?: readonly { token: string; amount: bigint }[]
|
|
90
|
+
}
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
/**
|
|
@@ -91,12 +95,7 @@ type EstimateExecGasOpts = Pick<
|
|
|
91
95
|
* @param opts - Options for estimation: provider, destRouter, receiver address and message
|
|
92
96
|
* @returns Estimated gasLimit
|
|
93
97
|
*/
|
|
94
|
-
export async function estimateExecGas({
|
|
95
|
-
provider,
|
|
96
|
-
router,
|
|
97
|
-
receiver,
|
|
98
|
-
message,
|
|
99
|
-
}: EstimateExecGasOpts) {
|
|
98
|
+
export async function estimateExecGas({ provider, router, message }: EstimateExecGasOpts) {
|
|
100
99
|
// we need to override the state, increasing receiver's balance for each token, to simulate the
|
|
101
100
|
// state after tokens were transferred by the offRamp just before calling `ccipReceive`
|
|
102
101
|
const destAmounts: Record<string, bigint> = {}
|
|
@@ -106,25 +105,24 @@ export async function estimateExecGas({
|
|
|
106
105
|
const tokenContract = new Contract(token, TokenABI, provider) as unknown as TypedContract<
|
|
107
106
|
typeof TokenABI
|
|
108
107
|
>
|
|
109
|
-
const currentBalance = await tokenContract.balanceOf(receiver)
|
|
108
|
+
const currentBalance = await tokenContract.balanceOf(message.receiver)
|
|
110
109
|
destAmounts[token] = currentBalance
|
|
111
110
|
}
|
|
112
111
|
destAmounts[token]! += amount
|
|
113
|
-
const balancesSlot = await findBalancesSlot(token, provider, receiver, router)
|
|
112
|
+
const balancesSlot = await findBalancesSlot(token, provider, message.receiver, router)
|
|
114
113
|
stateOverrides[token] = {
|
|
115
114
|
stateDiff: {
|
|
116
|
-
[solidityPackedKeccak256(['uint256', 'uint256'], [receiver, balancesSlot])]:
|
|
117
|
-
destAmounts[token]!,
|
|
118
|
-
32,
|
|
119
|
-
),
|
|
115
|
+
[solidityPackedKeccak256(['uint256', 'uint256'], [message.receiver, balancesSlot])]:
|
|
116
|
+
toBeHex(destAmounts[token]!, 32),
|
|
120
117
|
},
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
120
|
|
|
121
|
+
const senderBytes = getAddressBytes(message.sender ?? '0x')
|
|
124
122
|
const receiverMsg: Any2EVMMessage = {
|
|
125
123
|
...message,
|
|
126
124
|
destTokenAmounts: message.destTokenAmounts ?? [],
|
|
127
|
-
sender:
|
|
125
|
+
sender: senderBytes.length < 32 ? zeroPadValue(senderBytes, 32) : hexlify(senderBytes),
|
|
128
126
|
data: hexlify(getDataBytes(message.data || '0x')),
|
|
129
127
|
sourceChainSelector: message.sourceChainSelector,
|
|
130
128
|
}
|
|
@@ -138,7 +136,7 @@ export async function estimateExecGas({
|
|
|
138
136
|
(await provider.send('eth_estimateGas', [
|
|
139
137
|
{
|
|
140
138
|
from: router,
|
|
141
|
-
to: receiver,
|
|
139
|
+
to: message.receiver,
|
|
142
140
|
data: calldata,
|
|
143
141
|
},
|
|
144
142
|
'latest',
|