@chainlink/ccip-sdk 0.96.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/dist/api/index.d.ts +17 -8
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +27 -10
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +0 -2
- 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 +13 -10
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +42 -68
- 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 +532 -151
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +113 -18
- 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 +3 -0
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +3 -1
- 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 +4 -1
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +1695 -120
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +1715 -123
- 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.map +1 -1
- package/dist/evm/extra-args.js +5 -24
- package/dist/evm/extra-args.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 +73 -14
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +240 -141
- 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 +98 -61
- package/dist/execution.js.map +1 -1
- package/dist/extra-args.d.ts +13 -3
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +13 -3
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts +25 -2
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +30 -4
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/requests.d.ts +85 -14
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +99 -16
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +12 -0
- package/dist/selectors.js.map +1 -1
- package/dist/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 +80 -17
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +67 -30
- 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 +14 -12
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +38 -34
- 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 +9 -16
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +26 -31
- package/dist/ton/index.js.map +1 -1
- 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 +46 -11
- 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 +65 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +74 -2
- package/dist/utils.js.map +1 -1
- package/package.json +9 -9
- package/src/api/index.ts +33 -10
- package/src/api/types.ts +0 -2
- package/src/aptos/exec.ts +2 -2
- package/src/aptos/hasher.ts +1 -1
- package/src/aptos/index.ts +51 -89
- package/src/aptos/types.ts +2 -15
- package/src/chain.ts +581 -163
- package/src/commits.ts +9 -9
- package/src/errors/CCIPError.ts +33 -4
- package/src/errors/codes.ts +3 -1
- package/src/errors/index.ts +1 -0
- package/src/errors/recovery.ts +7 -1
- package/src/errors/specialized.ts +1726 -130
- 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 +4 -21
- package/src/evm/hasher.ts +30 -18
- package/src/evm/index.ts +310 -166
- 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 +125 -86
- package/src/extra-args.ts +13 -3
- package/src/gas.ts +29 -3
- package/src/index.ts +2 -2
- package/src/requests.ts +112 -16
- package/src/selectors.ts +12 -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 +100 -68
- package/src/sui/hasher.ts +1 -1
- package/src/sui/index.ts +50 -47
- 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 +37 -40
- package/src/ton/types.ts +2 -2
- package/src/types.ts +70 -29
- package/src/utils.ts +73 -2
- 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/extra-args.ts
CHANGED
|
@@ -9,7 +9,7 @@ export const EVMExtraArgsV1Tag = id('CCIP EVMExtraArgsV1').substring(0, 10) as '
|
|
|
9
9
|
/** Tag identifier for EVMExtraArgsV2 encoding. */
|
|
10
10
|
export const EVMExtraArgsV2Tag = id('CCIP EVMExtraArgsV2').substring(0, 10) as '0x181dcf10'
|
|
11
11
|
/** Tag identifier for GenericExtraArgsV3 encoding (tightly packed binary format). */
|
|
12
|
-
export const GenericExtraArgsV3Tag = '
|
|
12
|
+
export const GenericExtraArgsV3Tag = id('CCIP GenericExtraArgsV3').substring(0, 10) as '0xa69dd4aa'
|
|
13
13
|
/** Tag identifier for SVMExtraArgsV1 encoding. */
|
|
14
14
|
export const SVMExtraArgsV1Tag = id('CCIP SVMExtraArgsV1').substring(0, 10) as '0x1f3b3aba'
|
|
15
15
|
/** Tag identifier for SuiExtraArgsV1 encoding. */
|
|
@@ -145,6 +145,7 @@ export type ExtraArgs =
|
|
|
145
145
|
* Encodes extra arguments for CCIP messages.
|
|
146
146
|
* The args are *to* a dest network, but are encoded as a message *from* this source chain.
|
|
147
147
|
* E.g. Solana uses Borsh to encode extraArgs in its produced requests, even those targeting EVM.
|
|
148
|
+
*
|
|
148
149
|
* @param args - Extra arguments to encode
|
|
149
150
|
* @param from - Source chain family for encoding format (defaults to EVM)
|
|
150
151
|
* @returns Encoded extra arguments as hex string
|
|
@@ -152,12 +153,16 @@ export type ExtraArgs =
|
|
|
152
153
|
*
|
|
153
154
|
* @example
|
|
154
155
|
* ```typescript
|
|
156
|
+
* import { encodeExtraArgs } from '@chainlink/ccip-sdk'
|
|
157
|
+
*
|
|
155
158
|
* const encoded = encodeExtraArgs({
|
|
156
159
|
* gasLimit: 200_000n,
|
|
157
160
|
* allowOutOfOrderExecution: true,
|
|
158
161
|
* })
|
|
159
|
-
* //
|
|
162
|
+
* console.log('Encoded:', encoded) // '0x181dcf10...'
|
|
160
163
|
* ```
|
|
164
|
+
*
|
|
165
|
+
* @see {@link decodeExtraArgs} - Decode extra arguments from bytes
|
|
161
166
|
*/
|
|
162
167
|
export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily.EVM): string {
|
|
163
168
|
const chain = supportedChains[from]
|
|
@@ -175,11 +180,16 @@ export function encodeExtraArgs(args: ExtraArgs, from: ChainFamily = ChainFamily
|
|
|
175
180
|
*
|
|
176
181
|
* @example
|
|
177
182
|
* ```typescript
|
|
183
|
+
* import { decodeExtraArgs } from '@chainlink/ccip-sdk'
|
|
184
|
+
*
|
|
178
185
|
* const decoded = decodeExtraArgs('0x181dcf10...')
|
|
179
186
|
* if (decoded?._tag === 'EVMExtraArgsV2') {
|
|
180
|
-
* console.log(
|
|
187
|
+
* console.log('Gas limit:', decoded.gasLimit)
|
|
188
|
+
* console.log('Out of order:', decoded.allowOutOfOrderExecution)
|
|
181
189
|
* }
|
|
182
190
|
* ```
|
|
191
|
+
*
|
|
192
|
+
* @see {@link encodeExtraArgs} - Encode extra arguments to bytes
|
|
183
193
|
*/
|
|
184
194
|
export function decodeExtraArgs(
|
|
185
195
|
data: BytesLike,
|
package/src/gas.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Chain } from './chain.ts'
|
|
|
4
4
|
import {
|
|
5
5
|
CCIPContractTypeInvalidError,
|
|
6
6
|
CCIPMethodUnsupportedError,
|
|
7
|
+
CCIPOnRampRequiredError,
|
|
7
8
|
CCIPTokenDecimalsInsufficientError,
|
|
8
9
|
} from './errors/index.ts'
|
|
9
10
|
import { discoverOffRamp } from './execution.ts'
|
|
@@ -50,11 +51,34 @@ export type EstimateReceiveExecutionOpts = {
|
|
|
50
51
|
|
|
51
52
|
/**
|
|
52
53
|
* Estimate CCIP gasLimit needed to execute a request on a contract receiver.
|
|
53
|
-
*
|
|
54
|
-
* @
|
|
54
|
+
*
|
|
55
|
+
* @param opts - {@link EstimateReceiveExecutionOpts} for estimation
|
|
56
|
+
* @returns Estimated gasLimit
|
|
57
|
+
*
|
|
55
58
|
* @throws {@link CCIPMethodUnsupportedError} if dest chain doesn't support estimation
|
|
56
59
|
* @throws {@link CCIPContractTypeInvalidError} if routerOrRamp is not a valid contract type
|
|
57
60
|
* @throws {@link CCIPTokenDecimalsInsufficientError} if dest token has insufficient decimals
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { estimateReceiveExecution, EVMChain } from '@chainlink/ccip-sdk'
|
|
65
|
+
*
|
|
66
|
+
* const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
67
|
+
* const dest = await EVMChain.fromUrl('https://rpc.fuji.avax.network')
|
|
68
|
+
*
|
|
69
|
+
* const gasLimit = await estimateReceiveExecution({
|
|
70
|
+
* source,
|
|
71
|
+
* dest,
|
|
72
|
+
* routerOrRamp: '0xRouter...',
|
|
73
|
+
* message: {
|
|
74
|
+
* sender: '0x...',
|
|
75
|
+
* receiver: '0x...',
|
|
76
|
+
* data: '0x...',
|
|
77
|
+
* tokenAmounts: [],
|
|
78
|
+
* },
|
|
79
|
+
* })
|
|
80
|
+
* console.log('Estimated gas:', gasLimit)
|
|
81
|
+
* ```
|
|
58
82
|
*/
|
|
59
83
|
export async function estimateReceiveExecution({
|
|
60
84
|
source,
|
|
@@ -78,7 +102,9 @@ export async function estimateReceiveExecution({
|
|
|
78
102
|
if (!tnv[0].includes('OffRamp'))
|
|
79
103
|
throw new CCIPContractTypeInvalidError(routerOrRamp, tnv[2], ['OffRamp'])
|
|
80
104
|
offRamp = routerOrRamp
|
|
81
|
-
|
|
105
|
+
const onRamps = await dest.getOnRampsForOffRamp(offRamp, source.network.chainSelector)
|
|
106
|
+
if (!onRamps.length) throw new CCIPOnRampRequiredError()
|
|
107
|
+
onRamp = onRamps[onRamps.length - 1]!
|
|
82
108
|
} catch {
|
|
83
109
|
throw sourceErr // re-throw original error
|
|
84
110
|
}
|
package/src/index.ts
CHANGED
|
@@ -43,14 +43,14 @@ export {
|
|
|
43
43
|
export { estimateReceiveExecution } from './gas.ts'
|
|
44
44
|
export { decodeMessage, getMessagesForSender, sourceToDestTokenAddresses } from './requests.ts'
|
|
45
45
|
export {
|
|
46
|
-
type CCIPCommit,
|
|
47
46
|
type CCIPExecution,
|
|
48
47
|
type CCIPMessage,
|
|
49
48
|
type CCIPRequest,
|
|
49
|
+
type CCIPVerifications,
|
|
50
50
|
type ChainTransaction,
|
|
51
51
|
type CommitReport,
|
|
52
|
+
type ExecutionInput,
|
|
52
53
|
type ExecutionReceipt,
|
|
53
|
-
type ExecutionReport,
|
|
54
54
|
type Lane,
|
|
55
55
|
type Logger,
|
|
56
56
|
type MessageInput,
|
package/src/requests.ts
CHANGED
|
@@ -46,6 +46,14 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
46
46
|
source_chain_selector?: string
|
|
47
47
|
sourceChainSelector?: string
|
|
48
48
|
extraArgs?: string | Record<string, unknown>
|
|
49
|
+
sequenceNumber?: bigint
|
|
50
|
+
messageNumber?: bigint
|
|
51
|
+
tokenTransfer?: {
|
|
52
|
+
destExecData: string
|
|
53
|
+
destGasAmount?: bigint
|
|
54
|
+
token?: string
|
|
55
|
+
sourceTokenAddress?: string
|
|
56
|
+
}[]
|
|
49
57
|
tokenAmounts: {
|
|
50
58
|
destExecData: string
|
|
51
59
|
destGasAmount?: bigint
|
|
@@ -60,6 +68,7 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
60
68
|
totalAmount: bigint
|
|
61
69
|
}
|
|
62
70
|
}
|
|
71
|
+
receipts?: { feeTokenAmount: bigint }[]
|
|
63
72
|
sourceNetworkInfo?: { chainSelector: string }
|
|
64
73
|
destNetworkInfo?: { chainSelector: string }
|
|
65
74
|
}
|
|
@@ -82,7 +91,7 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
82
91
|
? BigInt(v as string | number | bigint)
|
|
83
92
|
: k?.match(/(^dest.*address)|(receiver|offramp|accounts)/i)
|
|
84
93
|
? decodeAddress(v as BytesLike, destFamily)
|
|
85
|
-
: k?.match(/((source.*address)|sender|origin|onramp|(feetoken$)|(token.*address$))/i)
|
|
94
|
+
: k?.match(/((source.*address)|sender|issuer|origin|onramp|(feetoken$)|(token.*address$))/i)
|
|
86
95
|
? decodeAddress(v as BytesLike, sourceFamily)
|
|
87
96
|
: v instanceof Uint8Array ||
|
|
88
97
|
(Array.isArray(v) && v.length >= 4 && v.every((e) => typeof e === 'number'))
|
|
@@ -90,6 +99,10 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
90
99
|
: v,
|
|
91
100
|
) as typeof data_
|
|
92
101
|
|
|
102
|
+
if (data_.tokenTransfer) {
|
|
103
|
+
data_.tokenAmounts = data_.tokenTransfer
|
|
104
|
+
delete data_.tokenTransfer
|
|
105
|
+
}
|
|
93
106
|
for (const ta of data_.tokenAmounts) {
|
|
94
107
|
if (ta.token && !ta.sourceTokenAddress) ta.sourceTokenAddress = ta.token
|
|
95
108
|
if (!ta.token && ta.sourceTokenAddress) ta.token = ta.sourceTokenAddress
|
|
@@ -121,6 +134,15 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
121
134
|
data_.feeToken = data_.fees.fixedFeesDetails.tokenAddress
|
|
122
135
|
data_.feeTokenAmount = data_.fees.fixedFeesDetails.totalAmount
|
|
123
136
|
}
|
|
137
|
+
if (data_.sequenceNumber == null && data_.messageNumber != null) {
|
|
138
|
+
data_.sequenceNumber = data_.messageNumber
|
|
139
|
+
}
|
|
140
|
+
if (!data_.feeTokenAmount && data_.receipts) {
|
|
141
|
+
data_.feeTokenAmount = data_.receipts.reduce(
|
|
142
|
+
(acc, receipt) => acc + receipt.feeTokenAmount,
|
|
143
|
+
BigInt(0),
|
|
144
|
+
)
|
|
145
|
+
}
|
|
124
146
|
|
|
125
147
|
return data_ as unknown as CCIPMessage
|
|
126
148
|
}
|
|
@@ -128,9 +150,24 @@ function decodeJsonMessage(data: Record<string, unknown> | undefined) {
|
|
|
128
150
|
/**
|
|
129
151
|
* Decodes hex strings, bytearrays, JSON strings and raw objects as CCIPMessages.
|
|
130
152
|
* Does minimal validation, but converts objects in the format expected by ccip-tools-ts.
|
|
153
|
+
*
|
|
131
154
|
* @param data - Data to decode (hex string, Uint8Array, JSON string, or object)
|
|
132
155
|
* @returns Decoded CCIPMessage
|
|
133
156
|
* @throws {@link CCIPMessageDecodeError} if data cannot be decoded as a valid message
|
|
157
|
+
* @throws {@link CCIPMessageInvalidError} if message structure is invalid or missing required fields
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* import { decodeMessage } from '@chainlink/ccip-sdk'
|
|
162
|
+
*
|
|
163
|
+
* // Decode from JSON string
|
|
164
|
+
* const message = decodeMessage('{"header":{"sourceChainSelector":"123",...}')
|
|
165
|
+
*
|
|
166
|
+
* // Decode from hex-encoded bytes
|
|
167
|
+
* const message = decodeMessage('0x...')
|
|
168
|
+
*
|
|
169
|
+
* console.log('Message ID:', message.messageId)
|
|
170
|
+
* ```
|
|
134
171
|
*/
|
|
135
172
|
export function decodeMessage(data: string | Uint8Array | Record<string, unknown>): CCIPMessage {
|
|
136
173
|
if (
|
|
@@ -171,6 +208,8 @@ export function buildMessageForDest(message: MessageInput, dest: ChainFamily): A
|
|
|
171
208
|
* @returns CCIP requests (messages) in the transaction (at least one)
|
|
172
209
|
* @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported for legacy messages
|
|
173
210
|
* @throws {@link CCIPMessageNotFoundInTxError} if no CCIP messages found in transaction
|
|
211
|
+
*
|
|
212
|
+
* @see {@link getMessageById} - Search by messageId when tx hash unknown
|
|
174
213
|
*/
|
|
175
214
|
export async function getMessagesInTx(source: Chain, tx: ChainTransaction): Promise<CCIPRequest[]> {
|
|
176
215
|
// RPC fallback
|
|
@@ -194,17 +233,36 @@ export async function getMessagesInTx(source: Chain, tx: ChainTransaction): Prom
|
|
|
194
233
|
}
|
|
195
234
|
requests.push({ lane, message, log, tx })
|
|
196
235
|
}
|
|
197
|
-
if (!requests.length)
|
|
236
|
+
if (!requests.length)
|
|
237
|
+
throw new CCIPMessageNotFoundInTxError(tx.hash, { context: { network: source.network.name } })
|
|
198
238
|
return requests
|
|
199
239
|
}
|
|
200
240
|
|
|
201
241
|
/**
|
|
202
|
-
* Fetch a CCIP message by
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* @
|
|
242
|
+
* Fetch a CCIP message by messageId from RPC logs (slow scan).
|
|
243
|
+
*
|
|
244
|
+
* This is the fallback implementation called by {@link Chain.getMessageById}
|
|
245
|
+
* when the API client is unavailable or fails.
|
|
246
|
+
*
|
|
247
|
+
* @param source - Source chain to scan logs from
|
|
248
|
+
* @param messageId - Message ID to search for
|
|
249
|
+
* @param opts - Optional hints (onRamp address narrows search, page controls batch size)
|
|
250
|
+
* @returns CCIPRequest matching the messageId
|
|
251
|
+
*
|
|
252
|
+
* @throws {@link CCIPMessageIdNotFoundError} if message not found after scanning all logs
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
*
|
|
256
|
+
* ```typescript
|
|
257
|
+
* import { getMessageById, EVMChain } from '@chainlink/ccip-sdk'
|
|
258
|
+
*
|
|
259
|
+
* const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
260
|
+
* const request = await getMessageById(source, '0xabc123...', {
|
|
261
|
+
* onRamp: '0xOnRampAddress...',
|
|
262
|
+
* })
|
|
263
|
+
* console.log(`Found: seqNr=${request.message.sequenceNumber}`)
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
208
266
|
* @internal
|
|
209
267
|
*/
|
|
210
268
|
export async function getMessageById(
|
|
@@ -249,9 +307,10 @@ const BLOCK_LOG_WINDOW_SIZE = 5000
|
|
|
249
307
|
* Fetches all CCIP messages contained in a given commit batch.
|
|
250
308
|
* @param source - The source chain.
|
|
251
309
|
* @param request - The CCIP request containing lane and message info.
|
|
252
|
-
* @param
|
|
310
|
+
* @param range - Object containing minSeqNr and maxSeqNr for the batch range.
|
|
253
311
|
* @param opts - Optional log filtering parameters.
|
|
254
312
|
* @returns Array of messages in the batch.
|
|
313
|
+
* @see {@link getVerifications} - Get commit report to determine batch range
|
|
255
314
|
*/
|
|
256
315
|
export async function getMessagesInBatch<
|
|
257
316
|
C extends Chain,
|
|
@@ -293,6 +352,7 @@ export async function getMessagesInBatch<
|
|
|
293
352
|
const message = (source.constructor as ChainStatic).decodeMessage(log)
|
|
294
353
|
if (
|
|
295
354
|
!message ||
|
|
355
|
+
!('sequenceNumber' in message) ||
|
|
296
356
|
('destChainSelector' in message &&
|
|
297
357
|
message.destChainSelector !== request.lane.destChainSelector)
|
|
298
358
|
)
|
|
@@ -314,6 +374,7 @@ export async function getMessagesInBatch<
|
|
|
314
374
|
const message = (source.constructor as ChainStatic).decodeMessage(log)
|
|
315
375
|
if (
|
|
316
376
|
!message ||
|
|
377
|
+
!('sequenceNumber' in message) ||
|
|
317
378
|
('destChainSelector' in message &&
|
|
318
379
|
message.destChainSelector !== request.lane.destChainSelector)
|
|
319
380
|
)
|
|
@@ -339,6 +400,21 @@ export async function getMessagesInBatch<
|
|
|
339
400
|
* @param filter - Log filter options.
|
|
340
401
|
* @returns Async generator of CCIP requests.
|
|
341
402
|
* @throws {@link CCIPChainFamilyUnsupportedError} if chain family not supported for legacy messages
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* import { getMessagesForSender, EVMChain } from '@chainlink/ccip-sdk'
|
|
407
|
+
*
|
|
408
|
+
* const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
409
|
+
*
|
|
410
|
+
* for await (const request of getMessagesForSender(chain, '0xSenderAddress', {})) {
|
|
411
|
+
* console.log('Message ID:', request.message.messageId)
|
|
412
|
+
* console.log('Destination:', request.lane.destChainSelector)
|
|
413
|
+
* }
|
|
414
|
+
* ```
|
|
415
|
+
*
|
|
416
|
+
* @see {@link getMessagesInTx} - Fetch from specific transaction
|
|
417
|
+
* @see {@link getMessageById} - Search by messageId
|
|
342
418
|
*/
|
|
343
419
|
export async function* getMessagesForSender(
|
|
344
420
|
source: Chain,
|
|
@@ -376,13 +452,33 @@ export async function* getMessagesForSender(
|
|
|
376
452
|
}
|
|
377
453
|
|
|
378
454
|
/**
|
|
379
|
-
* Map source
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* @
|
|
385
|
-
* @
|
|
455
|
+
* Map source token to its pool address and destination token address.
|
|
456
|
+
*
|
|
457
|
+
* Resolves token routing by querying the TokenAdminRegistry and TokenPool
|
|
458
|
+
* to find the corresponding destination chain token.
|
|
459
|
+
*
|
|
460
|
+
* @param source - Source chain instance
|
|
461
|
+
* @param destChainSelector - Destination chain selector
|
|
462
|
+
* @param onRamp - OnRamp contract address
|
|
463
|
+
* @param sourceTokenAmount - Token amount object containing `token` and `amount`
|
|
464
|
+
* @returns Extended token amount with `sourcePoolAddress`, `sourceTokenAddress`, and `destTokenAddress`
|
|
465
|
+
*
|
|
466
|
+
* @throws {@link CCIPTokenNotInRegistryError} if token is not registered in TokenAdminRegistry
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* ```typescript
|
|
470
|
+
* import { sourceToDestTokenAddresses, EVMChain } from '@chainlink/ccip-sdk'
|
|
471
|
+
*
|
|
472
|
+
* const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
473
|
+
* const tokenAmount = await sourceToDestTokenAddresses(
|
|
474
|
+
* source,
|
|
475
|
+
* destChainSelector,
|
|
476
|
+
* '0xOnRamp...',
|
|
477
|
+
* { token: '0xLINK...', amount: 1000000000000000000n }
|
|
478
|
+
* )
|
|
479
|
+
* console.log(`Pool: ${tokenAmount.sourcePoolAddress}`)
|
|
480
|
+
* console.log(`Dest token: ${tokenAmount.destTokenAddress}`)
|
|
481
|
+
* ```
|
|
386
482
|
*/
|
|
387
483
|
export async function sourceToDestTokenAddresses<S extends { token: string }>(
|
|
388
484
|
source: Chain,
|
package/src/selectors.ts
CHANGED
|
@@ -1099,6 +1099,12 @@ const selectors: Selectors = {
|
|
|
1099
1099
|
network_type: 'TESTNET',
|
|
1100
1100
|
family: 'EVM',
|
|
1101
1101
|
},
|
|
1102
|
+
'46630': {
|
|
1103
|
+
selector: 2032988798112970440n,
|
|
1104
|
+
name: 'robinhood-testnet',
|
|
1105
|
+
network_type: 'TESTNET',
|
|
1106
|
+
family: 'EVM',
|
|
1107
|
+
},
|
|
1102
1108
|
'47763': {
|
|
1103
1109
|
selector: 7222032299962346917n,
|
|
1104
1110
|
name: 'neox-mainnet',
|
|
@@ -1349,6 +1355,12 @@ const selectors: Selectors = {
|
|
|
1349
1355
|
network_type: 'MAINNET',
|
|
1350
1356
|
family: 'EVM',
|
|
1351
1357
|
},
|
|
1358
|
+
'202601': {
|
|
1359
|
+
selector: 1091131740251125869n,
|
|
1360
|
+
name: 'ethereum-testnet-sepolia-ronin-1',
|
|
1361
|
+
network_type: 'TESTNET',
|
|
1362
|
+
family: 'EVM',
|
|
1363
|
+
},
|
|
1352
1364
|
'421613': {
|
|
1353
1365
|
selector: 6101244977088475029n,
|
|
1354
1366
|
name: 'ethereum-testnet-goerli-arbitrum-1',
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BCS (Binary Canonical Serialization) codecs for Move-based chains (Aptos, Sui).
|
|
3
|
+
* These chains share similar BCS encoding and 32-byte address formats.
|
|
4
|
+
*/
|
|
5
|
+
import { bcs } from '@mysten/bcs'
|
|
6
|
+
import {
|
|
7
|
+
type BigNumberish,
|
|
8
|
+
type BytesLike,
|
|
9
|
+
concat,
|
|
10
|
+
dataLength,
|
|
11
|
+
dataSlice,
|
|
12
|
+
getBytes,
|
|
13
|
+
hexlify,
|
|
14
|
+
toBeHex,
|
|
15
|
+
zeroPadBytes,
|
|
16
|
+
zeroPadValue,
|
|
17
|
+
} from 'ethers'
|
|
18
|
+
|
|
19
|
+
import { CCIPDataFormatUnsupportedError } from '../errors/index.ts'
|
|
20
|
+
import {
|
|
21
|
+
type EVMExtraArgsV2,
|
|
22
|
+
type SVMExtraArgsV1,
|
|
23
|
+
EVMExtraArgsV2Tag,
|
|
24
|
+
SVMExtraArgsV1Tag,
|
|
25
|
+
} from '../extra-args.ts'
|
|
26
|
+
import { ChainFamily } from '../types.ts'
|
|
27
|
+
import { decodeAddress, getDataBytes } from '../utils.ts'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* BCS codec for decoding EVM extra args on Move chains (Aptos/Sui).
|
|
31
|
+
* Used when receiving cross-chain messages from EVM source chains.
|
|
32
|
+
*/
|
|
33
|
+
export const BcsEVMExtraArgsV2Codec = bcs.struct('EVMExtraArgsV2', {
|
|
34
|
+
gasLimit: bcs.u256(),
|
|
35
|
+
allowOutOfOrderExecution: bcs.bool(),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* BCS codec for decoding SVM (Solana) extra args on Move chains (Aptos/Sui).
|
|
40
|
+
* Used when receiving cross-chain messages from Solana source chains.
|
|
41
|
+
*/
|
|
42
|
+
export const BcsSVMExtraArgsV1Codec = bcs.struct('SVMExtraArgsV1', {
|
|
43
|
+
computeUnits: bcs.u32(),
|
|
44
|
+
accountIsWritableBitmap: bcs.u64(),
|
|
45
|
+
allowOutOfOrderExecution: bcs.bool(),
|
|
46
|
+
tokenReceiver: bcs.vector(bcs.u8()),
|
|
47
|
+
accounts: bcs.vector(bcs.vector(bcs.u8())),
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Decodes extra arguments from Move-based chain CCIP messages.
|
|
52
|
+
* Works for both Aptos and Sui since they share the same BCS encoding.
|
|
53
|
+
* @param extraArgs - Encoded extra arguments bytes.
|
|
54
|
+
* @returns Decoded extra arguments or undefined if unknown format.
|
|
55
|
+
*/
|
|
56
|
+
export function decodeMoveExtraArgs(
|
|
57
|
+
extraArgs: BytesLike,
|
|
58
|
+
):
|
|
59
|
+
| (EVMExtraArgsV2 & { _tag: 'EVMExtraArgsV2' })
|
|
60
|
+
| (SVMExtraArgsV1 & { _tag: 'SVMExtraArgsV1' })
|
|
61
|
+
| undefined {
|
|
62
|
+
const data = getDataBytes(extraArgs),
|
|
63
|
+
tag = dataSlice(data, 0, 4)
|
|
64
|
+
switch (tag) {
|
|
65
|
+
case EVMExtraArgsV2Tag: {
|
|
66
|
+
const parsed = BcsEVMExtraArgsV2Codec.parse(getBytes(dataSlice(data, 4)))
|
|
67
|
+
// Move serialization of EVMExtraArgsV2: 37 bytes total: 4 tag + 32 LE gasLimit + 1 allowOOOE
|
|
68
|
+
return {
|
|
69
|
+
_tag: 'EVMExtraArgsV2',
|
|
70
|
+
...parsed,
|
|
71
|
+
gasLimit: BigInt(parsed.gasLimit),
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
case SVMExtraArgsV1Tag: {
|
|
75
|
+
const parsed = BcsSVMExtraArgsV1Codec.parse(getBytes(dataSlice(data, 4)))
|
|
76
|
+
// Move serialization of SVMExtraArgsV1: 13 bytes total: 4 tag + 8 LE computeUnits
|
|
77
|
+
return {
|
|
78
|
+
_tag: 'SVMExtraArgsV1',
|
|
79
|
+
...parsed,
|
|
80
|
+
computeUnits: BigInt(parsed.computeUnits),
|
|
81
|
+
accountIsWritableBitmap: BigInt(parsed.accountIsWritableBitmap),
|
|
82
|
+
tokenReceiver: decodeAddress(new Uint8Array(parsed.tokenReceiver), ChainFamily.Solana),
|
|
83
|
+
accounts: parsed.accounts.map((account) =>
|
|
84
|
+
decodeAddress(new Uint8Array(account), ChainFamily.Solana),
|
|
85
|
+
),
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Converts bytes to a Move-chain address (32-byte zero-padded).
|
|
93
|
+
* Works for both Aptos and Sui since they share the same address format.
|
|
94
|
+
* @param bytes - Bytes to convert.
|
|
95
|
+
* @returns Address as 0x-prefixed hex string, 32 bytes padded.
|
|
96
|
+
* @throws {@link CCIPDataFormatUnsupportedError} if bytes length exceeds 32
|
|
97
|
+
*/
|
|
98
|
+
export function getMoveAddress(bytes: BytesLike | readonly number[]): string {
|
|
99
|
+
let suffix = ''
|
|
100
|
+
if (Array.isArray(bytes)) bytes = new Uint8Array(bytes)
|
|
101
|
+
if (typeof bytes === 'string' && bytes.startsWith('0x')) {
|
|
102
|
+
const idx = bytes.indexOf('::')
|
|
103
|
+
if (idx > 0) {
|
|
104
|
+
suffix = bytes.slice(idx)
|
|
105
|
+
bytes = bytes.slice(0, idx)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
bytes = getDataBytes(bytes)
|
|
109
|
+
if (bytes.length > 32)
|
|
110
|
+
throw new CCIPDataFormatUnsupportedError(`Move address exceeds 32 bytes: ${hexlify(bytes)}`)
|
|
111
|
+
return zeroPadValue(bytes, 32) + suffix
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Encodes a numeric value as a 32-byte hex string.
|
|
116
|
+
* Used for BCS encoding on Move chains (Aptos/Sui).
|
|
117
|
+
* @param value - Numeric value to encode.
|
|
118
|
+
* @returns 32-byte hex string representation of the value.
|
|
119
|
+
*/
|
|
120
|
+
export const encodeNumber = (value: BigNumberish): string => toBeHex(value, 32)
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Encodes dynamic bytes with length prefix for BCS serialization.
|
|
124
|
+
* Used for BCS encoding on Move chains (Aptos/Sui).
|
|
125
|
+
* @param value - Bytes to encode.
|
|
126
|
+
* @returns Encoded bytes with 32-byte aligned padding.
|
|
127
|
+
*/
|
|
128
|
+
export const encodeRawBytes = (value: BytesLike): string =>
|
|
129
|
+
concat([
|
|
130
|
+
encodeNumber(dataLength(value)),
|
|
131
|
+
zeroPadBytes(value, Math.ceil(dataLength(value) / 32) * 32),
|
|
132
|
+
])
|
package/src/solana/exec.ts
CHANGED
|
@@ -14,7 +14,7 @@ import BN from 'bn.js'
|
|
|
14
14
|
import { hexlify } from 'ethers'
|
|
15
15
|
|
|
16
16
|
import { CCIPSolanaLookupTableNotFoundError } from '../errors/index.ts'
|
|
17
|
-
import { type
|
|
17
|
+
import { type ExecutionInput, type WithLogger, ChainFamily } from '../types.ts'
|
|
18
18
|
import { IDL as CCIP_OFFRAMP_IDL } from './idl/1.6.0/CCIP_OFFRAMP.ts'
|
|
19
19
|
import { encodeSolanaOffchainTokenData } from './offchain.ts'
|
|
20
20
|
import type { CCIPMessage_V1_6_Solana, UnsignedSolanaTx } from './types.ts'
|
|
@@ -43,7 +43,7 @@ export async function generateUnsignedExecuteReport(
|
|
|
43
43
|
ctx: { connection: Connection } & WithLogger,
|
|
44
44
|
payer: PublicKey,
|
|
45
45
|
offramp: PublicKey,
|
|
46
|
-
execReport:
|
|
46
|
+
execReport: ExecutionInput<CCIPMessage_V1_6_Solana>,
|
|
47
47
|
opts?: { forceLookupTable?: boolean; forceBuffer?: boolean; clearLeftoverAccounts?: boolean },
|
|
48
48
|
): Promise<UnsignedSolanaTx> {
|
|
49
49
|
const { connection, logger = console } = ctx
|
|
@@ -274,7 +274,7 @@ async function getManuallyExecuteInputs({
|
|
|
274
274
|
}: {
|
|
275
275
|
payer: PublicKey
|
|
276
276
|
offramp: Program<typeof CCIP_OFFRAMP_IDL>
|
|
277
|
-
execReport:
|
|
277
|
+
execReport: ExecutionInput<CCIPMessage_V1_6_Solana>
|
|
278
278
|
bufferId?: Buffer
|
|
279
279
|
} & WithLogger) {
|
|
280
280
|
const executionReport = prepareExecutionReport(execReport)
|
|
@@ -346,7 +346,7 @@ function prepareExecutionReport({
|
|
|
346
346
|
message,
|
|
347
347
|
offchainTokenData,
|
|
348
348
|
proofs,
|
|
349
|
-
}:
|
|
349
|
+
}: ExecutionInput<CCIPMessage_V1_6_Solana>): IdlTypes<
|
|
350
350
|
typeof CCIP_OFFRAMP_IDL
|
|
351
351
|
>['ExecutionReportSingleChain'] {
|
|
352
352
|
return {
|