@chainlink/ccip-sdk 1.1.1 → 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/chain.d.ts +53 -27
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +71 -16
- 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 -27
- 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 +2 -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/utils.js +2 -2
- package/dist/solana/utils.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/chain.ts +120 -42
- 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 -26
- package/src/extra-args.ts +18 -8
- package/src/gas.ts +8 -3
- package/src/index.ts +4 -0
- package/src/requests.ts +18 -12
- package/src/solana/utils.ts +2 -2
- package/src/ton/index.ts +47 -26
- package/src/utils.ts +10 -4
package/src/evm/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
JsonRpcProvider,
|
|
13
13
|
WebSocketProvider,
|
|
14
14
|
ZeroAddress,
|
|
15
|
+
formatUnits,
|
|
15
16
|
getAddress,
|
|
16
17
|
hexlify,
|
|
17
18
|
isBytesLike,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
isHexString,
|
|
20
21
|
keccak256,
|
|
21
22
|
toBeHex,
|
|
23
|
+
toBigInt,
|
|
22
24
|
zeroPadValue,
|
|
23
25
|
} from 'ethers'
|
|
24
26
|
import type { TypedContract } from 'ethers-abitype'
|
|
@@ -47,6 +49,7 @@ import {
|
|
|
47
49
|
CCIPHasherVersionUnsupportedError,
|
|
48
50
|
CCIPLogDataInvalidError,
|
|
49
51
|
CCIPSourceChainUnsupportedError,
|
|
52
|
+
CCIPTokenDecimalsInsufficientError,
|
|
50
53
|
CCIPTokenNotConfiguredError,
|
|
51
54
|
CCIPTokenPoolChainConfigNotFoundError,
|
|
52
55
|
CCIPTransactionNotFoundError,
|
|
@@ -692,7 +695,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
692
695
|
offRampABI = OffRamp_1_6_ABI
|
|
693
696
|
// falls through
|
|
694
697
|
case CCIPVersion.V2_0: {
|
|
695
|
-
offRampABI
|
|
698
|
+
offRampABI ??= OffRamp_2_0_ABI
|
|
696
699
|
const contract = new Contract(
|
|
697
700
|
offRamp,
|
|
698
701
|
offRampABI,
|
|
@@ -1003,9 +1006,16 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1003
1006
|
}
|
|
1004
1007
|
|
|
1005
1008
|
/**
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
+
* Generates unsigned EVM transactions for sending a CCIP message.
|
|
1010
|
+
*
|
|
1011
|
+
* @param opts - Send message options with sender address for populating transaction fields.
|
|
1012
|
+
* @returns Unsigned EVM transaction set containing 0 or more token approval txs
|
|
1013
|
+
* (if needed at the time of generation), followed by a ccipSend TransactionRequest.
|
|
1014
|
+
*
|
|
1015
|
+
* @remarks
|
|
1016
|
+
* When a token in `tokenAmounts` has `ZeroAddress` as its address, the corresponding
|
|
1017
|
+
* amount is included as native `value` in the `ccipSend` transaction instead of
|
|
1018
|
+
* going through the ERC-20 approve flow.
|
|
1009
1019
|
*/
|
|
1010
1020
|
async generateUnsignedSendMessage(
|
|
1011
1021
|
opts: Parameters<Chain['generateUnsignedSendMessage']>[0],
|
|
@@ -1138,7 +1148,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1138
1148
|
async generateUnsignedExecute(
|
|
1139
1149
|
opts: Parameters<Chain['generateUnsignedExecute']>[0],
|
|
1140
1150
|
): Promise<UnsignedEVMTx> {
|
|
1141
|
-
const { offRamp, input } = await this.resolveExecuteOpts(opts)
|
|
1151
|
+
const { offRamp, input, gasLimit } = await this.resolveExecuteOpts(opts)
|
|
1142
1152
|
if ('verifications' in input) {
|
|
1143
1153
|
const contract = new Contract(
|
|
1144
1154
|
offRamp,
|
|
@@ -1166,14 +1176,14 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1166
1176
|
messageId,
|
|
1167
1177
|
input.verifications.map(({ destAddress }) => destAddress),
|
|
1168
1178
|
input.verifications.map(({ ccvData }) => hexlify(ccvData)),
|
|
1169
|
-
BigInt(
|
|
1179
|
+
BigInt(gasLimit ?? 0),
|
|
1170
1180
|
{ from: offRamp }, // internal method
|
|
1171
1181
|
)
|
|
1172
1182
|
const execTx = await contract.execute.populateTransaction(
|
|
1173
1183
|
input.encodedMessage,
|
|
1174
1184
|
input.verifications.map(({ destAddress }) => destAddress),
|
|
1175
1185
|
input.verifications.map(({ ccvData }) => hexlify(ccvData)),
|
|
1176
|
-
BigInt(
|
|
1186
|
+
BigInt(gasLimit ?? 0),
|
|
1177
1187
|
)
|
|
1178
1188
|
execTx.gasLimit = txGasLimit + 40000n // plus `execute`'s overhead
|
|
1179
1189
|
return { family: ChainFamily.EVM, transactions: [execTx] }
|
|
@@ -1190,7 +1200,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1190
1200
|
interfaces.EVM2EVMOffRamp_v1_2,
|
|
1191
1201
|
this.provider,
|
|
1192
1202
|
) as unknown as TypedContract<typeof EVM2EVMOffRamp_1_2_ABI>
|
|
1193
|
-
const gasOverride = BigInt(
|
|
1203
|
+
const gasOverride = BigInt(gasLimit ?? 0)
|
|
1194
1204
|
manualExecTx = await contract.manuallyExecute.populateTransaction(
|
|
1195
1205
|
{
|
|
1196
1206
|
...input,
|
|
@@ -1217,9 +1227,9 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1217
1227
|
},
|
|
1218
1228
|
[
|
|
1219
1229
|
{
|
|
1220
|
-
receiverExecutionGasLimit: BigInt(
|
|
1230
|
+
receiverExecutionGasLimit: BigInt(gasLimit ?? 0),
|
|
1221
1231
|
tokenGasOverrides: input.message.tokenAmounts.map(() =>
|
|
1222
|
-
BigInt(opts.tokensGasLimit ??
|
|
1232
|
+
BigInt(opts.tokensGasLimit ?? gasLimit ?? 0),
|
|
1223
1233
|
),
|
|
1224
1234
|
},
|
|
1225
1235
|
],
|
|
@@ -1272,9 +1282,9 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1272
1282
|
[
|
|
1273
1283
|
[
|
|
1274
1284
|
{
|
|
1275
|
-
receiverExecutionGasLimit: BigInt(
|
|
1285
|
+
receiverExecutionGasLimit: BigInt(gasLimit ?? 0),
|
|
1276
1286
|
tokenGasOverrides: input.message.tokenAmounts.map(() =>
|
|
1277
|
-
BigInt(opts.tokensGasLimit ??
|
|
1287
|
+
BigInt(opts.tokensGasLimit ?? gasLimit ?? 0),
|
|
1278
1288
|
),
|
|
1279
1289
|
},
|
|
1280
1290
|
],
|
|
@@ -1288,27 +1298,27 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1288
1298
|
|
|
1289
1299
|
/* Executing a message for the first time has some hard try/catches on-chain
|
|
1290
1300
|
* so we need to ensure some lower-bounds gasLimits */
|
|
1291
|
-
let
|
|
1301
|
+
let txGasLimit = await this.provider.estimateGas(manualExecTx)
|
|
1292
1302
|
if (
|
|
1293
1303
|
'gasLimit' in input.message &&
|
|
1294
1304
|
input.message.gasLimit &&
|
|
1295
|
-
|
|
1305
|
+
txGasLimit < input.message.gasLimit + 100000n
|
|
1296
1306
|
)
|
|
1297
1307
|
// if message requested gasLimit, ensure execution more than 100k above requested, otherwise it's clearly a try/catch fail
|
|
1298
|
-
|
|
1299
|
-
else if ('gasLimit' in input.message && !input.message.gasLimit &&
|
|
1308
|
+
txGasLimit = BigInt(input.message.gasLimit) + 200000n
|
|
1309
|
+
else if ('gasLimit' in input.message && !input.message.gasLimit && txGasLimit < 240000n)
|
|
1300
1310
|
// if message didn't request gasLimit, ensure execution gasLimit is above 240k (empiric)
|
|
1301
|
-
|
|
1302
|
-
manualExecTx.gasLimit =
|
|
1311
|
+
txGasLimit = 240000n
|
|
1312
|
+
manualExecTx.gasLimit = txGasLimit
|
|
1303
1313
|
|
|
1304
1314
|
return { family: ChainFamily.EVM, transactions: [manualExecTx] }
|
|
1305
1315
|
}
|
|
1306
1316
|
|
|
1307
1317
|
/**
|
|
1308
1318
|
* {@inheritDoc Chain.execute}
|
|
1309
|
-
* @throws {@link CCIPWalletInvalidError} if wallet is not a valid Signer
|
|
1310
|
-
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
|
|
1311
|
-
* @throws {@link CCIPExecTxRevertedError} if execution transaction reverts
|
|
1319
|
+
* @throws {@link CCIPWalletInvalidError} if wallet is not a valid Signer.
|
|
1320
|
+
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm.
|
|
1321
|
+
* @throws {@link CCIPExecTxRevertedError} if execution transaction reverts.
|
|
1312
1322
|
*/
|
|
1313
1323
|
async execute(opts: Parameters<Chain['execute']>[0]) {
|
|
1314
1324
|
const wallet = opts.wallet
|
|
@@ -1399,7 +1409,16 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1399
1409
|
}
|
|
1400
1410
|
}
|
|
1401
1411
|
|
|
1402
|
-
/**
|
|
1412
|
+
/**
|
|
1413
|
+
* Fetches the token pool configuration for an EVM token pool contract.
|
|
1414
|
+
*
|
|
1415
|
+
* @param tokenPool - Token pool contract address.
|
|
1416
|
+
* @returns Token pool config containing token, router, typeAndVersion, and optionally minBlockConfirmations.
|
|
1417
|
+
*
|
|
1418
|
+
* @remarks
|
|
1419
|
+
* For pools with version \>= 2.0, also returns `minBlockConfirmations` for
|
|
1420
|
+
* Faster-Than-Finality (FTF) support. Pre-2.0 pools omit this field.
|
|
1421
|
+
*/
|
|
1403
1422
|
async getTokenPoolConfig(tokenPool: string): Promise<{
|
|
1404
1423
|
token: string
|
|
1405
1424
|
router: string
|
|
@@ -1444,7 +1463,22 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1444
1463
|
)
|
|
1445
1464
|
}
|
|
1446
1465
|
|
|
1447
|
-
/**
|
|
1466
|
+
/**
|
|
1467
|
+
* Fetches remote chain configurations for an EVM token pool contract.
|
|
1468
|
+
*
|
|
1469
|
+
* @param tokenPool - Token pool address on the current chain.
|
|
1470
|
+
* @param remoteChainSelector - Optional chain selector to filter results to a single destination.
|
|
1471
|
+
* @returns Record mapping chain names to {@link TokenPoolRemote} configs.
|
|
1472
|
+
*
|
|
1473
|
+
* @remarks
|
|
1474
|
+
* Handles 3 pool version branches:
|
|
1475
|
+
* - v1.5: single remote pool via `getRemotePool`, standard rate limiters.
|
|
1476
|
+
* - v1.6: multiple remote pools via `getRemotePools`, standard rate limiters.
|
|
1477
|
+
* - v2.0+: multiple remote pools plus FTF (Faster-Than-Finality) rate limiters
|
|
1478
|
+
* (`customBlockConfirmationsOutboundRateLimiterState` / `customBlockConfirmationsInboundRateLimiterState`).
|
|
1479
|
+
*
|
|
1480
|
+
* @throws {@link CCIPTokenPoolChainConfigNotFoundError} if remote token is not configured for a chain.
|
|
1481
|
+
*/
|
|
1448
1482
|
async getTokenPoolRemotes(
|
|
1449
1483
|
tokenPool: string,
|
|
1450
1484
|
remoteChainSelector?: bigint,
|
|
@@ -1729,10 +1763,76 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1729
1763
|
override async estimateReceiveExecution(
|
|
1730
1764
|
opts: Parameters<NonNullable<Chain['estimateReceiveExecution']>>[0],
|
|
1731
1765
|
): Promise<number> {
|
|
1766
|
+
const convertAmounts = (
|
|
1767
|
+
tokenAmounts?: readonly ((
|
|
1768
|
+
| { token: string }
|
|
1769
|
+
| { destTokenAddress: string; extraData?: string }
|
|
1770
|
+
) & {
|
|
1771
|
+
amount: bigint
|
|
1772
|
+
})[],
|
|
1773
|
+
) =>
|
|
1774
|
+
!tokenAmounts
|
|
1775
|
+
? undefined
|
|
1776
|
+
: Promise.all(
|
|
1777
|
+
tokenAmounts.map(async (ta) => {
|
|
1778
|
+
if (!('destTokenAddress' in ta)) return ta
|
|
1779
|
+
let amount = ta.amount
|
|
1780
|
+
if (isHexString(ta.extraData, 32)) {
|
|
1781
|
+
// extraData is source token decimals in most pools derived from standard TP contracts;
|
|
1782
|
+
// we can identify for it being exactly 32B and being a small integer; otherwise, assume same decimals
|
|
1783
|
+
const sourceDecimals = toBigInt(ta.extraData)
|
|
1784
|
+
if (0 < sourceDecimals && sourceDecimals <= 36) {
|
|
1785
|
+
const { decimals: destDecimals } = await this.getTokenInfo(ta.destTokenAddress)
|
|
1786
|
+
amount =
|
|
1787
|
+
(amount * BigInt(10) ** BigInt(destDecimals)) /
|
|
1788
|
+
BigInt(10) ** BigInt(sourceDecimals)
|
|
1789
|
+
if (amount === 0n)
|
|
1790
|
+
throw new CCIPTokenDecimalsInsufficientError(
|
|
1791
|
+
ta.destTokenAddress,
|
|
1792
|
+
destDecimals,
|
|
1793
|
+
this.network.name,
|
|
1794
|
+
formatUnits(amount, sourceDecimals),
|
|
1795
|
+
)
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
return { token: ta.destTokenAddress, amount }
|
|
1799
|
+
}),
|
|
1800
|
+
)
|
|
1801
|
+
|
|
1802
|
+
let opts_
|
|
1803
|
+
if (!('offRamp' in opts)) {
|
|
1804
|
+
const { lane, message, metadata } = await this.getMessageById(opts.messageId)
|
|
1805
|
+
|
|
1806
|
+
const offRamp =
|
|
1807
|
+
('offRampAddress' in message && message.offRampAddress) ||
|
|
1808
|
+
metadata?.offRamp ||
|
|
1809
|
+
(await this.apiClient!.getExecutionInput(opts.messageId)).offRamp
|
|
1810
|
+
|
|
1811
|
+
opts_ = {
|
|
1812
|
+
offRamp,
|
|
1813
|
+
message: {
|
|
1814
|
+
sourceChainSelector: lane.sourceChainSelector,
|
|
1815
|
+
messageId: message.messageId,
|
|
1816
|
+
receiver: message.receiver,
|
|
1817
|
+
sender: message.sender,
|
|
1818
|
+
data: message.data,
|
|
1819
|
+
destTokenAmounts: await convertAmounts(message.tokenAmounts),
|
|
1820
|
+
},
|
|
1821
|
+
}
|
|
1822
|
+
} else {
|
|
1823
|
+
opts_ = {
|
|
1824
|
+
...opts,
|
|
1825
|
+
message: {
|
|
1826
|
+
...opts.message,
|
|
1827
|
+
destTokenAmounts: await convertAmounts(opts.message.destTokenAmounts),
|
|
1828
|
+
},
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1732
1832
|
const destRouter = await this.getRouterForOffRamp(
|
|
1733
|
-
|
|
1734
|
-
|
|
1833
|
+
opts_.offRamp,
|
|
1834
|
+
opts_.message.sourceChainSelector,
|
|
1735
1835
|
)
|
|
1736
|
-
return estimateExecGas({ provider: this.provider, router: destRouter, ...
|
|
1836
|
+
return estimateExecGas({ provider: this.provider, router: destRouter, ...opts_ })
|
|
1737
1837
|
}
|
|
1738
1838
|
}
|
package/src/extra-args.ts
CHANGED
|
@@ -68,7 +68,7 @@ export type EVMExtraArgsV2 = EVMExtraArgsV1 & {
|
|
|
68
68
|
export type GenericExtraArgsV3 = {
|
|
69
69
|
/** Gas limit for execution on the destination chain (uint32). */
|
|
70
70
|
gasLimit: bigint
|
|
71
|
-
/** Number of block confirmations
|
|
71
|
+
/** Number of source-chain block confirmations to wait before relaying the message. */
|
|
72
72
|
blockConfirmations: number
|
|
73
73
|
/** Cross-chain verifier addresses (EVM addresses). */
|
|
74
74
|
ccvs: string[]
|
|
@@ -132,7 +132,17 @@ export type SuiExtraArgsV1 = EVMExtraArgsV2 & {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
* Union
|
|
135
|
+
* Union of all supported extra arguments formats for CCIP messages.
|
|
136
|
+
*
|
|
137
|
+
* The SDK auto-detects the correct variant based on the fields provided:
|
|
138
|
+
* - {@link EVMExtraArgsV1} - EVM legacy (gasLimit only)
|
|
139
|
+
* - {@link EVMExtraArgsV2} - EVM with out-of-order execution support
|
|
140
|
+
* - {@link GenericExtraArgsV3} - Generic V3 with minimum block confirmations, cross-chain verifiers, custom executor, and per-token receiver/args
|
|
141
|
+
* - {@link SVMExtraArgsV1} - Solana (compute units, accounts)
|
|
142
|
+
* - {@link SuiExtraArgsV1} - Sui (gas limit, receiver object IDs)
|
|
143
|
+
*
|
|
144
|
+
* @see {@link encodeExtraArgs} - Encode extra arguments for on-chain use.
|
|
145
|
+
* @see {@link decodeExtraArgs} - Decode extra arguments from bytes.
|
|
136
146
|
*/
|
|
137
147
|
export type ExtraArgs =
|
|
138
148
|
| EVMExtraArgsV1
|
|
@@ -146,10 +156,10 @@ export type ExtraArgs =
|
|
|
146
156
|
* The args are *to* a dest network, but are encoded as a message *from* this source chain.
|
|
147
157
|
* E.g. Solana uses Borsh to encode extraArgs in its produced requests, even those targeting EVM.
|
|
148
158
|
*
|
|
149
|
-
* @param args - Extra arguments to encode
|
|
150
|
-
* @param from - Source chain family for encoding format (defaults to EVM)
|
|
151
|
-
* @returns Encoded extra arguments as hex string
|
|
152
|
-
* @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported
|
|
159
|
+
* @param args - Extra arguments to encode.
|
|
160
|
+
* @param from - Source chain family for encoding format (defaults to EVM).
|
|
161
|
+
* @returns Encoded extra arguments as hex string.
|
|
162
|
+
* @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported.
|
|
153
163
|
*
|
|
154
164
|
* @example
|
|
155
165
|
* ```typescript
|
|
@@ -175,8 +185,8 @@ export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily
|
|
|
175
185
|
* @param data - Extra arguments bytearray data.
|
|
176
186
|
* @param from - Optional chain family to narrow decoding attempts.
|
|
177
187
|
* @returns Extra arguments object if found, undefined otherwise.
|
|
178
|
-
* @throws {@link CCIPChainFamilyUnsupportedError} if specified chain family not supported
|
|
179
|
-
* @throws {@link CCIPExtraArgsParseError} if data cannot be parsed as valid extra args
|
|
188
|
+
* @throws {@link CCIPChainFamilyUnsupportedError} if specified chain family not supported.
|
|
189
|
+
* @throws {@link CCIPExtraArgsParseError} if data cannot be parsed as valid extra args.
|
|
180
190
|
*
|
|
181
191
|
* @example
|
|
182
192
|
* ```typescript
|
package/src/gas.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type EstimateMessageInput = {
|
|
|
28
28
|
data?: BytesLike
|
|
29
29
|
/**
|
|
30
30
|
* optional tokenAmounts; `amount` with either source `token` (as in MessageInput) or
|
|
31
|
-
* `{ sourceTokenAddress?, sourcePoolAddress, destTokenAddress }` (as in v1.5..
|
|
31
|
+
* `{ sourceTokenAddress?, sourcePoolAddress, destTokenAddress }` (as in v1.5..v2.0 tokenAmounts)
|
|
32
32
|
* can be provided
|
|
33
33
|
*/
|
|
34
34
|
tokenAmounts?: readonly ({
|
|
@@ -122,7 +122,12 @@ export async function estimateReceiveExecution({
|
|
|
122
122
|
const tokenAmount =
|
|
123
123
|
'destTokenAddress' in ta
|
|
124
124
|
? ta
|
|
125
|
-
: await sourceToDestTokenAddresses(
|
|
125
|
+
: await sourceToDestTokenAddresses({
|
|
126
|
+
source,
|
|
127
|
+
onRamp,
|
|
128
|
+
destChainSelector: dest.network.chainSelector,
|
|
129
|
+
sourceTokenAmount: ta,
|
|
130
|
+
})
|
|
126
131
|
const sourceTokenAddress =
|
|
127
132
|
'token' in ta
|
|
128
133
|
? ta.token
|
|
@@ -147,10 +152,10 @@ export async function estimateReceiveExecution({
|
|
|
147
152
|
}),
|
|
148
153
|
)
|
|
149
154
|
return dest.estimateReceiveExecution({
|
|
150
|
-
receiver: message.receiver,
|
|
151
155
|
offRamp,
|
|
152
156
|
message: {
|
|
153
157
|
messageId: message.messageId ?? hexlify(randomBytes(32)),
|
|
158
|
+
receiver: message.receiver,
|
|
154
159
|
sender: message.sender,
|
|
155
160
|
data: message.data,
|
|
156
161
|
sourceChainSelector: source.network.chainSelector,
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,9 @@ export type {
|
|
|
12
12
|
APIErrorResponse,
|
|
13
13
|
CCIPAPIClientContext,
|
|
14
14
|
LaneLatencyResponse,
|
|
15
|
+
MessageSearchFilters,
|
|
16
|
+
MessageSearchPage,
|
|
17
|
+
MessageSearchResult,
|
|
15
18
|
} from './api/index.ts'
|
|
16
19
|
export {
|
|
17
20
|
CCIPAPIClient,
|
|
@@ -41,6 +44,7 @@ export {
|
|
|
41
44
|
type EVMExtraArgsV1,
|
|
42
45
|
type EVMExtraArgsV2,
|
|
43
46
|
type ExtraArgs,
|
|
47
|
+
type GenericExtraArgsV3,
|
|
44
48
|
type SVMExtraArgsV1,
|
|
45
49
|
type SuiExtraArgsV1,
|
|
46
50
|
decodeExtraArgs,
|
package/src/requests.ts
CHANGED
|
@@ -89,9 +89,9 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
89
89
|
k?.match(/(selector|amount|nonce|number|limit|bitmap|juels)$/i)
|
|
90
90
|
? BigInt(v as string | number | bigint)
|
|
91
91
|
: k?.match(/(^dest.*address)|(receiver|offramp|accounts)/i)
|
|
92
|
-
? decodeAddress(v as BytesLike, destFamily)
|
|
92
|
+
? decodeAddress((typeof v === 'bigint' ? v.toString() : v) as BytesLike, destFamily)
|
|
93
93
|
: k?.match(/((source.*address)|sender|issuer|origin|onramp|(feetoken$)|(token.*address$))/i)
|
|
94
|
-
? decodeAddress(v as BytesLike, sourceFamily)
|
|
94
|
+
? decodeAddress((typeof v === 'bigint' ? v.toString() : v) as BytesLike, sourceFamily)
|
|
95
95
|
: v instanceof Uint8Array ||
|
|
96
96
|
(Array.isArray(v) && v.length >= 4 && v.every((e) => typeof e === 'number'))
|
|
97
97
|
? hexlify(getDataBytes(v as readonly number[]))
|
|
@@ -456,10 +456,7 @@ export async function* getMessagesForSender(
|
|
|
456
456
|
* Resolves token routing by querying the TokenAdminRegistry and TokenPool
|
|
457
457
|
* to find the corresponding destination chain token.
|
|
458
458
|
*
|
|
459
|
-
* @param
|
|
460
|
-
* @param destChainSelector - Destination chain selector
|
|
461
|
-
* @param onRamp - OnRamp contract address
|
|
462
|
-
* @param sourceTokenAmount - Token amount object containing `token` and `amount`
|
|
459
|
+
* @param opts - options to convert source to dest token addresses
|
|
463
460
|
* @returns Extended token amount with `sourcePoolAddress`, `sourceTokenAddress`, and `destTokenAddress`
|
|
464
461
|
*
|
|
465
462
|
* @throws {@link CCIPTokenNotInRegistryError} if token is not registered in TokenAdminRegistry
|
|
@@ -479,12 +476,21 @@ export async function* getMessagesForSender(
|
|
|
479
476
|
* console.log(`Dest token: ${tokenAmount.destTokenAddress}`)
|
|
480
477
|
* ```
|
|
481
478
|
*/
|
|
482
|
-
export async function sourceToDestTokenAddresses<S extends { token: string }>(
|
|
483
|
-
source
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
sourceTokenAmount
|
|
487
|
-
|
|
479
|
+
export async function sourceToDestTokenAddresses<S extends { token: string }>({
|
|
480
|
+
source,
|
|
481
|
+
onRamp,
|
|
482
|
+
destChainSelector,
|
|
483
|
+
sourceTokenAmount,
|
|
484
|
+
}: {
|
|
485
|
+
/** Source chain instance */
|
|
486
|
+
source: Chain
|
|
487
|
+
/** OnRamp contract address */
|
|
488
|
+
onRamp: string
|
|
489
|
+
/** Destination chain selector */
|
|
490
|
+
destChainSelector: bigint
|
|
491
|
+
/** Token amount object containing `token` and `amount` */
|
|
492
|
+
sourceTokenAmount: S
|
|
493
|
+
}): Promise<
|
|
488
494
|
S & {
|
|
489
495
|
sourcePoolAddress: string
|
|
490
496
|
sourceTokenAddress: string
|
package/src/solana/utils.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
CCIPTransactionNotFinalizedError,
|
|
28
28
|
} from '../errors/index.ts'
|
|
29
29
|
import type { ChainLog, WithLogger } from '../types.ts'
|
|
30
|
-
import { getDataBytes, sleep } from '../utils.ts'
|
|
30
|
+
import { bigIntReplacer, getDataBytes, sleep } from '../utils.ts'
|
|
31
31
|
import type { IDL as BASE_TOKEN_POOL_IDL } from './idl/1.6.0/BASE_TOKEN_POOL.ts'
|
|
32
32
|
import type { UnsignedSolanaTx, Wallet } from './types.ts'
|
|
33
33
|
import type { RateLimiterState } from '../chain.ts'
|
|
@@ -347,7 +347,7 @@ export async function simulateTransaction(
|
|
|
347
347
|
throw new SendTransactionError({
|
|
348
348
|
action: 'simulate',
|
|
349
349
|
signature: '',
|
|
350
|
-
transactionMessage: JSON.stringify(result.value.err),
|
|
350
|
+
transactionMessage: JSON.stringify(result.value.err, bigIntReplacer),
|
|
351
351
|
logs: result.value.logs!,
|
|
352
352
|
})
|
|
353
353
|
}
|
package/src/ton/index.ts
CHANGED
|
@@ -3,7 +3,18 @@ import { Buffer } from 'buffer'
|
|
|
3
3
|
import { type Transaction, Address, Cell, beginCell, toNano } from '@ton/core'
|
|
4
4
|
import { TonClient } from '@ton/ton'
|
|
5
5
|
import { type AxiosAdapter, getAdapter } from 'axios'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
type BytesLike,
|
|
8
|
+
concat,
|
|
9
|
+
dataLength,
|
|
10
|
+
dataSlice,
|
|
11
|
+
hexlify,
|
|
12
|
+
isBytesLike,
|
|
13
|
+
isHexString,
|
|
14
|
+
toBeArray,
|
|
15
|
+
toBeHex,
|
|
16
|
+
toBigInt,
|
|
17
|
+
} from 'ethers'
|
|
7
18
|
import { type Memoized, memoize } from 'micro-memoize'
|
|
8
19
|
import type { PickDeep } from 'type-fest'
|
|
9
20
|
|
|
@@ -45,6 +56,7 @@ import {
|
|
|
45
56
|
bytesToBuffer,
|
|
46
57
|
createRateLimitedFetch,
|
|
47
58
|
decodeAddress,
|
|
59
|
+
getDataBytes,
|
|
48
60
|
networkInfo,
|
|
49
61
|
parseTypeAndVersion,
|
|
50
62
|
sleep,
|
|
@@ -64,6 +76,16 @@ function isTvmError(error: unknown): error is Error & { exitCode: number } {
|
|
|
64
76
|
return error instanceof Error && 'exitCode' in error && typeof error.exitCode === 'number'
|
|
65
77
|
}
|
|
66
78
|
|
|
79
|
+
function bitsToBytes(bits: string): Uint8Array {
|
|
80
|
+
return Uint8Array.from(bits.match(/.{1,8}/g)!.map((byte) => parseInt(byte.padEnd(8, '0'), 2)))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function bytesToBits(bytes: Uint8Array): string {
|
|
84
|
+
return Array.from(bytes)
|
|
85
|
+
.map((B) => B.toString(2).padStart(8, '0'))
|
|
86
|
+
.join('')
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
/**
|
|
68
90
|
* TON chain implementation supporting TON networks.
|
|
69
91
|
*
|
|
@@ -702,14 +724,14 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
|
|
|
702
724
|
*/
|
|
703
725
|
static encodeExtraArgs(args: ExtraArgs): string {
|
|
704
726
|
if ('gasLimit' in args && 'allowOutOfOrderExecution' in args) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
727
|
+
return concat([
|
|
728
|
+
EVMExtraArgsV2Tag,
|
|
729
|
+
bitsToBytes(
|
|
730
|
+
'1' +
|
|
731
|
+
bytesToBits(toBeArray(args.gasLimit, 32)) +
|
|
732
|
+
(args.allowOutOfOrderExecution ? '1' : '0'),
|
|
733
|
+
),
|
|
734
|
+
])
|
|
713
735
|
}
|
|
714
736
|
return '0x'
|
|
715
737
|
}
|
|
@@ -729,25 +751,24 @@ export class TONChain extends Chain<typeof ChainFamily.TON> {
|
|
|
729
751
|
static decodeExtraArgs(
|
|
730
752
|
extraArgs: BytesLike,
|
|
731
753
|
): (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' }) | undefined {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
754
|
+
if (dataSlice(extraArgs, 0, 4) !== EVMExtraArgsV2Tag || dataLength(extraArgs) < 5) return
|
|
755
|
+
const data = getDataBytes(extraArgs).subarray(4)
|
|
756
|
+
let bits = bytesToBits(data)
|
|
757
|
+
let gasLimit = 0n
|
|
758
|
+
if (bits[0] === '1') {
|
|
759
|
+
if (bits.length < 1 + 32 * 8) return
|
|
760
|
+
gasLimit = toBigInt(bitsToBytes(bits.substring(1, 1 + 32 * 8)))
|
|
761
|
+
bits = bits.substring(1 + 32 * 8)
|
|
762
|
+
} else {
|
|
763
|
+
bits = bits.substring(1)
|
|
764
|
+
}
|
|
738
765
|
|
|
739
|
-
|
|
740
|
-
const magicTag = slice.loadUint(32)
|
|
741
|
-
if (magicTag !== Number(EVMExtraArgsV2Tag)) return undefined
|
|
766
|
+
const allowOutOfOrderExecution = bits[0] === '1'
|
|
742
767
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
} catch {
|
|
749
|
-
// Return undefined for any parsing errors (invalid BOC, malformed data, etc.)
|
|
750
|
-
return undefined
|
|
768
|
+
return {
|
|
769
|
+
_tag: 'EVMExtraArgsV2',
|
|
770
|
+
gasLimit,
|
|
771
|
+
allowOutOfOrderExecution,
|
|
751
772
|
}
|
|
752
773
|
}
|
|
753
774
|
|
package/src/utils.ts
CHANGED
|
@@ -190,10 +190,16 @@ export const networkInfo = memoize(function networkInfo_(
|
|
|
190
190
|
|
|
191
191
|
const BLOCK_RANGE = 10_000
|
|
192
192
|
/**
|
|
193
|
-
* Generates
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
|
|
193
|
+
* Generates block ranges for paginated log queries.
|
|
194
|
+
*
|
|
195
|
+
* @param params - Range parameters:
|
|
196
|
+
* - `singleBlock` - yields a single `{ fromBlock, toBlock }` for that block.
|
|
197
|
+
* - `endBlock` + optional `startBlock` - if `startBlock` is given, moves forward
|
|
198
|
+
* from there up to `endBlock`; otherwise moves backward from `endBlock` to genesis.
|
|
199
|
+
* - `page` - step size per range (default 10 000).
|
|
200
|
+
* @returns Generator of `{ fromBlock, toBlock }` pairs, optionally with a `progress` percentage
|
|
201
|
+
* string when iterating forward.
|
|
202
|
+
*/
|
|
197
203
|
export function* blockRangeGenerator(
|
|
198
204
|
params: { page?: number } & ({ endBlock: number; startBlock?: number } | { singleBlock: number }),
|
|
199
205
|
) {
|