@chainlink/ccip-sdk 0.95.0 → 0.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/all-chains.d.ts +23 -0
- package/dist/all-chains.d.ts.map +1 -0
- package/dist/all-chains.js +24 -0
- package/dist/all-chains.js.map +1 -0
- package/dist/api/index.d.ts +31 -19
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +46 -25
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +24 -30
- package/dist/api/types.d.ts.map +1 -1
- package/dist/aptos/exec.d.ts +2 -2
- package/dist/aptos/exec.d.ts.map +1 -1
- package/dist/aptos/exec.js.map +1 -1
- package/dist/aptos/hasher.d.ts.map +1 -1
- package/dist/aptos/hasher.js +1 -1
- package/dist/aptos/hasher.js.map +1 -1
- package/dist/aptos/index.d.ts +43 -15
- package/dist/aptos/index.d.ts.map +1 -1
- package/dist/aptos/index.js +112 -105
- package/dist/aptos/index.js.map +1 -1
- package/dist/aptos/types.d.ts +2 -19
- package/dist/aptos/types.d.ts.map +1 -1
- package/dist/aptos/types.js +0 -11
- package/dist/aptos/types.js.map +1 -1
- package/dist/chain.d.ts +734 -174
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +216 -31
- package/dist/chain.js.map +1 -1
- package/dist/commits.d.ts +4 -6
- package/dist/commits.d.ts.map +1 -1
- package/dist/commits.js +4 -4
- package/dist/commits.js.map +1 -1
- package/dist/errors/CCIPError.d.ts +33 -4
- package/dist/errors/CCIPError.d.ts.map +1 -1
- package/dist/errors/CCIPError.js +33 -4
- package/dist/errors/CCIPError.js.map +1 -1
- package/dist/errors/codes.d.ts +5 -0
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +5 -1
- package/dist/errors/codes.js.map +1 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +2 -2
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/recovery.d.ts.map +1 -1
- package/dist/errors/recovery.js +6 -1
- package/dist/errors/recovery.js.map +1 -1
- package/dist/errors/specialized.d.ts +1702 -121
- package/dist/errors/specialized.d.ts.map +1 -1
- package/dist/errors/specialized.js +1729 -125
- package/dist/errors/specialized.js.map +1 -1
- package/dist/errors/utils.d.ts.map +1 -1
- package/dist/errors/utils.js +0 -1
- package/dist/errors/utils.js.map +1 -1
- package/dist/evm/abi/OffRamp_2_0.d.ts +764 -0
- package/dist/evm/abi/OffRamp_2_0.d.ts.map +1 -0
- package/dist/evm/abi/OffRamp_2_0.js +744 -0
- package/dist/evm/abi/OffRamp_2_0.js.map +1 -0
- package/dist/evm/abi/OnRamp_2_0.d.ts +925 -0
- package/dist/evm/abi/OnRamp_2_0.d.ts.map +1 -0
- package/dist/evm/abi/OnRamp_2_0.js +992 -0
- package/dist/evm/abi/OnRamp_2_0.js.map +1 -0
- package/dist/evm/const.d.ts +12 -2
- package/dist/evm/const.d.ts.map +1 -1
- package/dist/evm/const.js +8 -2
- package/dist/evm/const.js.map +1 -1
- package/dist/evm/errors.d.ts.map +1 -1
- package/dist/evm/errors.js +7 -2
- package/dist/evm/errors.js.map +1 -1
- package/dist/evm/extra-args.d.ts +25 -0
- package/dist/evm/extra-args.d.ts.map +1 -0
- package/dist/evm/extra-args.js +309 -0
- package/dist/evm/extra-args.js.map +1 -0
- package/dist/evm/gas.d.ts.map +1 -1
- package/dist/evm/gas.js +7 -12
- package/dist/evm/gas.js.map +1 -1
- package/dist/evm/hasher.d.ts.map +1 -1
- package/dist/evm/hasher.js +23 -13
- package/dist/evm/hasher.js.map +1 -1
- package/dist/evm/index.d.ts +140 -35
- package/dist/evm/index.d.ts.map +1 -1
- package/dist/evm/index.js +306 -226
- package/dist/evm/index.js.map +1 -1
- package/dist/evm/messages.d.ts +59 -5
- package/dist/evm/messages.d.ts.map +1 -1
- package/dist/evm/messages.js +210 -0
- package/dist/evm/messages.js.map +1 -1
- package/dist/evm/offchain.js.map +1 -1
- package/dist/evm/types.d.ts +7 -2
- package/dist/evm/types.d.ts.map +1 -1
- package/dist/evm/types.js +22 -1
- package/dist/evm/types.js.map +1 -1
- package/dist/execution.d.ts +62 -22
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +102 -51
- package/dist/execution.js.map +1 -1
- package/dist/extra-args.d.ts +113 -4
- package/dist/extra-args.d.ts.map +1 -1
- package/dist/extra-args.js +38 -3
- package/dist/extra-args.js.map +1 -1
- package/dist/gas.d.ts +31 -5
- package/dist/gas.d.ts.map +1 -1
- package/dist/gas.js +43 -9
- package/dist/gas.js.map +1 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/requests.d.ts +101 -22
- package/dist/requests.d.ts.map +1 -1
- package/dist/requests.js +115 -24
- package/dist/requests.js.map +1 -1
- package/dist/selectors.d.ts.map +1 -1
- package/dist/selectors.js +24 -0
- package/dist/selectors.js.map +1 -1
- package/dist/shared/bcs-codecs.d.ts +61 -0
- package/dist/shared/bcs-codecs.d.ts.map +1 -0
- package/dist/shared/bcs-codecs.js +102 -0
- package/dist/shared/bcs-codecs.js.map +1 -0
- package/dist/shared/constants.d.ts +3 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +3 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/solana/exec.d.ts +2 -2
- package/dist/solana/exec.d.ts.map +1 -1
- package/dist/solana/exec.js.map +1 -1
- package/dist/solana/index.d.ts +148 -30
- package/dist/solana/index.d.ts.map +1 -1
- package/dist/solana/index.js +137 -44
- package/dist/solana/index.js.map +1 -1
- package/dist/sui/hasher.d.ts.map +1 -1
- package/dist/sui/hasher.js +1 -1
- package/dist/sui/hasher.js.map +1 -1
- package/dist/sui/index.d.ts +49 -19
- package/dist/sui/index.d.ts.map +1 -1
- package/dist/sui/index.js +76 -43
- package/dist/sui/index.js.map +1 -1
- package/dist/sui/manuallyExec/encoder.d.ts +2 -2
- package/dist/sui/manuallyExec/encoder.d.ts.map +1 -1
- package/dist/sui/manuallyExec/encoder.js.map +1 -1
- package/dist/sui/manuallyExec/index.d.ts +2 -2
- package/dist/sui/manuallyExec/index.d.ts.map +1 -1
- package/dist/ton/exec.d.ts +2 -2
- package/dist/ton/exec.d.ts.map +1 -1
- package/dist/ton/exec.js.map +1 -1
- package/dist/ton/index.d.ts +66 -27
- package/dist/ton/index.d.ts.map +1 -1
- package/dist/ton/index.js +172 -47
- package/dist/ton/index.js.map +1 -1
- package/dist/ton/send.d.ts +52 -0
- package/dist/ton/send.d.ts.map +1 -0
- package/dist/ton/send.js +166 -0
- package/dist/ton/send.js.map +1 -0
- package/dist/ton/types.d.ts +2 -2
- package/dist/ton/types.d.ts.map +1 -1
- package/dist/ton/types.js.map +1 -1
- package/dist/types.d.ts +148 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +79 -4
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +92 -7
- package/dist/utils.js.map +1 -1
- package/package.json +16 -11
- package/src/all-chains.ts +26 -0
- package/src/api/index.ts +58 -34
- package/src/api/types.ts +24 -31
- package/src/aptos/exec.ts +2 -2
- package/src/aptos/hasher.ts +1 -1
- package/src/aptos/index.ts +127 -129
- package/src/aptos/types.ts +2 -15
- package/src/chain.ts +837 -191
- package/src/commits.ts +9 -9
- package/src/errors/CCIPError.ts +33 -4
- package/src/errors/codes.ts +5 -1
- package/src/errors/index.ts +2 -1
- package/src/errors/recovery.ts +9 -1
- package/src/errors/specialized.ts +1745 -132
- package/src/errors/utils.ts +0 -1
- package/src/evm/abi/OffRamp_2_0.ts +743 -0
- package/src/evm/abi/OnRamp_2_0.ts +991 -0
- package/src/evm/const.ts +10 -3
- package/src/evm/errors.ts +6 -2
- package/src/evm/extra-args.ts +360 -0
- package/src/evm/gas.ts +14 -13
- package/src/evm/hasher.ts +30 -18
- package/src/evm/index.ts +376 -281
- package/src/evm/messages.ts +323 -11
- package/src/evm/offchain.ts +2 -2
- package/src/evm/types.ts +20 -2
- package/src/execution.ts +126 -71
- package/src/extra-args.ts +118 -4
- package/src/gas.ts +44 -11
- package/src/index.ts +14 -11
- package/src/requests.ts +128 -24
- package/src/selectors.ts +24 -0
- package/src/shared/bcs-codecs.ts +132 -0
- package/src/shared/constants.ts +2 -0
- package/src/solana/exec.ts +4 -4
- package/src/solana/index.ts +170 -82
- package/src/sui/hasher.ts +1 -1
- package/src/sui/index.ts +88 -56
- package/src/sui/manuallyExec/encoder.ts +2 -2
- package/src/sui/manuallyExec/index.ts +2 -2
- package/src/ton/exec.ts +2 -2
- package/src/ton/index.ts +220 -58
- package/src/ton/send.ts +222 -0
- package/src/ton/types.ts +2 -2
- package/src/types.ts +173 -30
- package/src/utils.ts +91 -7
- package/dist/aptos/utils.d.ts +0 -12
- package/dist/aptos/utils.d.ts.map +0 -1
- package/dist/aptos/utils.js +0 -15
- package/dist/aptos/utils.js.map +0 -1
- package/src/aptos/utils.ts +0 -24
package/src/evm/messages.ts
CHANGED
|
@@ -1,21 +1,310 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
AbiParameterToPrimitiveType,
|
|
3
|
+
AbiParametersToPrimitiveTypes,
|
|
4
|
+
ExtractAbiEvent,
|
|
5
|
+
} from 'abitype'
|
|
6
|
+
import {
|
|
7
|
+
type Addressable,
|
|
8
|
+
type BytesLike,
|
|
9
|
+
type Result,
|
|
10
|
+
dataSlice,
|
|
11
|
+
hexlify,
|
|
12
|
+
toBigInt,
|
|
13
|
+
toNumber,
|
|
14
|
+
} from 'ethers'
|
|
15
|
+
import type { Simplify } from 'type-fest'
|
|
3
16
|
|
|
17
|
+
import { CCIPMessageDecodeError } from '../errors/index.ts'
|
|
4
18
|
import type { EVMExtraArgsV2 } from '../extra-args.ts'
|
|
5
|
-
import type { CCIPVersion, MergeArrayElements } from '../types.ts'
|
|
19
|
+
import type { CCIPVersion, ChainFamily, MergeArrayElements } from '../types.ts'
|
|
20
|
+
import { decodeAddress, getDataBytes, networkInfo } from '../utils.ts'
|
|
6
21
|
import type EVM2EVMOnRamp_1_5_ABI from './abi/OnRamp_1_5.ts'
|
|
7
22
|
import type OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
|
|
23
|
+
import type OnRamp_2_0_ABI from './abi/OnRamp_2_0.ts'
|
|
8
24
|
import { defaultAbiCoder } from './const.ts'
|
|
9
25
|
|
|
10
26
|
/** Utility type that cleans up address types to just `string`. */
|
|
11
27
|
export type CleanAddressable<T> = T extends string | Addressable
|
|
12
28
|
? string
|
|
13
|
-
: T extends
|
|
29
|
+
: T extends { [K: string]: unknown } | [...unknown[]]
|
|
14
30
|
? { [K in keyof T]: CleanAddressable<T[K]> }
|
|
15
|
-
: T extends readonly unknown[]
|
|
16
|
-
? readonly CleanAddressable<T[
|
|
31
|
+
: T extends { readonly [K: string]: unknown } | readonly [...unknown[]]
|
|
32
|
+
? { readonly [K in keyof T]: CleanAddressable<T[K]> }
|
|
17
33
|
: T
|
|
18
34
|
|
|
35
|
+
/** Token transfer in MessageV1 format. */
|
|
36
|
+
export type TokenTransferV1 = {
|
|
37
|
+
amount: bigint
|
|
38
|
+
sourcePoolAddress: string
|
|
39
|
+
sourceTokenAddress: string
|
|
40
|
+
destTokenAddress: string
|
|
41
|
+
tokenReceiver: string
|
|
42
|
+
extraData: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** MessageV1 struct matching the Solidity MessageV1Codec format. */
|
|
46
|
+
export type MessageV1 = {
|
|
47
|
+
sourceChainSelector: bigint
|
|
48
|
+
destChainSelector: bigint
|
|
49
|
+
messageNumber: bigint
|
|
50
|
+
executionGasLimit: number
|
|
51
|
+
ccipReceiveGasLimit: number
|
|
52
|
+
finality: number
|
|
53
|
+
ccvAndExecutorHash: string
|
|
54
|
+
onRampAddress: string
|
|
55
|
+
offRampAddress: string
|
|
56
|
+
sender: string
|
|
57
|
+
receiver: string
|
|
58
|
+
destBlob: string
|
|
59
|
+
tokenTransfer: readonly TokenTransferV1[]
|
|
60
|
+
data: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Decodes a TokenTransferV1 from bytes.
|
|
65
|
+
* @param encoded - The encoded bytes.
|
|
66
|
+
* @param offset - The starting offset.
|
|
67
|
+
* @param sourceFamily - The source chain family for source addresses.
|
|
68
|
+
* @param destFamily - The destination chain family for dest addresses.
|
|
69
|
+
* @returns The decoded token transfer and the new offset.
|
|
70
|
+
*/
|
|
71
|
+
function decodeTokenTransferV1(
|
|
72
|
+
encoded: Uint8Array,
|
|
73
|
+
offset: number,
|
|
74
|
+
sourceFamily: ChainFamily,
|
|
75
|
+
destFamily: ChainFamily,
|
|
76
|
+
): { tokenTransfer: TokenTransferV1; newOffset: number } {
|
|
77
|
+
// version (1 byte)
|
|
78
|
+
if (offset >= encoded.length) throw new CCIPMessageDecodeError('TOKEN_TRANSFER_VERSION')
|
|
79
|
+
const version = encoded[offset++]!
|
|
80
|
+
if (version !== 1) throw new CCIPMessageDecodeError(`Invalid encoding version: ${version}`)
|
|
81
|
+
|
|
82
|
+
// amount (32 bytes)
|
|
83
|
+
if (offset + 32 > encoded.length) throw new CCIPMessageDecodeError('TOKEN_TRANSFER_AMOUNT')
|
|
84
|
+
const amount = toBigInt(dataSlice(encoded, offset, offset + 32))
|
|
85
|
+
offset += 32
|
|
86
|
+
|
|
87
|
+
// sourcePoolAddressLength and sourcePoolAddress
|
|
88
|
+
if (offset >= encoded.length) {
|
|
89
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_POOL_LENGTH')
|
|
90
|
+
}
|
|
91
|
+
const sourcePoolAddressLength = encoded[offset++]!
|
|
92
|
+
if (offset + sourcePoolAddressLength > encoded.length) {
|
|
93
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_POOL_CONTENT')
|
|
94
|
+
}
|
|
95
|
+
const sourcePoolAddress = decodeAddress(
|
|
96
|
+
dataSlice(encoded, offset, offset + sourcePoolAddressLength),
|
|
97
|
+
sourceFamily,
|
|
98
|
+
)
|
|
99
|
+
offset += sourcePoolAddressLength
|
|
100
|
+
|
|
101
|
+
// sourceTokenAddressLength and sourceTokenAddress
|
|
102
|
+
if (offset >= encoded.length) {
|
|
103
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_TOKEN_LENGTH')
|
|
104
|
+
}
|
|
105
|
+
const sourceTokenAddressLength = encoded[offset++]!
|
|
106
|
+
if (offset + sourceTokenAddressLength > encoded.length) {
|
|
107
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_SOURCE_TOKEN_CONTENT')
|
|
108
|
+
}
|
|
109
|
+
const sourceTokenAddress = decodeAddress(
|
|
110
|
+
dataSlice(encoded, offset, offset + sourceTokenAddressLength),
|
|
111
|
+
sourceFamily,
|
|
112
|
+
)
|
|
113
|
+
offset += sourceTokenAddressLength
|
|
114
|
+
|
|
115
|
+
// destTokenAddressLength and destTokenAddress
|
|
116
|
+
if (offset >= encoded.length) {
|
|
117
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_DEST_TOKEN_LENGTH')
|
|
118
|
+
}
|
|
119
|
+
const destTokenAddressLength = encoded[offset++]!
|
|
120
|
+
if (offset + destTokenAddressLength > encoded.length) {
|
|
121
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_DEST_TOKEN_CONTENT')
|
|
122
|
+
}
|
|
123
|
+
const destTokenAddress = decodeAddress(
|
|
124
|
+
dataSlice(encoded, offset, offset + destTokenAddressLength),
|
|
125
|
+
destFamily,
|
|
126
|
+
)
|
|
127
|
+
offset += destTokenAddressLength
|
|
128
|
+
|
|
129
|
+
// tokenReceiverLength and tokenReceiver
|
|
130
|
+
if (offset >= encoded.length) {
|
|
131
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_TOKEN_RECEIVER_LENGTH')
|
|
132
|
+
}
|
|
133
|
+
const tokenReceiverLength = encoded[offset++]!
|
|
134
|
+
if (offset + tokenReceiverLength > encoded.length) {
|
|
135
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_TOKEN_RECEIVER_CONTENT')
|
|
136
|
+
}
|
|
137
|
+
const tokenReceiver = decodeAddress(
|
|
138
|
+
dataSlice(encoded, offset, offset + tokenReceiverLength),
|
|
139
|
+
destFamily,
|
|
140
|
+
)
|
|
141
|
+
offset += tokenReceiverLength
|
|
142
|
+
|
|
143
|
+
// extraDataLength and extraData
|
|
144
|
+
if (offset + 2 > encoded.length) {
|
|
145
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_EXTRA_DATA_LENGTH')
|
|
146
|
+
}
|
|
147
|
+
const extraDataLength = toNumber(dataSlice(encoded, offset, offset + 2))
|
|
148
|
+
offset += 2
|
|
149
|
+
if (offset + extraDataLength > encoded.length) {
|
|
150
|
+
throw new CCIPMessageDecodeError('TOKEN_TRANSFER_EXTRA_DATA_CONTENT')
|
|
151
|
+
}
|
|
152
|
+
const extraData = hexlify(dataSlice(encoded, offset, offset + extraDataLength))
|
|
153
|
+
offset += extraDataLength
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
tokenTransfer: {
|
|
157
|
+
amount,
|
|
158
|
+
sourcePoolAddress,
|
|
159
|
+
sourceTokenAddress,
|
|
160
|
+
destTokenAddress,
|
|
161
|
+
tokenReceiver,
|
|
162
|
+
extraData,
|
|
163
|
+
},
|
|
164
|
+
newOffset: offset,
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Decodes a MessageV1 from bytes following the v1 protocol format.
|
|
170
|
+
* @param encodedMessage - The encoded message bytes to decode.
|
|
171
|
+
* @returns The decoded MessageV1 struct.
|
|
172
|
+
*/
|
|
173
|
+
export function decodeMessageV1(encodedMessage: BytesLike): MessageV1 {
|
|
174
|
+
const MESSAGE_V1_BASE_SIZE = 77
|
|
175
|
+
const encoded = getDataBytes(encodedMessage)
|
|
176
|
+
|
|
177
|
+
if (encoded.length < MESSAGE_V1_BASE_SIZE) throw new CCIPMessageDecodeError('MESSAGE_MIN_SIZE')
|
|
178
|
+
|
|
179
|
+
const version = encoded[0]!
|
|
180
|
+
if (version !== 1) throw new CCIPMessageDecodeError(`Invalid encoding version: ${version}`)
|
|
181
|
+
|
|
182
|
+
// sourceChainSelector (8 bytes, big endian)
|
|
183
|
+
const sourceChainSelector = toBigInt(dataSlice(encoded, 1, 9))
|
|
184
|
+
|
|
185
|
+
// destChainSelector (8 bytes, big endian)
|
|
186
|
+
const destChainSelector = toBigInt(dataSlice(encoded, 9, 17))
|
|
187
|
+
|
|
188
|
+
// Get chain families for address decoding
|
|
189
|
+
const sourceNetworkInfo = networkInfo(sourceChainSelector)
|
|
190
|
+
const destNetworkInfo = networkInfo(destChainSelector)
|
|
191
|
+
const sourceFamily = sourceNetworkInfo.family
|
|
192
|
+
const destFamily = destNetworkInfo.family
|
|
193
|
+
|
|
194
|
+
// messageNumber (8 bytes, big endian)
|
|
195
|
+
const messageNumber = toBigInt(dataSlice(encoded, 17, 25))
|
|
196
|
+
|
|
197
|
+
// executionGasLimit (4 bytes, big endian)
|
|
198
|
+
const executionGasLimit = toNumber(dataSlice(encoded, 25, 29))
|
|
199
|
+
|
|
200
|
+
// ccipReceiveGasLimit (4 bytes, big endian)
|
|
201
|
+
const ccipReceiveGasLimit = toNumber(dataSlice(encoded, 29, 33))
|
|
202
|
+
|
|
203
|
+
// finality (2 bytes, big endian)
|
|
204
|
+
const finality = toNumber(dataSlice(encoded, 33, 35))
|
|
205
|
+
|
|
206
|
+
// ccvAndExecutorHash (32 bytes)
|
|
207
|
+
const ccvAndExecutorHash = hexlify(dataSlice(encoded, 35, 67))
|
|
208
|
+
|
|
209
|
+
// onRampAddressLength and onRampAddress
|
|
210
|
+
let offset = 67
|
|
211
|
+
if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_ONRAMP_ADDRESS_LENGTH')
|
|
212
|
+
const onRampAddressLength = encoded[offset++]!
|
|
213
|
+
if (offset + onRampAddressLength > encoded.length) {
|
|
214
|
+
throw new CCIPMessageDecodeError('MESSAGE_ONRAMP_ADDRESS_CONTENT')
|
|
215
|
+
}
|
|
216
|
+
const onRampAddress = decodeAddress(
|
|
217
|
+
dataSlice(encoded, offset, offset + onRampAddressLength),
|
|
218
|
+
sourceFamily,
|
|
219
|
+
)
|
|
220
|
+
offset += onRampAddressLength
|
|
221
|
+
|
|
222
|
+
// offRampAddressLength and offRampAddress
|
|
223
|
+
if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_OFFRAMP_ADDRESS_LENGTH')
|
|
224
|
+
const offRampAddressLength = encoded[offset++]!
|
|
225
|
+
if (offset + offRampAddressLength > encoded.length) {
|
|
226
|
+
throw new CCIPMessageDecodeError('MESSAGE_OFFRAMP_ADDRESS_CONTENT')
|
|
227
|
+
}
|
|
228
|
+
const offRampAddress = decodeAddress(
|
|
229
|
+
dataSlice(encoded, offset, offset + offRampAddressLength),
|
|
230
|
+
destFamily,
|
|
231
|
+
)
|
|
232
|
+
offset += offRampAddressLength
|
|
233
|
+
|
|
234
|
+
// senderLength and sender
|
|
235
|
+
if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_SENDER_LENGTH')
|
|
236
|
+
const senderLength = encoded[offset++]!
|
|
237
|
+
if (offset + senderLength > encoded.length) {
|
|
238
|
+
throw new CCIPMessageDecodeError('MESSAGE_SENDER_CONTENT')
|
|
239
|
+
}
|
|
240
|
+
const sender = decodeAddress(dataSlice(encoded, offset, offset + senderLength), sourceFamily)
|
|
241
|
+
offset += senderLength
|
|
242
|
+
|
|
243
|
+
// receiverLength and receiver
|
|
244
|
+
if (offset >= encoded.length) throw new CCIPMessageDecodeError('MESSAGE_RECEIVER_LENGTH')
|
|
245
|
+
const receiverLength = encoded[offset++]!
|
|
246
|
+
if (offset + receiverLength > encoded.length) {
|
|
247
|
+
throw new CCIPMessageDecodeError('MESSAGE_RECEIVER_CONTENT')
|
|
248
|
+
}
|
|
249
|
+
const receiver = decodeAddress(dataSlice(encoded, offset, offset + receiverLength), destFamily)
|
|
250
|
+
offset += receiverLength
|
|
251
|
+
|
|
252
|
+
// destBlobLength and destBlob
|
|
253
|
+
if (offset + 2 > encoded.length) throw new CCIPMessageDecodeError('MESSAGE_DEST_BLOB_LENGTH')
|
|
254
|
+
const destBlobLength = toNumber(dataSlice(encoded, offset, offset + 2))
|
|
255
|
+
offset += 2
|
|
256
|
+
if (offset + destBlobLength > encoded.length) {
|
|
257
|
+
throw new CCIPMessageDecodeError('MESSAGE_DEST_BLOB_CONTENT')
|
|
258
|
+
}
|
|
259
|
+
const destBlob = hexlify(dataSlice(encoded, offset, offset + destBlobLength))
|
|
260
|
+
offset += destBlobLength
|
|
261
|
+
|
|
262
|
+
// tokenTransferLength and tokenTransfer
|
|
263
|
+
if (offset + 2 > encoded.length) throw new CCIPMessageDecodeError('MESSAGE_TOKEN_TRANSFER_LENGTH')
|
|
264
|
+
const tokenTransferLength = toNumber(dataSlice(encoded, offset, offset + 2))
|
|
265
|
+
offset += 2
|
|
266
|
+
|
|
267
|
+
// Decode token transfer, which is either 0 or 1
|
|
268
|
+
const tokenTransfer: TokenTransferV1[] = []
|
|
269
|
+
if (tokenTransferLength > 0) {
|
|
270
|
+
const expectedEnd = offset + tokenTransferLength
|
|
271
|
+
const result = decodeTokenTransferV1(encoded, offset, sourceFamily, destFamily)
|
|
272
|
+
tokenTransfer.push(result.tokenTransfer)
|
|
273
|
+
offset = result.newOffset
|
|
274
|
+
if (offset !== expectedEnd) throw new CCIPMessageDecodeError('MESSAGE_TOKEN_TRANSFER_CONTENT')
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// dataLength and data
|
|
278
|
+
if (offset + 2 > encoded.length) throw new CCIPMessageDecodeError('MESSAGE_DATA_LENGTH')
|
|
279
|
+
const dataLength = toNumber(dataSlice(encoded, offset, offset + 2))
|
|
280
|
+
offset += 2
|
|
281
|
+
if (offset + dataLength > encoded.length) {
|
|
282
|
+
throw new CCIPMessageDecodeError('MESSAGE_DATA_CONTENT')
|
|
283
|
+
}
|
|
284
|
+
const data = hexlify(dataSlice(encoded, offset, offset + dataLength))
|
|
285
|
+
offset += dataLength
|
|
286
|
+
|
|
287
|
+
// Ensure we've consumed all bytes
|
|
288
|
+
if (offset !== encoded.length) throw new CCIPMessageDecodeError('MESSAGE_FINAL_OFFSET')
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
sourceChainSelector,
|
|
292
|
+
destChainSelector,
|
|
293
|
+
messageNumber,
|
|
294
|
+
executionGasLimit,
|
|
295
|
+
ccipReceiveGasLimit,
|
|
296
|
+
finality,
|
|
297
|
+
ccvAndExecutorHash,
|
|
298
|
+
onRampAddress,
|
|
299
|
+
offRampAddress,
|
|
300
|
+
sender,
|
|
301
|
+
receiver,
|
|
302
|
+
destBlob,
|
|
303
|
+
tokenTransfer,
|
|
304
|
+
data,
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
19
308
|
// v1.2-v1.5 Message ()
|
|
20
309
|
type EVM2AnyMessageRequested = CleanAddressable<
|
|
21
310
|
AbiParametersToPrimitiveTypes<
|
|
@@ -50,12 +339,35 @@ export type CCIPMessage_V1_2_EVM = EVM2AnyMessageRequested
|
|
|
50
339
|
/** v1.6 EVM specialization with EVMExtraArgsV2 and tokenAmounts.*.destGasAmount. */
|
|
51
340
|
export type CCIPMessage_V1_6_EVM = CCIPMessage_V1_6 & EVMExtraArgsV2
|
|
52
341
|
|
|
342
|
+
type MessageSentV2EventParams = ExtractAbiEvent<typeof OnRamp_2_0_ABI, 'CCIPMessageSent'>['inputs']
|
|
343
|
+
type CCIPMessageSentV2 = {
|
|
344
|
+
[N in MessageSentV2EventParams[number]['name']]: CleanAddressable<
|
|
345
|
+
AbiParameterToPrimitiveType<MessageSentV2EventParams[number] & { readonly name: N }>
|
|
346
|
+
>
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* CCIP v2.0 (fka v1.7) Message
|
|
351
|
+
*/
|
|
352
|
+
export type CCIPMessage_V2_0 = Simplify<
|
|
353
|
+
CCIPMessageSentV2 &
|
|
354
|
+
Omit<MessageV1, 'tokenTransfer'> & {
|
|
355
|
+
tokenAmounts: MessageV1['tokenTransfer']
|
|
356
|
+
sequenceNumber: MessageV1['messageNumber']
|
|
357
|
+
feeTokenAmount: bigint
|
|
358
|
+
}
|
|
359
|
+
>
|
|
360
|
+
|
|
53
361
|
/** Union type for CCIP EVM messages across versions. */
|
|
54
|
-
export type CCIPMessage_EVM<V extends CCIPVersion = CCIPVersion> = V extends typeof CCIPVersion.
|
|
55
|
-
?
|
|
56
|
-
: V extends typeof CCIPVersion.
|
|
57
|
-
?
|
|
58
|
-
:
|
|
362
|
+
export type CCIPMessage_EVM<V extends CCIPVersion = CCIPVersion> = V extends typeof CCIPVersion.V2_0
|
|
363
|
+
? CCIPMessage_V2_0
|
|
364
|
+
: V extends typeof CCIPVersion.V1_6
|
|
365
|
+
? CCIPMessage_V1_6_EVM
|
|
366
|
+
: V extends typeof CCIPVersion.V1_5
|
|
367
|
+
? CCIPMessage_V1_5_EVM
|
|
368
|
+
: V extends typeof CCIPVersion.V1_2
|
|
369
|
+
? CCIPMessage_V1_2_EVM
|
|
370
|
+
: never
|
|
59
371
|
|
|
60
372
|
const SourceTokenData =
|
|
61
373
|
'tuple(bytes sourcePoolAddress, bytes destTokenAddress, bytes extraData, uint64 destGasAmount)'
|
package/src/evm/offchain.ts
CHANGED
|
@@ -63,7 +63,7 @@ export async function fetchEVMOffchainTokenData(
|
|
|
63
63
|
)
|
|
64
64
|
let lbtcTokenData: OffchainTokenData[] = []
|
|
65
65
|
try {
|
|
66
|
-
let tokenAmounts
|
|
66
|
+
let tokenAmounts
|
|
67
67
|
if ('sourceTokenData' in request.message) {
|
|
68
68
|
tokenAmounts = request.message.sourceTokenData.map(parseSourceTokenData)
|
|
69
69
|
} else {
|
|
@@ -179,7 +179,7 @@ async function getUsdcTokenData(
|
|
|
179
179
|
* Try to fetch LBTC attestations for transfers, return undefined in position if can't or not required
|
|
180
180
|
**/
|
|
181
181
|
async function getLbtcTokenData(
|
|
182
|
-
tokenAmounts: readonly SourceTokenData[],
|
|
182
|
+
tokenAmounts: readonly Pick<SourceTokenData, 'extraData'>[],
|
|
183
183
|
allLogsInRequest: readonly Pick<Log, 'topics' | 'address' | 'data'>[],
|
|
184
184
|
networkType: NetworkType,
|
|
185
185
|
{ logger = console }: WithLogger = {},
|
package/src/evm/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TransactionRequest, Result } from 'ethers'
|
|
2
2
|
|
|
3
3
|
import type { ChainFamily } from '../types.ts'
|
|
4
4
|
|
|
@@ -7,5 +7,23 @@ import type { ChainFamily } from '../types.ts'
|
|
|
7
7
|
*/
|
|
8
8
|
export type UnsignedEVMTx = {
|
|
9
9
|
family: typeof ChainFamily.EVM
|
|
10
|
-
transactions: Pick<TransactionRequest, 'from' | 'to' | 'data'>[]
|
|
10
|
+
transactions: Pick<TransactionRequest, 'from' | 'to' | 'data' | 'gasLimit'>[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Convert a Result or Promise to an object
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export function resultToObject<T>(o: T): T {
|
|
18
|
+
if (o instanceof Promise) return o.then(resultToObject) as T
|
|
19
|
+
if (!(o instanceof Result)) return o
|
|
20
|
+
if (o.length === 0) return o.toArray() as T
|
|
21
|
+
try {
|
|
22
|
+
const obj = o.toObject()
|
|
23
|
+
if (!Object.keys(obj).every((k) => /^_+\d*$/.test(k)))
|
|
24
|
+
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, resultToObject(v)])) as T
|
|
25
|
+
} catch (_) {
|
|
26
|
+
// fallthrough
|
|
27
|
+
}
|
|
28
|
+
return o.toArray().map(resultToObject) as T
|
|
11
29
|
}
|
package/src/execution.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
import { memoize } from 'micro-memoize'
|
|
2
2
|
|
|
3
|
-
import type { Chain
|
|
3
|
+
import type { Chain } from './chain.ts'
|
|
4
4
|
import {
|
|
5
5
|
CCIPMerkleRootMismatchError,
|
|
6
6
|
CCIPMessageNotInBatchError,
|
|
7
7
|
CCIPOffRampNotFoundError,
|
|
8
8
|
} from './errors/index.ts'
|
|
9
9
|
import { Tree, getLeafHasher, proofFlagsToBits } from './hasher/index.ts'
|
|
10
|
-
import {
|
|
11
|
-
type CCIPCommit,
|
|
12
|
-
type CCIPExecution,
|
|
13
|
-
type CCIPMessage,
|
|
14
|
-
type CCIPRequest,
|
|
15
|
-
type CCIPVersion,
|
|
16
|
-
type ExecutionReport,
|
|
17
|
-
type Lane,
|
|
18
|
-
type WithLogger,
|
|
19
|
-
ExecutionState,
|
|
20
|
-
} from './types.ts'
|
|
10
|
+
import type { CCIPMessage, CCIPVersion, Lane, WithLogger } from './types.ts'
|
|
21
11
|
|
|
22
12
|
/**
|
|
23
13
|
* Pure/sync function to calculate/generate OffRamp.executeManually report for messageIds
|
|
@@ -28,6 +18,38 @@ import {
|
|
|
28
18
|
* @param merkleRoot - Optional merkleRoot of the CommitReport, for validation
|
|
29
19
|
* @param ctx - Context for logging
|
|
30
20
|
* @returns ManualExec report arguments
|
|
21
|
+
* @throws CCIPMessageNotInBatchError - When the messageId is not found in the provided batch
|
|
22
|
+
* @throws CCIPMerkleRootMismatchError - When calculated merkle root doesn't match the provided one
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* This is a pure/sync function that performs no I/O - all data must be pre-fetched.
|
|
26
|
+
* It builds a merkle tree from the messages, generates a proof for the target messageId,
|
|
27
|
+
* and optionally validates against the provided merkleRoot.
|
|
28
|
+
*
|
|
29
|
+
* The returned proof can be used with `execute` to manually execute a stuck message.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { calculateManualExecProof, EVMChain } from '@chainlink/ccip-sdk'
|
|
34
|
+
*
|
|
35
|
+
* // Fetch the request and all messages in its batch
|
|
36
|
+
* const request = (await source.getMessagesInTx(txHash))[0]
|
|
37
|
+
* const verifications = await dest.getVerifications({ offRamp, request })
|
|
38
|
+
* const messages = await source.getMessagesInBatch(request, commit.report)
|
|
39
|
+
*
|
|
40
|
+
* // Calculate proof for manual execution
|
|
41
|
+
* const proof = calculateManualExecProof(
|
|
42
|
+
* messages,
|
|
43
|
+
* request.lane,
|
|
44
|
+
* request.message.messageId,
|
|
45
|
+
* commit.report.merkleRoot
|
|
46
|
+
* )
|
|
47
|
+
* console.log('Merkle root:', proof.merkleRoot)
|
|
48
|
+
* console.log('Proofs:', proof.proofs)
|
|
49
|
+
* ```
|
|
50
|
+
* @see {@link discoverOffRamp} - Find the OffRamp for manual execution
|
|
51
|
+
* @see {@link execute} - Execute the report on destination chain
|
|
52
|
+
* @see {@link generateUnsignedExecute} - Build unsigned execution tx
|
|
31
53
|
**/
|
|
32
54
|
export function calculateManualExecProof<V extends CCIPVersion = CCIPVersion>(
|
|
33
55
|
messagesInBatch: readonly CCIPMessage<V>[],
|
|
@@ -35,7 +57,7 @@ export function calculateManualExecProof<V extends CCIPVersion = CCIPVersion>(
|
|
|
35
57
|
messageId: string,
|
|
36
58
|
merkleRoot?: string,
|
|
37
59
|
ctx?: WithLogger,
|
|
38
|
-
)
|
|
60
|
+
) {
|
|
39
61
|
const hasher = getLeafHasher(lane, ctx)
|
|
40
62
|
|
|
41
63
|
const msgIdx = messagesInBatch.findIndex((message) => message.messageId === messageId)
|
|
@@ -64,6 +86,30 @@ export function calculateManualExecProof<V extends CCIPVersion = CCIPVersion>(
|
|
|
64
86
|
}
|
|
65
87
|
}
|
|
66
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Discover the OffRamp address for a given OnRamp and destination chain.
|
|
91
|
+
* Results are memoized for performance.
|
|
92
|
+
*
|
|
93
|
+
* @param source - Source chain instance.
|
|
94
|
+
* @param dest - Destination chain instance.
|
|
95
|
+
* @param onRamp - OnRamp contract address on source chain.
|
|
96
|
+
* @param ctx - Optional context with logger.
|
|
97
|
+
* @returns OffRamp address on destination chain.
|
|
98
|
+
* @throws CCIPOffRampNotFoundError - When no matching OffRamp is found for the OnRamp
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* import { discoverOffRamp, EVMChain } from '@chainlink/ccip-sdk'
|
|
102
|
+
*
|
|
103
|
+
* const source = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
104
|
+
* const dest = await EVMChain.fromUrl('https://rpc.fuji.avax.network')
|
|
105
|
+
*
|
|
106
|
+
* const offRamp = await discoverOffRamp(source, dest, onRampAddress)
|
|
107
|
+
* console.log('OffRamp on destination:', offRamp)
|
|
108
|
+
* ```
|
|
109
|
+
* @see {@link calculateManualExecProof} - Use with OffRamp for manual execution
|
|
110
|
+
* @see {@link execute} - Execute on destination chain
|
|
111
|
+
* @see {@link getExecutionReceipts} - Check execution status
|
|
112
|
+
*/
|
|
67
113
|
export const discoverOffRamp = memoize(
|
|
68
114
|
async function discoverOffRamp_(
|
|
69
115
|
source: Chain,
|
|
@@ -77,26 +123,76 @@ export const discoverOffRamp = memoize(
|
|
|
77
123
|
dest.network.chainSelector,
|
|
78
124
|
)
|
|
79
125
|
for (const offRamp of sourceOffRamps) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const offRampsOnRamp = await dest.getOnRampForOffRamp(offRamp, source.network.chainSelector)
|
|
126
|
+
let destOnRamps
|
|
127
|
+
try {
|
|
128
|
+
destOnRamps = await source.getOnRampsForOffRamp(offRamp, dest.network.chainSelector)
|
|
129
|
+
} catch (err) {
|
|
85
130
|
logger.debug(
|
|
86
|
-
'discoverOffRamp:
|
|
87
|
-
{
|
|
88
|
-
sourceOnRamp: onRamp,
|
|
89
|
-
sourceRouter,
|
|
90
|
-
sourceOffRamps,
|
|
91
|
-
destOnRamp,
|
|
92
|
-
destOffRamps,
|
|
93
|
-
offRampsOnRamp,
|
|
94
|
-
},
|
|
95
|
-
'=',
|
|
131
|
+
'discoverOffRamp: skipping offRamp',
|
|
96
132
|
offRamp,
|
|
133
|
+
'(no valid source chain config)',
|
|
134
|
+
err,
|
|
97
135
|
)
|
|
98
|
-
|
|
99
|
-
|
|
136
|
+
continue
|
|
137
|
+
}
|
|
138
|
+
for (const destOnRamp of destOnRamps) {
|
|
139
|
+
const destRouter = await dest.getRouterForOnRamp(destOnRamp, source.network.chainSelector)
|
|
140
|
+
const destOffRamps = await dest.getOffRampsForRouter(
|
|
141
|
+
destRouter,
|
|
142
|
+
source.network.chainSelector,
|
|
143
|
+
)
|
|
144
|
+
for (const offRamp of destOffRamps) {
|
|
145
|
+
let offRampsOnRamps
|
|
146
|
+
try {
|
|
147
|
+
offRampsOnRamps = await dest.getOnRampsForOffRamp(offRamp, source.network.chainSelector)
|
|
148
|
+
} catch (err) {
|
|
149
|
+
logger.debug(
|
|
150
|
+
'discoverOffRamp: skipping dest offRamp',
|
|
151
|
+
offRamp,
|
|
152
|
+
'(no valid source chain config)',
|
|
153
|
+
err,
|
|
154
|
+
)
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
for (const offRampsOnRamp of offRampsOnRamps) {
|
|
158
|
+
logger.debug(
|
|
159
|
+
'discoverOffRamp: found, from',
|
|
160
|
+
{
|
|
161
|
+
sourceOnRamp: onRamp,
|
|
162
|
+
sourceRouter,
|
|
163
|
+
sourceOffRamps,
|
|
164
|
+
destOnRamp,
|
|
165
|
+
destOffRamps,
|
|
166
|
+
offRampsOnRamp,
|
|
167
|
+
},
|
|
168
|
+
'=',
|
|
169
|
+
offRamp,
|
|
170
|
+
)
|
|
171
|
+
for (const offRamp of destOffRamps) {
|
|
172
|
+
const offRampsOnRamps = await dest.getOnRampsForOffRamp(
|
|
173
|
+
offRamp,
|
|
174
|
+
source.network.chainSelector,
|
|
175
|
+
)
|
|
176
|
+
for (const offRampsOnRamp of offRampsOnRamps) {
|
|
177
|
+
logger.debug(
|
|
178
|
+
'discoverOffRamp: found, from',
|
|
179
|
+
{
|
|
180
|
+
sourceOnRamp: onRamp,
|
|
181
|
+
sourceRouter,
|
|
182
|
+
sourceOffRamps,
|
|
183
|
+
destOnRamp,
|
|
184
|
+
destOffRamps,
|
|
185
|
+
offRampsOnRamps,
|
|
186
|
+
},
|
|
187
|
+
'=',
|
|
188
|
+
offRamp,
|
|
189
|
+
)
|
|
190
|
+
if (offRampsOnRamp === onRamp) {
|
|
191
|
+
return offRamp
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
100
196
|
}
|
|
101
197
|
}
|
|
102
198
|
}
|
|
@@ -107,44 +203,3 @@ export const discoverOffRamp = memoize(
|
|
|
107
203
|
[source.network.chainSelector, dest.network.chainSelector, onRamp] as const,
|
|
108
204
|
},
|
|
109
205
|
)
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Generic implementation for fetching ExecutionReceipts for given requests.
|
|
113
|
-
* If more than one request is given, may yield them interleaved.
|
|
114
|
-
* Completes as soon as there's no more work to be done.
|
|
115
|
-
*
|
|
116
|
-
* Two possible behaviors:
|
|
117
|
-
* - if `startBlock|startTime` is given, pages forward from that block up;
|
|
118
|
-
* completes when success (final) receipt is found for all requests (or reach latest block)
|
|
119
|
-
* - otherwise, pages backwards and returns only the most recent receipt per request;
|
|
120
|
-
* completes when receipts for all requests were seen
|
|
121
|
-
*
|
|
122
|
-
* @param dest - Provider to page through.
|
|
123
|
-
* @param offRamp - OffRamp contract address.
|
|
124
|
-
* @param request - CCIP request to search executions for.
|
|
125
|
-
* @param commit - Optional commit info to narrow down search.
|
|
126
|
-
* @param hints - Optional hints (e.g., `page` for getLogs pagination range).
|
|
127
|
-
*/
|
|
128
|
-
export async function* getExecutionReceipts(
|
|
129
|
-
dest: Chain,
|
|
130
|
-
offRamp: string,
|
|
131
|
-
request: CCIPRequest,
|
|
132
|
-
commit?: CCIPCommit,
|
|
133
|
-
hints?: { page?: number },
|
|
134
|
-
): AsyncGenerator<CCIPExecution> {
|
|
135
|
-
const onlyLast = !commit?.log.blockNumber && !request.tx.timestamp // backwards
|
|
136
|
-
for await (const log of dest.getLogs({
|
|
137
|
-
startBlock: commit?.log.blockNumber,
|
|
138
|
-
startTime: request.tx.timestamp,
|
|
139
|
-
address: offRamp,
|
|
140
|
-
topics: ['ExecutionStateChanged'],
|
|
141
|
-
...hints,
|
|
142
|
-
})) {
|
|
143
|
-
const receipt = (dest.constructor as ChainStatic).decodeReceipt(log)
|
|
144
|
-
if (!receipt || receipt.messageId !== request.message.messageId) continue
|
|
145
|
-
|
|
146
|
-
const timestamp = log.tx?.timestamp ?? (await dest.getBlockTimestamp(log.blockNumber))
|
|
147
|
-
yield { receipt, log, timestamp }
|
|
148
|
-
if (onlyLast || receipt.state === ExecutionState.Success) break
|
|
149
|
-
}
|
|
150
|
-
}
|