@chainlink/ccip-sdk 1.3.1 → 1.4.1
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 +17 -6
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +17 -6
- package/dist/api/index.js.map +1 -1
- package/dist/aptos/index.d.ts +7 -1
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +20 -0
- package/dist/aptos/index.js.map +1 -1
- package/dist/chain.d.ts +65 -7
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +47 -3
- package/dist/chain.js.map +1 -1
- package/dist/errors/codes.d.ts +1 -2
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +1 -2
- 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 +2 -3
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +23 -28
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +33 -37
- package/dist/errors/specialized.js.map +1 -1
- package/dist/evm/const.d.ts.map +1 -1
- package/dist/evm/const.js +1 -0
- package/dist/evm/const.js.map +1 -1
- package/dist/evm/errors.d.ts.map +1 -1
- package/dist/evm/errors.js +20 -5
- package/dist/evm/errors.js.map +1 -1
- package/dist/evm/extra-args.d.ts.map +1 -1
- package/dist/evm/extra-args.js +14 -13
- package/dist/evm/extra-args.js.map +1 -1
- package/dist/evm/index.d.ts +11 -2
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +73 -22
- package/dist/evm/index.js.map +1 -1
- package/dist/gas.d.ts +2 -1
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +2 -1
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/offchain.d.ts +1 -0
- package/dist/offchain.d.ts.map +1 -1
- package/dist/offchain.js +1 -0
- package/dist/offchain.js.map +1 -1
- package/dist/requests.d.ts +7 -6
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +7 -8
- package/dist/requests.js.map +1 -1
- package/dist/solana/idl/1.6.0/FEE_QUOTER.d.ts +1719 -0
- package/dist/solana/idl/1.6.0/FEE_QUOTER.d.ts.map +1 -0
- package/dist/solana/idl/1.6.0/FEE_QUOTER.js +1719 -0
- package/dist/solana/idl/1.6.0/FEE_QUOTER.js.map +1 -0
- package/dist/solana/index.d.ts +34 -18
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +45 -5
- package/dist/solana/index.js.map +1 -1
- package/dist/solana/utils.d.ts +5 -2
- package/dist/solana/utils.d.ts.map +1 -1
- package/dist/solana/utils.js +5 -2
- package/dist/solana/utils.js.map +1 -1
- package/dist/sui/index.d.ts +1 -1
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +14 -14
- package/dist/sui/index.js.map +1 -1
- package/dist/ton/index.d.ts +11 -9
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +24 -26
- package/dist/ton/index.js.map +1 -1
- package/dist/ton/send.d.ts +7 -0
- package/dist/ton/send.d.ts.map +1 -1
- package/dist/ton/send.js +7 -0
- package/dist/ton/send.js.map +1 -1
- package/dist/utils.d.ts +9 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +10 -3
- package/dist/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/api/index.ts +17 -6
- package/src/aptos/index.ts +31 -0
- package/src/chain.ts +80 -8
- package/src/errors/codes.ts +1 -2
- package/src/errors/index.ts +1 -2
- package/src/errors/recovery.ts +2 -3
- package/src/errors/specialized.ts +35 -38
- package/src/evm/const.ts +1 -0
- package/src/evm/errors.ts +22 -5
- package/src/evm/extra-args.ts +15 -14
- package/src/evm/index.ts +110 -21
- package/src/gas.ts +2 -1
- package/src/index.ts +1 -0
- package/src/offchain.ts +1 -0
- package/src/requests.ts +8 -8
- package/src/solana/idl/1.6.0/FEE_QUOTER.ts +3440 -0
- package/src/solana/index.ts +60 -4
- package/src/solana/utils.ts +5 -2
- package/src/sui/index.ts +17 -15
- package/src/ton/index.ts +23 -31
- package/src/ton/send.ts +7 -0
- package/src/utils.ts +10 -3
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import type { BytesLike } from 'ethers'
|
|
2
|
+
|
|
1
3
|
import { type CCIPErrorOptions, CCIPError } from './CCIPError.ts'
|
|
2
4
|
import { CCIPErrorCode } from './codes.ts'
|
|
3
5
|
import { isTransientHttpStatus } from '../http-status.ts'
|
|
4
|
-
import {
|
|
6
|
+
import type { ChainFamily } from '../types.ts'
|
|
7
|
+
import { bigIntReplacer, getAddressBytes, util } from '../utils.ts'
|
|
5
8
|
|
|
6
9
|
// Chain/Network
|
|
7
10
|
|
|
@@ -987,7 +990,12 @@ export class CCIPUsdcAttestationError extends CCIPError {
|
|
|
987
990
|
*/
|
|
988
991
|
export class CCIPUsdcBurnFeesError extends CCIPError {
|
|
989
992
|
override readonly name = 'CCIPUsdcBurnFeesError'
|
|
990
|
-
/**
|
|
993
|
+
/**
|
|
994
|
+
* Creates a USDC burn fees error.
|
|
995
|
+
* @param sourceDomain - CCTP source domain identifier.
|
|
996
|
+
* @param destDomain - CCTP destination domain identifier.
|
|
997
|
+
* @param httpStatus - HTTP status code from the failed request.
|
|
998
|
+
*/
|
|
991
999
|
constructor(sourceDomain: number, destDomain: number, httpStatus: number) {
|
|
992
1000
|
super(
|
|
993
1001
|
CCIPErrorCode.USDC_BURN_FEES_FAILED,
|
|
@@ -1240,7 +1248,11 @@ export class CCIPTimeoutError extends CCIPError {
|
|
|
1240
1248
|
*/
|
|
1241
1249
|
export class CCIPAbortError extends CCIPError {
|
|
1242
1250
|
override readonly name = 'CCIPAbortError'
|
|
1243
|
-
/**
|
|
1251
|
+
/**
|
|
1252
|
+
* Creates an abort error.
|
|
1253
|
+
* @param operation - Name of the operation that was aborted.
|
|
1254
|
+
* @param options - Optional error options.
|
|
1255
|
+
*/
|
|
1244
1256
|
constructor(operation: string, options?: CCIPErrorOptions) {
|
|
1245
1257
|
super(CCIPErrorCode.ABORT, `Request aborted: ${operation}`, {
|
|
1246
1258
|
...options,
|
|
@@ -1853,14 +1865,22 @@ export class CCIPMerkleInternalError extends CCIPError {
|
|
|
1853
1865
|
* }
|
|
1854
1866
|
* ```
|
|
1855
1867
|
*/
|
|
1856
|
-
export class
|
|
1857
|
-
override readonly name = '
|
|
1858
|
-
/** Creates an
|
|
1859
|
-
constructor(address:
|
|
1860
|
-
|
|
1868
|
+
export class CCIPAddressInvalidError extends CCIPError {
|
|
1869
|
+
override readonly name = 'CCIPAddressInvalidError'
|
|
1870
|
+
/** Creates an address invalid error for the given chain family. */
|
|
1871
|
+
constructor(address: BytesLike, family: ChainFamily, options?: CCIPErrorOptions) {
|
|
1872
|
+
const len = address.length
|
|
1873
|
+
const type = typeof address === 'object' ? address.constructor.name : typeof address
|
|
1874
|
+
let bytesLen
|
|
1875
|
+
try {
|
|
1876
|
+
bytesLen = getAddressBytes(address).length
|
|
1877
|
+
} catch (err) {
|
|
1878
|
+
bytesLen = (err as Error).message
|
|
1879
|
+
}
|
|
1880
|
+
super(CCIPErrorCode.ADDRESS_INVALID, `Invalid ${family} address: ${util.inspect(address)}`, {
|
|
1861
1881
|
...options,
|
|
1862
1882
|
isTransient: false,
|
|
1863
|
-
context: { ...options?.context, address },
|
|
1883
|
+
context: { ...options?.context, address, family, len, type, bytesLen },
|
|
1864
1884
|
})
|
|
1865
1885
|
}
|
|
1866
1886
|
}
|
|
@@ -2556,34 +2576,6 @@ export class CCIPAptosLogInvalidError extends CCIPError {
|
|
|
2556
2576
|
}
|
|
2557
2577
|
}
|
|
2558
2578
|
|
|
2559
|
-
/**
|
|
2560
|
-
* Thrown when Aptos address is invalid.
|
|
2561
|
-
*
|
|
2562
|
-
* @example
|
|
2563
|
-
* ```typescript
|
|
2564
|
-
* import { CCIPDataFormatUnsupportedError } from '@chainlink/ccip-sdk'
|
|
2565
|
-
*
|
|
2566
|
-
* try {
|
|
2567
|
-
* AptosChain.getAddress('invalid-address')
|
|
2568
|
-
* } catch (error) {
|
|
2569
|
-
* if (error instanceof CCIPDataFormatUnsupportedError) {
|
|
2570
|
-
* console.log(`Invalid address: ${error.message}`)
|
|
2571
|
-
* }
|
|
2572
|
-
* }
|
|
2573
|
-
* ```
|
|
2574
|
-
*/
|
|
2575
|
-
export class CCIPAptosAddressInvalidError extends CCIPError {
|
|
2576
|
-
override readonly name = 'CCIPAptosAddressInvalidError'
|
|
2577
|
-
/** Creates an Aptos address invalid error. */
|
|
2578
|
-
constructor(address: string, options?: CCIPErrorOptions) {
|
|
2579
|
-
super(CCIPErrorCode.ADDRESS_INVALID_APTOS, `Invalid aptos address: "${address}"`, {
|
|
2580
|
-
...options,
|
|
2581
|
-
isTransient: false,
|
|
2582
|
-
context: { ...options?.context, address },
|
|
2583
|
-
})
|
|
2584
|
-
}
|
|
2585
|
-
}
|
|
2586
|
-
|
|
2587
2579
|
/**
|
|
2588
2580
|
* Thrown when Aptos can only encode specific extra args types.
|
|
2589
2581
|
*
|
|
@@ -3429,7 +3421,12 @@ export class CCIPApiClientNotAvailableError extends CCIPError {
|
|
|
3429
3421
|
*/
|
|
3430
3422
|
export class CCIPUnexpectedPaginationError extends CCIPError {
|
|
3431
3423
|
override readonly name = 'CCIPUnexpectedPaginationError'
|
|
3432
|
-
/**
|
|
3424
|
+
/**
|
|
3425
|
+
* Creates an unexpected pagination error.
|
|
3426
|
+
* @param txHash - Source transaction hash.
|
|
3427
|
+
* @param messageCount - Number of messages returned in the first page.
|
|
3428
|
+
* @param options - Optional error options.
|
|
3429
|
+
*/
|
|
3433
3430
|
constructor(txHash: string, messageCount: number, options?: CCIPErrorOptions) {
|
|
3434
3431
|
super(
|
|
3435
3432
|
CCIPErrorCode.API_UNEXPECTED_PAGINATION,
|
package/src/evm/const.ts
CHANGED
|
@@ -33,6 +33,7 @@ const customErrors = [
|
|
|
33
33
|
'error NotEnoughGas()',
|
|
34
34
|
'error InvalidChain(uint64 chainSelector)',
|
|
35
35
|
'error InvalidAdapter()',
|
|
36
|
+
'error BlacklistableBlacklistedAccount(address)',
|
|
36
37
|
] as const
|
|
37
38
|
|
|
38
39
|
export const VersionedContractABI = parseAbi(['function typeAndVersion() view returns (string)'])
|
package/src/evm/errors.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { defaultAbiCoder, interfaces } from './const.ts'
|
|
15
15
|
import { decodeExtraArgs } from '../extra-args.ts'
|
|
16
16
|
import { ChainFamily } from '../types.ts'
|
|
17
|
+
import { networkInfo } from '../utils.ts'
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Get error data from an error object, if possible
|
|
@@ -151,6 +152,16 @@ export function recursiveParseError(
|
|
|
151
152
|
)
|
|
152
153
|
}
|
|
153
154
|
if (!isBytesLike(data) || [0, 20].includes(dataLength(data))) {
|
|
155
|
+
// include networkName for chainSelectors
|
|
156
|
+
if (key.match(/sel(ector)?$/i) && typeof data === 'bigint') {
|
|
157
|
+
let name
|
|
158
|
+
try {
|
|
159
|
+
;({ name } = networkInfo(data))
|
|
160
|
+
} catch {
|
|
161
|
+
// ignore
|
|
162
|
+
}
|
|
163
|
+
if (name) return [[key, `${data} [${name}]`]]
|
|
164
|
+
}
|
|
154
165
|
return [[key, data]]
|
|
155
166
|
}
|
|
156
167
|
try {
|
|
@@ -166,14 +177,16 @@ export function recursiveParseError(
|
|
|
166
177
|
if (!parsed) return [[key, data]]
|
|
167
178
|
const [fragment, _, args] = parsed
|
|
168
179
|
const desc = fragment.format('full')
|
|
169
|
-
|
|
170
|
-
const res = [[
|
|
180
|
+
const key_ = j(key, desc.split(' ')[0]!)
|
|
181
|
+
const res = [[key_, desc.substring(desc.indexOf(' ') + 1)]] as ReturnType<
|
|
182
|
+
typeof recursiveParseError
|
|
183
|
+
>
|
|
171
184
|
if (!args) return res
|
|
172
185
|
if (['ReceiverError', 'TokenHandlingError'].includes(fragment.name) && args.err === '0x') {
|
|
173
|
-
res.push([`${
|
|
186
|
+
res.push([`${key_}.err`, '0x [possibly out-of-gas or abi.decode error]'])
|
|
174
187
|
return res
|
|
175
188
|
}
|
|
176
|
-
res.push(...recursiveParseError(
|
|
189
|
+
res.push(...recursiveParseError(key, args))
|
|
177
190
|
return res
|
|
178
191
|
}
|
|
179
192
|
|
|
@@ -187,7 +200,11 @@ export function parseData(data: unknown): Record<string, unknown> | undefined {
|
|
|
187
200
|
if (isHexString(data)) {
|
|
188
201
|
const parsed = recursiveParseError('', data)
|
|
189
202
|
if (parsed.length === 1 && parsed[0]![1] === data) return
|
|
190
|
-
|
|
203
|
+
// like Object.fromEntries, but on duplicated keys, add a space to first occurrence, to avoid overwriting and keep all values
|
|
204
|
+
return parsed.reduceRight(
|
|
205
|
+
(acc, [k, v]) => ({ ...{ [k && k in acc ? k + ' ' : k]: v }, ...acc }),
|
|
206
|
+
{},
|
|
207
|
+
)
|
|
191
208
|
}
|
|
192
209
|
if (typeof data !== 'object') return
|
|
193
210
|
// ethers tx/simulation/call errors
|
package/src/evm/extra-args.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
encodeBase58,
|
|
6
6
|
getAddress,
|
|
7
7
|
hexlify,
|
|
8
|
-
|
|
8
|
+
toBeArray,
|
|
9
9
|
toBigInt,
|
|
10
10
|
toNumber,
|
|
11
11
|
zeroPadValue,
|
|
@@ -25,7 +25,8 @@ import {
|
|
|
25
25
|
SuiExtraArgsV1Tag,
|
|
26
26
|
} from '../extra-args.ts'
|
|
27
27
|
import { DEFAULT_GAS_LIMIT } from '../shared/constants.ts'
|
|
28
|
-
import {
|
|
28
|
+
import { ChainFamily } from '../types.ts'
|
|
29
|
+
import { decodeAddress, getAddressBytes, getDataBytes } from '../utils.ts'
|
|
29
30
|
import { defaultAbiCoder } from './const.ts'
|
|
30
31
|
import { resultToObject } from './types.ts'
|
|
31
32
|
|
|
@@ -60,16 +61,16 @@ const SuiExtraArgsV1ABI =
|
|
|
60
61
|
* - tokenArgs (variable)
|
|
61
62
|
*/
|
|
62
63
|
function encodeExtraArgsV3(args: GenericExtraArgsV3): string {
|
|
63
|
-
const parts:
|
|
64
|
+
const parts: BytesLike[] = []
|
|
64
65
|
|
|
65
66
|
// Tag (4 bytes)
|
|
66
|
-
parts.push(
|
|
67
|
+
parts.push(GenericExtraArgsV3Tag)
|
|
67
68
|
|
|
68
69
|
// gasLimit (4 bytes, uint32 big-endian)
|
|
69
|
-
parts.push(
|
|
70
|
+
parts.push(toBeArray(args.gasLimit, 4))
|
|
70
71
|
|
|
71
72
|
// blockConfirmations (2 bytes, uint16 big-endian)
|
|
72
|
-
parts.push(
|
|
73
|
+
parts.push(toBeArray(args.blockConfirmations, 2))
|
|
73
74
|
|
|
74
75
|
// ccvsLength (1 byte)
|
|
75
76
|
parts.push(new Uint8Array([args.ccvs.length]))
|
|
@@ -83,14 +84,14 @@ function encodeExtraArgsV3(args: GenericExtraArgsV3): string {
|
|
|
83
84
|
// ccvAddressLength = 20
|
|
84
85
|
parts.push(new Uint8Array([20]))
|
|
85
86
|
// ccvAddress (20 bytes)
|
|
86
|
-
parts.push(
|
|
87
|
+
parts.push(decodeAddress(ccvAddress, ChainFamily.EVM))
|
|
87
88
|
} else {
|
|
88
89
|
// ccvAddressLength = 0
|
|
89
90
|
parts.push(new Uint8Array([0]))
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
// ccvArgsLength (2 bytes, uint16 big-endian)
|
|
93
|
-
parts.push(
|
|
94
|
+
parts.push(toBeArray(ccvArgsBytes.length, 2))
|
|
94
95
|
|
|
95
96
|
// ccvArgs (variable)
|
|
96
97
|
if (ccvArgsBytes.length > 0) {
|
|
@@ -99,26 +100,25 @@ function encodeExtraArgsV3(args: GenericExtraArgsV3): string {
|
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
// executorLength (1 byte)
|
|
102
|
-
if (args.executor && args.executor !== '
|
|
103
|
+
if (args.executor && args.executor !== '0x') {
|
|
103
104
|
parts.push(new Uint8Array([20]))
|
|
104
|
-
parts.push(
|
|
105
|
+
parts.push(decodeAddress(args.executor, ChainFamily.EVM))
|
|
105
106
|
} else {
|
|
106
107
|
parts.push(new Uint8Array([0]))
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
// Convert BytesLike fields to Uint8Array
|
|
110
111
|
const executorArgsBytes = getDataBytes(args.executorArgs)
|
|
111
|
-
const tokenReceiverBytes = getDataBytes(args.tokenReceiver)
|
|
112
|
-
const tokenArgsBytes = getDataBytes(args.tokenArgs)
|
|
113
112
|
|
|
114
113
|
// executorArgsLength (2 bytes, uint16 big-endian)
|
|
115
|
-
parts.push(
|
|
114
|
+
parts.push(toBeArray(executorArgsBytes.length, 2))
|
|
116
115
|
|
|
117
116
|
// executorArgs (variable)
|
|
118
117
|
if (executorArgsBytes.length > 0) {
|
|
119
118
|
parts.push(executorArgsBytes)
|
|
120
119
|
}
|
|
121
120
|
|
|
121
|
+
const tokenReceiverBytes = getAddressBytes(args.tokenReceiver)
|
|
122
122
|
// tokenReceiverLength (1 byte)
|
|
123
123
|
parts.push(new Uint8Array([tokenReceiverBytes.length]))
|
|
124
124
|
|
|
@@ -127,8 +127,9 @@ function encodeExtraArgsV3(args: GenericExtraArgsV3): string {
|
|
|
127
127
|
parts.push(tokenReceiverBytes)
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
const tokenArgsBytes = getDataBytes(args.tokenArgs)
|
|
130
131
|
// tokenArgsLength (2 bytes, uint16 big-endian)
|
|
131
|
-
parts.push(
|
|
132
|
+
parts.push(toBeArray(tokenArgsBytes.length, 2))
|
|
132
133
|
|
|
133
134
|
// tokenArgs (variable)
|
|
134
135
|
if (tokenArgsBytes.length > 0) {
|
package/src/evm/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
type LogFilter,
|
|
35
35
|
type RateLimiterState,
|
|
36
36
|
type TokenPoolRemote,
|
|
37
|
+
type TokenPrice,
|
|
37
38
|
type TokenTransferFeeConfig,
|
|
38
39
|
type TokenTransferFeeOpts,
|
|
39
40
|
type TotalFeesEstimate,
|
|
@@ -41,7 +42,7 @@ import {
|
|
|
41
42
|
LaneFeature,
|
|
42
43
|
} from '../chain.ts'
|
|
43
44
|
import {
|
|
44
|
-
|
|
45
|
+
CCIPAddressInvalidError,
|
|
45
46
|
CCIPBlockNotFoundError,
|
|
46
47
|
CCIPContractNotRouterError,
|
|
47
48
|
CCIPContractTypeInvalidError,
|
|
@@ -56,7 +57,6 @@ import {
|
|
|
56
57
|
CCIPTokenNotConfiguredError,
|
|
57
58
|
CCIPTokenPoolChainConfigNotFoundError,
|
|
58
59
|
CCIPTransactionNotFoundError,
|
|
59
|
-
CCIPVersionFeatureUnavailableError,
|
|
60
60
|
CCIPVersionRequiresLaneError,
|
|
61
61
|
CCIPVersionUnsupportedError,
|
|
62
62
|
CCIPWalletInvalidError,
|
|
@@ -87,6 +87,7 @@ import {
|
|
|
87
87
|
decodeOnRampAddress,
|
|
88
88
|
getAddressBytes,
|
|
89
89
|
getDataBytes,
|
|
90
|
+
getSomeBlockNumberBefore,
|
|
90
91
|
networkInfo,
|
|
91
92
|
parseTypeAndVersion,
|
|
92
93
|
} from '../utils.ts'
|
|
@@ -250,6 +251,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
250
251
|
this.getFeeTokens = memoize(this.getFeeTokens.bind(this), { async: true, maxArgs: 1 })
|
|
251
252
|
this.detectUsdcDomains = memoize(this.detectUsdcDomains.bind(this))
|
|
252
253
|
this.resolveVerifier = memoize(this.resolveVerifier.bind(this))
|
|
254
|
+
this.getFeeQuoterFor = memoize(this.getFeeQuoterFor.bind(this), {
|
|
255
|
+
async: true,
|
|
256
|
+
maxArgs: 1,
|
|
257
|
+
})
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
/**
|
|
@@ -555,16 +560,16 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
555
560
|
*/
|
|
556
561
|
static getAddress(bytes: BytesLike): string {
|
|
557
562
|
if (isHexString(bytes, 20)) return getAddress(bytes)
|
|
558
|
-
|
|
559
|
-
if (
|
|
560
|
-
else if (
|
|
561
|
-
if (
|
|
562
|
-
|
|
563
|
+
let bytes_ = getAddressBytes(bytes)
|
|
564
|
+
if (bytes_.length < 20) throw new CCIPAddressInvalidError(bytes, this.family)
|
|
565
|
+
else if (bytes_.length > 20) {
|
|
566
|
+
if (bytes_.slice(0, bytes_.length - 20).every((b) => b === 0)) {
|
|
567
|
+
bytes_ = bytes_.slice(-20)
|
|
563
568
|
} else {
|
|
564
|
-
throw new
|
|
569
|
+
throw new CCIPAddressInvalidError(hexlify(bytes_), this.family)
|
|
565
570
|
}
|
|
566
571
|
}
|
|
567
|
-
return getAddress(hexlify(
|
|
572
|
+
return getAddress(hexlify(bytes_))
|
|
568
573
|
}
|
|
569
574
|
|
|
570
575
|
/**
|
|
@@ -970,17 +975,26 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
970
975
|
* @throws {@link CCIPVersionFeatureUnavailableError} if contract version is below v1.6
|
|
971
976
|
*/
|
|
972
977
|
async getFeeQuoterFor(address: string): Promise<string> {
|
|
973
|
-
|
|
974
|
-
if (type === 'FeeQuoter') {
|
|
978
|
+
const [type, version, typeAndVersion] = await this.typeAndVersion(address)
|
|
979
|
+
if (type === 'FeeQuoter' || type === 'PriceRegistry') {
|
|
975
980
|
return address
|
|
976
981
|
} else if (type === 'Router') {
|
|
977
|
-
|
|
978
|
-
;[type, version, typeAndVersion] = await this.typeAndVersion(address)
|
|
982
|
+
return this.getFeeQuoterFor(await this._getSomeOnRampFor(address)) // use cache
|
|
979
983
|
} else if (!type.includes('Ramp')) {
|
|
980
984
|
throw new CCIPContractNotRouterError(address, typeAndVersion)
|
|
981
985
|
}
|
|
982
|
-
|
|
983
|
-
|
|
986
|
+
|
|
987
|
+
if (version < CCIPVersion.V1_6) {
|
|
988
|
+
const contract = new Contract(
|
|
989
|
+
address,
|
|
990
|
+
version === CCIPVersion.V1_2
|
|
991
|
+
? interfaces.EVM2EVMOnRamp_v1_2
|
|
992
|
+
: interfaces.EVM2EVMOnRamp_v1_5,
|
|
993
|
+
this.provider,
|
|
994
|
+
) as unknown as TypedContract<typeof EVM2EVMOnRamp_1_2_ABI | typeof EVM2EVMOnRamp_1_5_ABI>
|
|
995
|
+
const { priceRegistry } = await contract.getDynamicConfig()
|
|
996
|
+
return priceRegistry as string
|
|
997
|
+
}
|
|
984
998
|
|
|
985
999
|
const isOnRamp = type.includes('OnRamp')
|
|
986
1000
|
const contract = new Contract(
|
|
@@ -1017,7 +1031,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1017
1031
|
this.provider,
|
|
1018
1032
|
) as unknown as TypedContract<typeof Router_ABI>
|
|
1019
1033
|
return contract.getFee(destChainSelector, {
|
|
1020
|
-
receiver:
|
|
1034
|
+
receiver: (() => {
|
|
1035
|
+
const receiverBytes = getAddressBytes(populatedMessage.receiver)
|
|
1036
|
+
return receiverBytes.length <= 32 ? zeroPadValue(receiverBytes, 32) : hexlify(receiverBytes)
|
|
1037
|
+
})(),
|
|
1021
1038
|
data: hexlify(populatedMessage.data ?? '0x'),
|
|
1022
1039
|
tokenAmounts: populatedMessage.tokenAmounts ?? [],
|
|
1023
1040
|
feeToken: populatedMessage.feeToken ?? ZeroAddress,
|
|
@@ -1133,6 +1150,52 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1133
1150
|
return undefined
|
|
1134
1151
|
}
|
|
1135
1152
|
|
|
1153
|
+
/** {@inheritDoc Chain.getTokenPrice} */
|
|
1154
|
+
override async getTokenPrice(opts: {
|
|
1155
|
+
router: string
|
|
1156
|
+
token: string
|
|
1157
|
+
timestamp?: number
|
|
1158
|
+
}): Promise<TokenPrice> {
|
|
1159
|
+
let { token } = opts
|
|
1160
|
+
|
|
1161
|
+
// Resolve native token (ZeroAddress) to wrapped native
|
|
1162
|
+
if (token === ZeroAddress) {
|
|
1163
|
+
token = await this.getNativeTokenForRouter(opts.router)
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
const priceContractAddress = await this.getFeeQuoterFor(opts.router)
|
|
1167
|
+
|
|
1168
|
+
// Both PriceRegistry (v1.2/v1.5) and FeeQuoter (v1.6+) expose
|
|
1169
|
+
// getTokenPrice(address) → { value: uint224, timestamp: uint32 }
|
|
1170
|
+
const contract = new Contract(
|
|
1171
|
+
priceContractAddress,
|
|
1172
|
+
interfaces.FeeQuoter,
|
|
1173
|
+
this.provider,
|
|
1174
|
+
) as unknown as TypedContract<typeof FeeQuoter_ABI>
|
|
1175
|
+
|
|
1176
|
+
// If timestamp provided, resolve to block number for historical query
|
|
1177
|
+
let blockTag: number | undefined
|
|
1178
|
+
if (opts.timestamp != null) {
|
|
1179
|
+
const { number: latestBlock } = (await this.provider.getBlock('latest'))!
|
|
1180
|
+
blockTag = await getSomeBlockNumberBefore(
|
|
1181
|
+
async (block: number) => (await this.provider.getBlock(block))!.timestamp,
|
|
1182
|
+
latestBlock,
|
|
1183
|
+
opts.timestamp,
|
|
1184
|
+
this,
|
|
1185
|
+
)
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
const [result, { decimals }] = await Promise.all([
|
|
1189
|
+
blockTag != null
|
|
1190
|
+
? contract.getTokenPrice.staticCall(token, { blockTag })
|
|
1191
|
+
: contract.getTokenPrice(token),
|
|
1192
|
+
this.getTokenInfo(token),
|
|
1193
|
+
])
|
|
1194
|
+
|
|
1195
|
+
const rawPrice = BigInt(result.value)
|
|
1196
|
+
return { price: Number(rawPrice) * 10 ** (decimals - 36) }
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1136
1199
|
/** {@inheritDoc Chain.getTotalFeesEstimate} */
|
|
1137
1200
|
override async getTotalFeesEstimate(
|
|
1138
1201
|
opts: Parameters<Chain['getTotalFeesEstimate']>[0],
|
|
@@ -1152,7 +1215,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1152
1215
|
let tokenArgs: string = '0x'
|
|
1153
1216
|
if (extraArgs && 'blockConfirmations' in extraArgs) {
|
|
1154
1217
|
blockConfirmations = extraArgs.blockConfirmations as number
|
|
1155
|
-
tokenArgs = hexlify(extraArgs.tokenArgs
|
|
1218
|
+
if (extraArgs.tokenArgs) tokenArgs = hexlify(extraArgs.tokenArgs)
|
|
1156
1219
|
}
|
|
1157
1220
|
|
|
1158
1221
|
// Skip pool-level fee lookup for pre-v2.0 lanes
|
|
@@ -1257,7 +1320,9 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1257
1320
|
}
|
|
1258
1321
|
|
|
1259
1322
|
const feeToken = message.feeToken ?? ZeroAddress
|
|
1260
|
-
const
|
|
1323
|
+
const receiverBytes = getAddressBytes(message.receiver)
|
|
1324
|
+
const receiver =
|
|
1325
|
+
receiverBytes.length <= 32 ? zeroPadValue(receiverBytes, 32) : hexlify(receiverBytes)
|
|
1261
1326
|
const data = hexlify(message.data ?? '0x')
|
|
1262
1327
|
const extraArgs = hexlify(
|
|
1263
1328
|
(this.constructor as typeof EVMChain).encodeExtraArgs(message.extraArgs),
|
|
@@ -1639,7 +1704,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1639
1704
|
* Fetches the token pool configuration for an EVM token pool contract.
|
|
1640
1705
|
*
|
|
1641
1706
|
* @param tokenPool - Token pool contract address.
|
|
1642
|
-
* @param feeOpts - Optional parameters to also fetch token transfer fee config
|
|
1707
|
+
* @param feeOpts - Optional parameters to also fetch token transfer fee config:
|
|
1708
|
+
* - `destChainSelector` — destination chain selector.
|
|
1709
|
+
* - `blockConfirmationsRequested` — number of block confirmations (0 = standard, positive = FTF).
|
|
1710
|
+
* - `tokenArgs` — hex-encoded bytes passed to the pool contract.
|
|
1643
1711
|
* @returns Token pool config containing token, router, typeAndVersion, and optionally
|
|
1644
1712
|
* minBlockConfirmations and tokenTransferFeeConfig.
|
|
1645
1713
|
*
|
|
@@ -1658,7 +1726,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1658
1726
|
minBlockConfirmations?: number
|
|
1659
1727
|
tokenTransferFeeConfig?: TokenTransferFeeConfig
|
|
1660
1728
|
}> {
|
|
1661
|
-
const [
|
|
1729
|
+
const [type, version, typeAndVersion] = await this.typeAndVersion(tokenPool)
|
|
1662
1730
|
|
|
1663
1731
|
let token, router, minBlockConfirmations, tokenTransferFeeConfig
|
|
1664
1732
|
if (version < CCIPVersion.V2_0) {
|
|
@@ -1670,6 +1738,14 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1670
1738
|
token = contract.getToken()
|
|
1671
1739
|
router = contract.getRouter()
|
|
1672
1740
|
} else {
|
|
1741
|
+
if (type === 'USDCTokenPoolProxy') {
|
|
1742
|
+
const proxy = new Contract(
|
|
1743
|
+
tokenPool,
|
|
1744
|
+
interfaces.USDCTokenPoolProxy_v2_0,
|
|
1745
|
+
this.provider,
|
|
1746
|
+
) as unknown as TypedContract<typeof USDCTokenPoolProxy_2_0_ABI>
|
|
1747
|
+
tokenPool = (await proxy.getPools())['cctpV2PoolWithCCV'] as string
|
|
1748
|
+
}
|
|
1673
1749
|
const contract = new Contract(
|
|
1674
1750
|
tokenPool,
|
|
1675
1751
|
interfaces.TokenPool_v2_0,
|
|
@@ -1678,6 +1754,11 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1678
1754
|
token = contract.getToken()
|
|
1679
1755
|
router = contract.getDynamicConfig().then(([router]) => router)
|
|
1680
1756
|
minBlockConfirmations = contract.getMinBlockConfirmations().catch((err) => {
|
|
1757
|
+
this.logger.debug(
|
|
1758
|
+
typeAndVersion,
|
|
1759
|
+
'threw when fetching minBlockConfirmations, defaulting to 0:',
|
|
1760
|
+
err,
|
|
1761
|
+
)
|
|
1681
1762
|
if (isError(err, 'CALL_EXCEPTION')) return 0
|
|
1682
1763
|
throw CCIPError.from(err)
|
|
1683
1764
|
})
|
|
@@ -1750,7 +1831,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1750
1831
|
tokenPool: string,
|
|
1751
1832
|
remoteChainSelector?: bigint,
|
|
1752
1833
|
): Promise<Record<string, TokenPoolRemote>> {
|
|
1753
|
-
const [
|
|
1834
|
+
const [type, version] = await this.typeAndVersion(tokenPool)
|
|
1754
1835
|
|
|
1755
1836
|
let supportedChains: Promise<NetworkInfo[]> | undefined
|
|
1756
1837
|
if (remoteChainSelector) supportedChains = Promise.resolve([networkInfo(remoteChainSelector)])
|
|
@@ -1812,6 +1893,14 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1812
1893
|
),
|
|
1813
1894
|
)
|
|
1814
1895
|
} else {
|
|
1896
|
+
if (type === 'USDCTokenPoolProxy') {
|
|
1897
|
+
const proxy = new Contract(
|
|
1898
|
+
tokenPool,
|
|
1899
|
+
interfaces.USDCTokenPoolProxy_v2_0,
|
|
1900
|
+
this.provider,
|
|
1901
|
+
) as unknown as TypedContract<typeof USDCTokenPoolProxy_2_0_ABI>
|
|
1902
|
+
tokenPool = (await proxy.getPools())['cctpV2PoolWithCCV'] as string
|
|
1903
|
+
}
|
|
1815
1904
|
const contract = new Contract(
|
|
1816
1905
|
tokenPool,
|
|
1817
1906
|
interfaces.TokenPool_v2_0,
|
package/src/gas.ts
CHANGED
|
@@ -57,11 +57,12 @@ export type EstimateReceiveExecutionOpts = {
|
|
|
57
57
|
* Estimate CCIP gasLimit needed to execute a request on a contract receiver.
|
|
58
58
|
*
|
|
59
59
|
* @param opts - {@link EstimateReceiveExecutionOpts} for estimation
|
|
60
|
-
* @returns Estimated
|
|
60
|
+
* @returns Estimated execution gas (base transaction cost subtracted)
|
|
61
61
|
*
|
|
62
62
|
* @throws {@link CCIPMethodUnsupportedError} if dest chain doesn't support estimation
|
|
63
63
|
* @throws {@link CCIPContractTypeInvalidError} if routerOrRamp is not a valid contract type
|
|
64
64
|
* @throws {@link CCIPTokenDecimalsInsufficientError} if dest token has insufficient decimals
|
|
65
|
+
* @throws {@link CCIPOnRampRequiredError} if no OnRamp found for the given OffRamp and source chain
|
|
65
66
|
*
|
|
66
67
|
* @example
|
|
67
68
|
* ```typescript
|
package/src/index.ts
CHANGED
package/src/offchain.ts
CHANGED
|
@@ -86,6 +86,7 @@ export const CCTP_FINALITY_STANDARD = 2000
|
|
|
86
86
|
* @param destDomain - CCTP destination domain identifier
|
|
87
87
|
* @param networkType - network type (mainnet or testnet)
|
|
88
88
|
* @returns Array of fee tiers with finality thresholds and BPS fees
|
|
89
|
+
* @throws {@link CCIPUsdcBurnFeesError} if the HTTP request fails or the response is not a valid array of fee tiers
|
|
89
90
|
*/
|
|
90
91
|
export async function getUsdcBurnFees(
|
|
91
92
|
sourceDomain: number,
|
package/src/requests.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type BytesLike, hexlify, isBytesLike, toBigInt } from 'ethers'
|
|
2
2
|
import type { PickDeep } from 'type-fest'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { Chain, ChainStatic } from './chain.ts'
|
|
5
5
|
import {
|
|
6
6
|
CCIPChainFamilyUnsupportedError,
|
|
7
7
|
CCIPMessageBatchIncompleteError,
|
|
@@ -196,9 +196,8 @@ export function decodeMessage(data: string | Uint8Array | Record<string, unknown
|
|
|
196
196
|
* @returns Original message or shallow copy with defaults for required fields
|
|
197
197
|
*/
|
|
198
198
|
export function buildMessageForDest(message: MessageInput, dest: ChainFamily): AnyMessage {
|
|
199
|
-
const chain = supportedChains[dest] ?? Chain
|
|
200
199
|
if (message.extraArgs && '_tag' in message.extraArgs) delete message.extraArgs._tag
|
|
201
|
-
return
|
|
200
|
+
return supportedChains[dest]!.buildMessageForDest(message)
|
|
202
201
|
}
|
|
203
202
|
|
|
204
203
|
/**
|
|
@@ -310,6 +309,7 @@ const BLOCK_LOG_WINDOW_SIZE = 5000
|
|
|
310
309
|
* @param range - Object containing minSeqNr and maxSeqNr for the batch range.
|
|
311
310
|
* @param opts - Optional log filtering parameters.
|
|
312
311
|
* @returns Array of messages in the batch.
|
|
312
|
+
* @throws {@link CCIPMessageBatchIncompleteError} if not all messages in the batch range could be found in source chain logs
|
|
313
313
|
* @see {@link getVerifications} - Get commit report to determine batch range
|
|
314
314
|
*/
|
|
315
315
|
export async function getMessagesInBatch<
|
|
@@ -409,12 +409,12 @@ export async function getMessagesInBatch<
|
|
|
409
409
|
* import { sourceToDestTokenAddresses, EVMChain } from '@chainlink/ccip-sdk'
|
|
410
410
|
*
|
|
411
411
|
* const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
412
|
-
* const tokenAmount = await sourceToDestTokenAddresses(
|
|
412
|
+
* const tokenAmount = await sourceToDestTokenAddresses({
|
|
413
413
|
* source,
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
* { token: '0xLINK...', amount: 1000000000000000000n }
|
|
417
|
-
* )
|
|
414
|
+
* onRamp: '0xOnRamp...',
|
|
415
|
+
* destChainSelector: 14767482510784806043n,
|
|
416
|
+
* sourceTokenAmount: { token: '0xLINK...', amount: 1000000000000000000n },
|
|
417
|
+
* })
|
|
418
418
|
* console.log(`Pool: ${tokenAmount.sourcePoolAddress}`)
|
|
419
419
|
* console.log(`Dest token: ${tokenAmount.destTokenAddress}`)
|
|
420
420
|
* ```
|