@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/evm/index.ts
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import { parseAbi } from 'abitype'
|
|
2
1
|
import {
|
|
3
2
|
type BytesLike,
|
|
4
3
|
type Interface,
|
|
5
4
|
type JsonRpcApiProvider,
|
|
6
5
|
type Log,
|
|
6
|
+
type Result,
|
|
7
7
|
type Signer,
|
|
8
8
|
type TransactionReceipt,
|
|
9
9
|
type TransactionRequest,
|
|
10
10
|
type TransactionResponse,
|
|
11
11
|
Contract,
|
|
12
12
|
JsonRpcProvider,
|
|
13
|
-
Result,
|
|
14
13
|
WebSocketProvider,
|
|
15
14
|
ZeroAddress,
|
|
16
15
|
getAddress,
|
|
17
16
|
hexlify,
|
|
18
17
|
isBytesLike,
|
|
19
18
|
isHexString,
|
|
19
|
+
keccak256,
|
|
20
20
|
toBeHex,
|
|
21
|
-
toBigInt,
|
|
22
21
|
zeroPadValue,
|
|
23
22
|
} from 'ethers'
|
|
24
23
|
import type { TypedContract } from 'ethers-abitype'
|
|
@@ -34,16 +33,16 @@ import {
|
|
|
34
33
|
} from '../chain.ts'
|
|
35
34
|
import {
|
|
36
35
|
CCIPAddressInvalidEvmError,
|
|
36
|
+
CCIPApiClientNotAvailableError,
|
|
37
37
|
CCIPBlockNotFoundError,
|
|
38
38
|
CCIPContractNotRouterError,
|
|
39
39
|
CCIPContractTypeInvalidError,
|
|
40
40
|
CCIPDataFormatUnsupportedError,
|
|
41
41
|
CCIPExecTxNotConfirmedError,
|
|
42
42
|
CCIPExecTxRevertedError,
|
|
43
|
-
CCIPExtraArgsParseError,
|
|
44
43
|
CCIPHasherVersionUnsupportedError,
|
|
45
44
|
CCIPLogDataInvalidError,
|
|
46
|
-
|
|
45
|
+
CCIPNotImplementedError,
|
|
47
46
|
CCIPSourceChainUnsupportedError,
|
|
48
47
|
CCIPTokenNotConfiguredError,
|
|
49
48
|
CCIPTokenPoolChainConfigNotFoundError,
|
|
@@ -60,8 +59,10 @@ import {
|
|
|
60
59
|
type CCIPExecution,
|
|
61
60
|
type CCIPMessage,
|
|
62
61
|
type CCIPRequest,
|
|
62
|
+
type CCIPVerifications,
|
|
63
63
|
type ChainTransaction,
|
|
64
64
|
type CommitReport,
|
|
65
|
+
type ExecutionInput,
|
|
65
66
|
type ExecutionReceipt,
|
|
66
67
|
type ExecutionState,
|
|
67
68
|
type Lane,
|
|
@@ -88,12 +89,21 @@ import type TokenPool_ABI from './abi/LockReleaseTokenPool_1_6_1.ts'
|
|
|
88
89
|
import EVM2EVMOffRamp_1_2_ABI from './abi/OffRamp_1_2.ts'
|
|
89
90
|
import EVM2EVMOffRamp_1_5_ABI from './abi/OffRamp_1_5.ts'
|
|
90
91
|
import OffRamp_1_6_ABI from './abi/OffRamp_1_6.ts'
|
|
92
|
+
import OffRamp_2_0_ABI from './abi/OffRamp_2_0.ts'
|
|
91
93
|
import EVM2EVMOnRamp_1_2_ABI from './abi/OnRamp_1_2.ts'
|
|
92
94
|
import EVM2EVMOnRamp_1_5_ABI from './abi/OnRamp_1_5.ts'
|
|
93
|
-
import OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
|
|
95
|
+
import type OnRamp_1_6_ABI from './abi/OnRamp_1_6.ts'
|
|
96
|
+
import type OnRamp_2_0_ABI from './abi/OnRamp_2_0.ts'
|
|
94
97
|
import type Router_ABI from './abi/Router.ts'
|
|
95
98
|
import type TokenAdminRegistry_1_5_ABI from './abi/TokenAdminRegistry_1_5.ts'
|
|
96
|
-
import {
|
|
99
|
+
import {
|
|
100
|
+
CCV_INDEXER_URL,
|
|
101
|
+
VersionedContractABI,
|
|
102
|
+
commitsFragments,
|
|
103
|
+
interfaces,
|
|
104
|
+
receiptsFragments,
|
|
105
|
+
requestsFragments,
|
|
106
|
+
} from './const.ts'
|
|
97
107
|
import { parseData } from './errors.ts'
|
|
98
108
|
import {
|
|
99
109
|
decodeExtraArgs as decodeExtraArgs_,
|
|
@@ -104,30 +114,19 @@ import { getV12LeafHasher, getV16LeafHasher } from './hasher.ts'
|
|
|
104
114
|
import { getEvmLogs } from './logs.ts'
|
|
105
115
|
import {
|
|
106
116
|
type CCIPMessage_V1_6_EVM,
|
|
117
|
+
type CCIPMessage_V2_0,
|
|
107
118
|
type CleanAddressable,
|
|
108
|
-
|
|
119
|
+
type MessageV1,
|
|
120
|
+
type TokenTransferV1,
|
|
121
|
+
decodeMessageV1,
|
|
109
122
|
} from './messages.ts'
|
|
123
|
+
export { decodeMessageV1 }
|
|
124
|
+
export type { MessageV1, TokenTransferV1 }
|
|
110
125
|
import { encodeEVMOffchainTokenData, fetchEVMOffchainTokenData } from './offchain.ts'
|
|
111
|
-
import { buildMessageForDest, getMessagesInBatch } from '../requests.ts'
|
|
112
|
-
import type
|
|
126
|
+
import { buildMessageForDest, decodeMessage, getMessagesInBatch } from '../requests.ts'
|
|
127
|
+
import { type UnsignedEVMTx, resultToObject } from './types.ts'
|
|
113
128
|
export type { UnsignedEVMTx }
|
|
114
129
|
|
|
115
|
-
const VersionedContractABI = parseAbi(['function typeAndVersion() view returns (string)'])
|
|
116
|
-
|
|
117
|
-
function resultToObject<T>(o: T): T {
|
|
118
|
-
if (o instanceof Promise) return o.then(resultToObject) as T
|
|
119
|
-
if (!(o instanceof Result)) return o
|
|
120
|
-
if (o.length === 0) return o.toArray() as T
|
|
121
|
-
try {
|
|
122
|
-
const obj = o.toObject()
|
|
123
|
-
if (!Object.keys(obj).every((k) => /^_+\d*$/.test(k)))
|
|
124
|
-
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, resultToObject(v)])) as T
|
|
125
|
-
} catch (_) {
|
|
126
|
-
// fallthrough
|
|
127
|
-
}
|
|
128
|
-
return o.toArray().map(resultToObject) as T
|
|
129
|
-
}
|
|
130
|
-
|
|
131
130
|
/** typeguard for ethers Signer interface (used for `wallet`s) */
|
|
132
131
|
function isSigner(wallet: unknown): wallet is Signer {
|
|
133
132
|
return (
|
|
@@ -158,6 +157,26 @@ async function submitTransaction(
|
|
|
158
157
|
|
|
159
158
|
/**
|
|
160
159
|
* EVM chain implementation supporting Ethereum-compatible networks.
|
|
160
|
+
*
|
|
161
|
+
* Provides methods for sending CCIP cross-chain messages, querying message
|
|
162
|
+
* status, fetching fee quotes, and manually executing pending messages on
|
|
163
|
+
* Ethereum Virtual Machine compatible chains.
|
|
164
|
+
*
|
|
165
|
+
* @example Create from RPC URL
|
|
166
|
+
* ```typescript
|
|
167
|
+
* import { EVMChain } from '@chainlink/ccip-sdk'
|
|
168
|
+
*
|
|
169
|
+
* const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
170
|
+
* console.log(`Connected to: ${chain.network.name}`)
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @example Query messages in a transaction
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const requests = await chain.getMessagesInTx('0xabc123...')
|
|
176
|
+
* for (const req of requests) {
|
|
177
|
+
* console.log(`Message ID: ${req.message.messageId}`)
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
161
180
|
*/
|
|
162
181
|
export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
163
182
|
static {
|
|
@@ -168,6 +187,13 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
168
187
|
|
|
169
188
|
provider: JsonRpcApiProvider
|
|
170
189
|
readonly destroy$: Promise<void>
|
|
190
|
+
private noncesPromises: Record<string, Promise<unknown>>
|
|
191
|
+
/**
|
|
192
|
+
* Cache of current nonces per wallet address.
|
|
193
|
+
* Used internally by {@link sendMessage} and {@link execute} to manage transaction ordering.
|
|
194
|
+
* Can be inspected for debugging or manually adjusted if needed.
|
|
195
|
+
*/
|
|
196
|
+
nonces: Record<string, number>
|
|
171
197
|
|
|
172
198
|
/**
|
|
173
199
|
* Creates a new EVMChain instance.
|
|
@@ -177,6 +203,9 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
177
203
|
constructor(provider: JsonRpcApiProvider, network: NetworkInfo, ctx?: ChainContext) {
|
|
178
204
|
super(network, ctx)
|
|
179
205
|
|
|
206
|
+
this.noncesPromises = {}
|
|
207
|
+
this.nonces = {}
|
|
208
|
+
|
|
180
209
|
this.provider = provider
|
|
181
210
|
this.destroy$ = new Promise<void>((resolve) => (this.destroy = resolve))
|
|
182
211
|
void this.destroy$.finally(() => provider.destroy())
|
|
@@ -216,6 +245,22 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
216
245
|
return (await this.provider.listAccounts()).map(({ address }) => address)
|
|
217
246
|
}
|
|
218
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Get the next nonce for a wallet address and increment the internal counter.
|
|
250
|
+
* Fetches from the network on first call, then uses cached value.
|
|
251
|
+
* @param address - Wallet address to get nonce for
|
|
252
|
+
* @returns The next available nonce
|
|
253
|
+
*/
|
|
254
|
+
async nextNonce(address: string): Promise<number> {
|
|
255
|
+
await (this.noncesPromises[address] ??= this.provider
|
|
256
|
+
.getTransactionCount(address)
|
|
257
|
+
.then((nonce) => {
|
|
258
|
+
this.nonces[address] = nonce
|
|
259
|
+
return nonce
|
|
260
|
+
}))
|
|
261
|
+
return this.nonces[address]!++
|
|
262
|
+
}
|
|
263
|
+
|
|
219
264
|
/**
|
|
220
265
|
* Creates a JSON-RPC provider from a URL.
|
|
221
266
|
* @param url - WebSocket (wss://) or HTTP (https://) endpoint URL.
|
|
@@ -260,9 +305,20 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
260
305
|
|
|
261
306
|
/**
|
|
262
307
|
* Creates an EVMChain instance from an RPC URL.
|
|
308
|
+
*
|
|
263
309
|
* @param url - WebSocket (wss://) or HTTP (https://) endpoint URL.
|
|
264
|
-
* @param ctx - context containing logger.
|
|
265
|
-
* @returns A new EVMChain instance.
|
|
310
|
+
* @param ctx - Optional context containing logger and API client configuration.
|
|
311
|
+
* @returns A new EVMChain instance connected to the specified network.
|
|
312
|
+
* @throws {@link CCIPChainNotFoundError} if chain cannot be identified from chainId
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```typescript
|
|
316
|
+
* // HTTP connection
|
|
317
|
+
* const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
|
|
318
|
+
*
|
|
319
|
+
* // With custom logger
|
|
320
|
+
* const chain = await EVMChain.fromUrl(url, { logger: customLogger })
|
|
321
|
+
* ```
|
|
266
322
|
*/
|
|
267
323
|
static async fromUrl(url: string, ctx?: ChainContext): Promise<EVMChain> {
|
|
268
324
|
return this.fromProvider(await this._getProvider(url), ctx)
|
|
@@ -298,15 +354,15 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
298
354
|
}
|
|
299
355
|
|
|
300
356
|
/** {@inheritDoc Chain.getMessagesInBatch} */
|
|
301
|
-
getMessagesInBatch<
|
|
357
|
+
override getMessagesInBatch<
|
|
302
358
|
R extends PickDeep<
|
|
303
359
|
CCIPRequest,
|
|
304
360
|
'lane' | `log.${'topics' | 'address' | 'blockNumber'}` | 'message.sequenceNumber'
|
|
305
361
|
>,
|
|
306
362
|
>(
|
|
307
363
|
request: R,
|
|
308
|
-
|
|
309
|
-
opts?:
|
|
364
|
+
range: Pick<CommitReport, 'minSeqNr' | 'maxSeqNr'>,
|
|
365
|
+
opts?: Pick<LogFilter, 'page'>,
|
|
310
366
|
): Promise<R['message'][]> {
|
|
311
367
|
let opts_: Parameters<EVMChain['getLogs']>[0] | undefined
|
|
312
368
|
if (request.lane.version >= CCIPVersion.V1_6) {
|
|
@@ -316,7 +372,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
316
372
|
topics: [[request.log.topics[0]!], [toBeHex(request.lane.destChainSelector, 32)]],
|
|
317
373
|
}
|
|
318
374
|
}
|
|
319
|
-
return getMessagesInBatch(this, request,
|
|
375
|
+
return getMessagesInBatch(this, request, range, opts_)
|
|
320
376
|
}
|
|
321
377
|
|
|
322
378
|
/** {@inheritDoc Chain.typeAndVersion} */
|
|
@@ -326,7 +382,9 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
326
382
|
VersionedContractABI,
|
|
327
383
|
this.provider,
|
|
328
384
|
) as unknown as TypedContract<typeof VersionedContractABI>
|
|
329
|
-
|
|
385
|
+
const res = parseTypeAndVersion(await contract.typeAndVersion())
|
|
386
|
+
if (res[1].startsWith('1.7.')) res[1] = CCIPVersion.V2_0
|
|
387
|
+
return res
|
|
330
388
|
}
|
|
331
389
|
|
|
332
390
|
/**
|
|
@@ -356,79 +414,16 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
356
414
|
const result = interfaces.OnRamp_v1_6.decodeEventLog(fragment, log.data, log.topics)
|
|
357
415
|
message = resultToObject(result) as Record<string, unknown>
|
|
358
416
|
if (message.message) message = message.message as Record<string, unknown> | undefined
|
|
417
|
+
else if (message.encodedMessage) {
|
|
418
|
+
Object.assign(message, decodeMessageV1(message.encodedMessage as BytesLike))
|
|
419
|
+
}
|
|
359
420
|
if (message) break
|
|
360
421
|
} catch (_) {
|
|
361
422
|
// try next fragment
|
|
362
423
|
}
|
|
363
424
|
}
|
|
364
425
|
if (!message) return
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (message.header) {
|
|
368
|
-
// CCIPMessage_V1_6
|
|
369
|
-
Object.assign(message, message.header)
|
|
370
|
-
delete message.header
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const sourceFamily = networkInfo(
|
|
374
|
-
(message as { sourceChainSelector: bigint }).sourceChainSelector,
|
|
375
|
-
).family
|
|
376
|
-
let destFamily: ChainFamily = ChainFamily.EVM
|
|
377
|
-
if ((message as { destChainSelector?: bigint }).destChainSelector) {
|
|
378
|
-
destFamily = networkInfo((message as { destChainSelector: bigint }).destChainSelector).family
|
|
379
|
-
}
|
|
380
|
-
// conversions to make any message version be compatible with latest v1.6
|
|
381
|
-
message.tokenAmounts = (message.tokenAmounts as Record<string, string | bigint | number>[]).map(
|
|
382
|
-
(tokenAmount, i) => {
|
|
383
|
-
if ('sourceTokenData' in message) {
|
|
384
|
-
// CCIPMessage_V1_2_EVM
|
|
385
|
-
try {
|
|
386
|
-
tokenAmount = {
|
|
387
|
-
...parseSourceTokenData(
|
|
388
|
-
(message as { sourceTokenData: string[] }).sourceTokenData[i]!,
|
|
389
|
-
),
|
|
390
|
-
...tokenAmount,
|
|
391
|
-
}
|
|
392
|
-
} catch (_) {
|
|
393
|
-
// legacy sourceTokenData
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (typeof tokenAmount.destExecData === 'string' && tokenAmount.destGasAmount == null) {
|
|
397
|
-
// CCIPMessage_V1_6_EVM
|
|
398
|
-
tokenAmount.destGasAmount = toBigInt(getDataBytes(tokenAmount.destExecData))
|
|
399
|
-
}
|
|
400
|
-
// Can be undefined if the message is from before v1.5 and failed to parse sourceTokenData
|
|
401
|
-
if (tokenAmount.sourcePoolAddress) {
|
|
402
|
-
tokenAmount.sourcePoolAddress = decodeAddress(
|
|
403
|
-
tokenAmount.sourcePoolAddress as string,
|
|
404
|
-
sourceFamily,
|
|
405
|
-
)
|
|
406
|
-
}
|
|
407
|
-
if (tokenAmount.destTokenAddress) {
|
|
408
|
-
tokenAmount.destTokenAddress = decodeAddress(
|
|
409
|
-
tokenAmount.destTokenAddress as string,
|
|
410
|
-
destFamily,
|
|
411
|
-
)
|
|
412
|
-
}
|
|
413
|
-
return tokenAmount
|
|
414
|
-
},
|
|
415
|
-
)
|
|
416
|
-
message.sender = decodeAddress(message.sender, sourceFamily)
|
|
417
|
-
message.feeToken = decodeAddress(message.feeToken as string, sourceFamily)
|
|
418
|
-
message.receiver = decodeAddress(message.receiver as string, destFamily)
|
|
419
|
-
if (message.extraArgs) {
|
|
420
|
-
// v1.6+
|
|
421
|
-
const parsed = this.decodeExtraArgs(message.extraArgs as string)
|
|
422
|
-
if (!parsed) throw new CCIPExtraArgsParseError(message.extraArgs as string)
|
|
423
|
-
const { _tag, ...rest } = parsed
|
|
424
|
-
// merge parsed extraArgs to any family in message root object
|
|
425
|
-
Object.assign(message, rest)
|
|
426
|
-
} else if (message.nonce === 0n) {
|
|
427
|
-
// v1.2..v1.5 targets EVM only; extraArgs is not explicit, gasLimit is already in
|
|
428
|
-
// message body, allowOutOfOrderExecution (in v1.5) was present only as nonce=0
|
|
429
|
-
message.allowOutOfOrderExecution = true
|
|
430
|
-
}
|
|
431
|
-
return message as CCIPMessage
|
|
426
|
+
return decodeMessage(message)
|
|
432
427
|
}
|
|
433
428
|
|
|
434
429
|
/**
|
|
@@ -609,13 +604,23 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
609
604
|
return router as string
|
|
610
605
|
}
|
|
611
606
|
case CCIPVersion.V1_6: {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
607
|
+
const contract = new Contract(
|
|
608
|
+
onRamp,
|
|
609
|
+
interfaces.OnRamp_v1_6,
|
|
610
|
+
this.provider,
|
|
611
|
+
) as unknown as TypedContract<typeof OnRamp_1_6_ABI>
|
|
616
612
|
const [, , router] = await contract.getDestChainConfig(destChainSelector)
|
|
617
613
|
return router as string
|
|
618
614
|
}
|
|
615
|
+
case CCIPVersion.V2_0: {
|
|
616
|
+
const contract = new Contract(
|
|
617
|
+
onRamp,
|
|
618
|
+
interfaces.OnRamp_v2_0,
|
|
619
|
+
this.provider,
|
|
620
|
+
) as unknown as TypedContract<typeof OnRamp_2_0_ABI>
|
|
621
|
+
const { router } = await contract.getDestChainConfig(destChainSelector)
|
|
622
|
+
return router as string
|
|
623
|
+
}
|
|
619
624
|
default:
|
|
620
625
|
throw new CCIPVersionUnsupportedError(version)
|
|
621
626
|
}
|
|
@@ -642,8 +647,11 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
642
647
|
;({ router } = await contract.getDynamicConfig())
|
|
643
648
|
break
|
|
644
649
|
}
|
|
645
|
-
case CCIPVersion.V1_6:
|
|
650
|
+
case CCIPVersion.V1_6:
|
|
646
651
|
offRampABI = OffRamp_1_6_ABI
|
|
652
|
+
// falls through
|
|
653
|
+
case CCIPVersion.V2_0: {
|
|
654
|
+
offRampABI = OffRamp_2_0_ABI
|
|
647
655
|
const contract = new Contract(
|
|
648
656
|
offRamp,
|
|
649
657
|
offRampABI,
|
|
@@ -692,10 +700,10 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
692
700
|
}
|
|
693
701
|
|
|
694
702
|
/**
|
|
695
|
-
* {@inheritDoc Chain.
|
|
703
|
+
* {@inheritDoc Chain.getOnRampsForOffRamp}
|
|
696
704
|
* @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
|
|
697
705
|
*/
|
|
698
|
-
async
|
|
706
|
+
async getOnRampsForOffRamp(offRamp: string, sourceChainSelector: bigint): Promise<string[]> {
|
|
699
707
|
const [, version] = await this.typeAndVersion(offRamp)
|
|
700
708
|
let offRampABI
|
|
701
709
|
switch (version) {
|
|
@@ -710,7 +718,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
710
718
|
this.provider,
|
|
711
719
|
) as unknown as TypedContract<typeof offRampABI>
|
|
712
720
|
const { onRamp } = await contract.getStaticConfig()
|
|
713
|
-
return onRamp as string
|
|
721
|
+
return [onRamp as string]
|
|
714
722
|
}
|
|
715
723
|
case CCIPVersion.V1_6: {
|
|
716
724
|
offRampABI = OffRamp_1_6_ABI
|
|
@@ -720,7 +728,19 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
720
728
|
this.provider,
|
|
721
729
|
) as unknown as TypedContract<typeof offRampABI>
|
|
722
730
|
const { onRamp } = await contract.getSourceChainConfig(sourceChainSelector)
|
|
723
|
-
|
|
731
|
+
if (!onRamp || onRamp.match(/^(0x)?0*$/i)) return []
|
|
732
|
+
return [decodeOnRampAddress(onRamp, networkInfo(sourceChainSelector).family)]
|
|
733
|
+
}
|
|
734
|
+
case CCIPVersion.V2_0: {
|
|
735
|
+
offRampABI = OffRamp_2_0_ABI
|
|
736
|
+
const contract = new Contract(
|
|
737
|
+
offRamp,
|
|
738
|
+
offRampABI,
|
|
739
|
+
this.provider,
|
|
740
|
+
) as unknown as TypedContract<typeof offRampABI>
|
|
741
|
+
const { onRamps } = await contract.getSourceChainConfig(sourceChainSelector)
|
|
742
|
+
const sourceFamily = networkInfo(sourceChainSelector).family
|
|
743
|
+
return onRamps.map((onRamp) => decodeOnRampAddress(onRamp, sourceFamily))
|
|
724
744
|
}
|
|
725
745
|
default:
|
|
726
746
|
throw new CCIPVersionUnsupportedError(version)
|
|
@@ -728,8 +748,19 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
728
748
|
}
|
|
729
749
|
|
|
730
750
|
/**
|
|
731
|
-
*
|
|
751
|
+
* Fetch the CommitStore set in OffRamp config (CCIP v1.5 and earlier).
|
|
752
|
+
* For CCIP v1.6 and later, it should return the offRamp address.
|
|
753
|
+
*
|
|
754
|
+
* @param offRamp - OffRamp contract address
|
|
755
|
+
* @returns Promise resolving to CommitStore address
|
|
756
|
+
*
|
|
757
|
+
* @example Get commit store
|
|
758
|
+
* ```typescript
|
|
759
|
+
* const commitStore = await dest.getCommitStoreForOffRamp(offRampAddress)
|
|
760
|
+
* // For v1.6+, commitStore === offRampAddress
|
|
761
|
+
* ```
|
|
732
762
|
* @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
|
|
763
|
+
* @internal
|
|
733
764
|
*/
|
|
734
765
|
async getCommitStoreForOffRamp(offRamp: string): Promise<string> {
|
|
735
766
|
const [, version] = await this.typeAndVersion(offRamp)
|
|
@@ -748,11 +779,8 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
748
779
|
const { commitStore } = await contract.getStaticConfig()
|
|
749
780
|
return commitStore as string
|
|
750
781
|
}
|
|
751
|
-
case CCIPVersion.V1_6: {
|
|
752
|
-
return offRamp
|
|
753
|
-
}
|
|
754
782
|
default:
|
|
755
|
-
|
|
783
|
+
return offRamp
|
|
756
784
|
}
|
|
757
785
|
}
|
|
758
786
|
|
|
@@ -1012,27 +1040,37 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1012
1040
|
let sendTx: TransactionRequest = txs.transactions[txs.transactions.length - 1]!
|
|
1013
1041
|
|
|
1014
1042
|
// approve all tokens (including feeToken, if needed) in parallel
|
|
1015
|
-
let nonce = await this.provider.getTransactionCount(sender)
|
|
1016
1043
|
const responses = await Promise.all(
|
|
1017
1044
|
approveTxs.map(async (tx: TransactionRequest) => {
|
|
1018
|
-
tx.nonce =
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1045
|
+
tx.nonce = await this.nextNonce(sender)
|
|
1046
|
+
try {
|
|
1047
|
+
tx = await wallet.populateTransaction(tx)
|
|
1048
|
+
tx.from = undefined
|
|
1049
|
+
const response = await submitTransaction(wallet, tx, this.provider)
|
|
1050
|
+
this.logger.debug('approve =>', response.hash)
|
|
1051
|
+
return response
|
|
1052
|
+
} catch (err) {
|
|
1053
|
+
this.nonces[sender]!--
|
|
1054
|
+
throw err
|
|
1055
|
+
}
|
|
1024
1056
|
}),
|
|
1025
1057
|
)
|
|
1026
1058
|
if (responses.length) await responses[responses.length - 1]!.wait(1, 60_000) // wait last tx nonce to be mined
|
|
1027
1059
|
|
|
1028
|
-
sendTx.nonce =
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1060
|
+
sendTx.nonce = await this.nextNonce(sender)
|
|
1061
|
+
let response
|
|
1062
|
+
try {
|
|
1063
|
+
// sendTx.gasLimit = await this.provider.estimateGas(sendTx)
|
|
1064
|
+
sendTx = await wallet.populateTransaction(sendTx)
|
|
1065
|
+
sendTx.from = undefined // some signers don't like receiving pre-populated `from`
|
|
1066
|
+
response = await submitTransaction(wallet, sendTx, this.provider)
|
|
1067
|
+
} catch (err) {
|
|
1068
|
+
this.nonces[sender]!--
|
|
1069
|
+
throw err
|
|
1070
|
+
}
|
|
1033
1071
|
this.logger.debug('ccipSend =>', response.hash)
|
|
1034
|
-
await response.wait(1, 60_000)
|
|
1035
|
-
return (await this.getMessagesInTx(await this.getTransaction(
|
|
1072
|
+
const tx = (await response.wait(1, 60_000))!
|
|
1073
|
+
return (await this.getMessagesInTx(await this.getTransaction(tx)))[0]!
|
|
1036
1074
|
}
|
|
1037
1075
|
|
|
1038
1076
|
/** {@inheritDoc Chain.getOffchainTokenData} */
|
|
@@ -1041,33 +1079,70 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1041
1079
|
}
|
|
1042
1080
|
|
|
1043
1081
|
/**
|
|
1044
|
-
* {@inheritDoc Chain.
|
|
1082
|
+
* {@inheritDoc Chain.generateUnsignedExecute}
|
|
1045
1083
|
* @returns array containing one unsigned `manuallyExecute` TransactionRequest object
|
|
1046
1084
|
* @throws {@link CCIPVersionUnsupportedError} if OffRamp version is not supported
|
|
1047
1085
|
*/
|
|
1048
|
-
async
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1086
|
+
async generateUnsignedExecute(
|
|
1087
|
+
opts: Parameters<Chain['generateUnsignedExecute']>[0],
|
|
1088
|
+
): Promise<UnsignedEVMTx> {
|
|
1089
|
+
let input: ExecutionInput, offRamp: string
|
|
1090
|
+
if (!('input' in opts)) {
|
|
1091
|
+
if (!this.apiClient) throw new CCIPApiClientNotAvailableError()
|
|
1092
|
+
;({ offRamp, ...input } = await this.apiClient.getExecutionInput(opts.messageId))
|
|
1093
|
+
} else {
|
|
1094
|
+
;({ offRamp, input } = opts)
|
|
1095
|
+
}
|
|
1096
|
+
if ('verifications' in input) {
|
|
1097
|
+
const contract = new Contract(
|
|
1098
|
+
offRamp,
|
|
1099
|
+
interfaces.OffRamp_v2_0,
|
|
1100
|
+
this.provider,
|
|
1101
|
+
) as unknown as TypedContract<typeof OffRamp_2_0_ABI>
|
|
1102
|
+
|
|
1103
|
+
const message = decodeMessageV1(input.encodedMessage)
|
|
1104
|
+
const messageId = keccak256(input.encodedMessage)
|
|
1105
|
+
// `execute` doesn't revert on failure, so we need to estimate using `executeSingleMessage`
|
|
1106
|
+
const txGasLimit = await contract.executeSingleMessage.estimateGas(
|
|
1107
|
+
{
|
|
1108
|
+
...message,
|
|
1109
|
+
executionGasLimit: BigInt(message.executionGasLimit),
|
|
1110
|
+
ccipReceiveGasLimit: BigInt(message.ccipReceiveGasLimit),
|
|
1111
|
+
finality: BigInt(message.finality),
|
|
1112
|
+
},
|
|
1113
|
+
messageId,
|
|
1114
|
+
input.verifications.map(({ destAddress }) => destAddress),
|
|
1115
|
+
input.verifications.map(({ ccvData }) => hexlify(ccvData)),
|
|
1116
|
+
BigInt(opts.gasLimit ?? 0),
|
|
1117
|
+
{ from: offRamp }, // internal method
|
|
1118
|
+
)
|
|
1119
|
+
const execTx = await contract.execute.populateTransaction(
|
|
1120
|
+
input.encodedMessage,
|
|
1121
|
+
input.verifications.map(({ destAddress }) => destAddress),
|
|
1122
|
+
input.verifications.map(({ ccvData }) => hexlify(ccvData)),
|
|
1123
|
+
BigInt(opts.gasLimit ?? 0),
|
|
1124
|
+
)
|
|
1125
|
+
execTx.gasLimit = txGasLimit + 40000n // plus `execute`'s overhead
|
|
1126
|
+
return { family: ChainFamily.EVM, transactions: [execTx] }
|
|
1127
|
+
}
|
|
1054
1128
|
|
|
1055
1129
|
let manualExecTx
|
|
1056
|
-
const
|
|
1130
|
+
const [_, version] = await this.typeAndVersion(offRamp)
|
|
1131
|
+
const offchainTokenData = input.offchainTokenData.map(encodeEVMOffchainTokenData)
|
|
1057
1132
|
|
|
1058
1133
|
switch (version) {
|
|
1059
1134
|
case CCIPVersion.V1_2: {
|
|
1060
1135
|
const contract = new Contract(
|
|
1061
1136
|
offRamp,
|
|
1062
|
-
|
|
1137
|
+
interfaces.EVM2EVMOffRamp_v1_2,
|
|
1063
1138
|
this.provider,
|
|
1064
1139
|
) as unknown as TypedContract<typeof EVM2EVMOffRamp_1_2_ABI>
|
|
1065
1140
|
const gasOverride = BigInt(opts.gasLimit ?? 0)
|
|
1066
1141
|
manualExecTx = await contract.manuallyExecute.populateTransaction(
|
|
1067
1142
|
{
|
|
1068
|
-
...
|
|
1069
|
-
proofs:
|
|
1070
|
-
messages: [
|
|
1143
|
+
...input,
|
|
1144
|
+
proofs: input.proofs.map((d) => hexlify(d)),
|
|
1145
|
+
messages: [input.message as CCIPMessage<typeof CCIPVersion.V1_2>],
|
|
1071
1146
|
offchainTokenData: [offchainTokenData],
|
|
1072
1147
|
},
|
|
1073
1148
|
[gasOverride],
|
|
@@ -1077,20 +1152,20 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1077
1152
|
case CCIPVersion.V1_5: {
|
|
1078
1153
|
const contract = new Contract(
|
|
1079
1154
|
offRamp,
|
|
1080
|
-
|
|
1155
|
+
interfaces.EVM2EVMOffRamp_v1_5,
|
|
1081
1156
|
this.provider,
|
|
1082
1157
|
) as unknown as TypedContract<typeof EVM2EVMOffRamp_1_5_ABI>
|
|
1083
1158
|
manualExecTx = await contract.manuallyExecute.populateTransaction(
|
|
1084
1159
|
{
|
|
1085
|
-
...
|
|
1086
|
-
proofs:
|
|
1087
|
-
messages: [
|
|
1160
|
+
...input,
|
|
1161
|
+
proofs: input.proofs.map((d) => hexlify(d)),
|
|
1162
|
+
messages: [input.message as CCIPMessage<typeof CCIPVersion.V1_5>],
|
|
1088
1163
|
offchainTokenData: [offchainTokenData],
|
|
1089
1164
|
},
|
|
1090
1165
|
[
|
|
1091
1166
|
{
|
|
1092
1167
|
receiverExecutionGasLimit: BigInt(opts.gasLimit ?? 0),
|
|
1093
|
-
tokenGasOverrides:
|
|
1168
|
+
tokenGasOverrides: input.message.tokenAmounts.map(() =>
|
|
1094
1169
|
BigInt(opts.tokensGasLimit ?? opts.gasLimit ?? 0),
|
|
1095
1170
|
),
|
|
1096
1171
|
},
|
|
@@ -1100,30 +1175,32 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1100
1175
|
}
|
|
1101
1176
|
case CCIPVersion.V1_6: {
|
|
1102
1177
|
// normalize message
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1178
|
+
const senderBytes = getAddressBytes(input.message.sender)
|
|
1179
|
+
// Addresses ≤32 bytes (EVM 20B, Aptos/Solana/Sui 32B) are zero-padded to 32 bytes;
|
|
1180
|
+
// Addresses >32 bytes (e.g., TON 36B) are used as raw bytes without padding
|
|
1181
|
+
const sender =
|
|
1182
|
+
senderBytes.length <= 32 ? zeroPadValue(senderBytes, 32) : hexlify(senderBytes)
|
|
1183
|
+
const tokenAmounts = (input.message as CCIPMessage_V1_6_EVM).tokenAmounts.map((ta) => ({
|
|
1184
|
+
...ta,
|
|
1185
|
+
sourcePoolAddress: zeroPadValue(getAddressBytes(ta.sourcePoolAddress), 32),
|
|
1186
|
+
extraData: hexlify(getDataBytes(ta.extraData)),
|
|
1187
|
+
}))
|
|
1111
1188
|
const message = {
|
|
1112
|
-
...(
|
|
1189
|
+
...(input.message as CCIPMessage_V1_6_EVM),
|
|
1113
1190
|
sender,
|
|
1114
1191
|
tokenAmounts,
|
|
1115
1192
|
}
|
|
1116
1193
|
const contract = new Contract(
|
|
1117
1194
|
offRamp,
|
|
1118
|
-
|
|
1195
|
+
interfaces.OffRamp_v1_6,
|
|
1119
1196
|
this.provider,
|
|
1120
1197
|
) as unknown as TypedContract<typeof OffRamp_1_6_ABI>
|
|
1121
1198
|
manualExecTx = await contract.manuallyExecute.populateTransaction(
|
|
1122
1199
|
[
|
|
1123
1200
|
{
|
|
1124
|
-
...
|
|
1125
|
-
proofs:
|
|
1126
|
-
sourceChainSelector:
|
|
1201
|
+
...input,
|
|
1202
|
+
proofs: input.proofs.map((p) => hexlify(p)),
|
|
1203
|
+
sourceChainSelector: input.message.sourceChainSelector,
|
|
1127
1204
|
messages: [
|
|
1128
1205
|
{
|
|
1129
1206
|
...message,
|
|
@@ -1143,7 +1220,7 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1143
1220
|
[
|
|
1144
1221
|
{
|
|
1145
1222
|
receiverExecutionGasLimit: BigInt(opts.gasLimit ?? 0),
|
|
1146
|
-
tokenGasOverrides:
|
|
1223
|
+
tokenGasOverrides: input.message.tokenAmounts.map(() =>
|
|
1147
1224
|
BigInt(opts.tokensGasLimit ?? opts.gasLimit ?? 0),
|
|
1148
1225
|
),
|
|
1149
1226
|
},
|
|
@@ -1159,23 +1236,28 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1159
1236
|
}
|
|
1160
1237
|
|
|
1161
1238
|
/**
|
|
1162
|
-
* {@inheritDoc Chain.
|
|
1239
|
+
* {@inheritDoc Chain.execute}
|
|
1163
1240
|
* @throws {@link CCIPWalletInvalidError} if wallet is not a valid Signer
|
|
1164
1241
|
* @throws {@link CCIPExecTxNotConfirmedError} if execution transaction fails to confirm
|
|
1165
1242
|
* @throws {@link CCIPExecTxRevertedError} if execution transaction reverts
|
|
1166
1243
|
*/
|
|
1167
|
-
async
|
|
1244
|
+
async execute(opts: Parameters<Chain['execute']>[0]) {
|
|
1168
1245
|
const wallet = opts.wallet
|
|
1169
1246
|
if (!isSigner(wallet)) throw new CCIPWalletInvalidError(wallet)
|
|
1170
1247
|
|
|
1171
|
-
const unsignedTxs = await this.
|
|
1248
|
+
const unsignedTxs = await this.generateUnsignedExecute({
|
|
1172
1249
|
...opts,
|
|
1173
1250
|
payer: await wallet.getAddress(),
|
|
1174
1251
|
})
|
|
1175
|
-
|
|
1176
|
-
unsignedTx
|
|
1177
|
-
|
|
1252
|
+
|
|
1253
|
+
const unsignedTx: TransactionRequest = unsignedTxs.transactions[0]!
|
|
1254
|
+
unsignedTx.nonce = await this.nextNonce(await wallet.getAddress())
|
|
1255
|
+
const populatedTx = await wallet.populateTransaction(unsignedTx)
|
|
1256
|
+
populatedTx.from = undefined // some signers don't like receiving pre-populated `from`
|
|
1257
|
+
|
|
1258
|
+
const response = await submitTransaction(wallet, populatedTx, this.provider)
|
|
1178
1259
|
this.logger.debug('manuallyExecute =>', response.hash)
|
|
1260
|
+
|
|
1179
1261
|
const receipt = await response.wait(1, 60_000)
|
|
1180
1262
|
if (!receipt?.hash) throw new CCIPExecTxNotConfirmedError(response.hash)
|
|
1181
1263
|
if (!receipt.status) throw new CCIPExecTxRevertedError(response.hash)
|
|
@@ -1407,6 +1489,64 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1407
1489
|
)
|
|
1408
1490
|
}
|
|
1409
1491
|
|
|
1492
|
+
/** {@inheritDoc Chain.getVerifications} */
|
|
1493
|
+
override async getVerifications(
|
|
1494
|
+
opts: Parameters<Chain['getVerifications']>[0],
|
|
1495
|
+
): Promise<CCIPVerifications> {
|
|
1496
|
+
const { offRamp, request } = opts
|
|
1497
|
+
if (request.lane.version >= CCIPVersion.V2_0) {
|
|
1498
|
+
const message = request.message as CCIPMessage_V2_0
|
|
1499
|
+
if (!message.encodedMessage)
|
|
1500
|
+
throw new CCIPNotImplementedError(`CCIPAPIClient getMessageById v2 encodedMessage`)
|
|
1501
|
+
const contract = new Contract(
|
|
1502
|
+
offRamp,
|
|
1503
|
+
interfaces.OffRamp_v2_0,
|
|
1504
|
+
this.provider,
|
|
1505
|
+
) as unknown as TypedContract<typeof OffRamp_2_0_ABI>
|
|
1506
|
+
const ccvs = await contract.getCCVsForMessage(message.encodedMessage)
|
|
1507
|
+
const [requiredCCVs, optionalCCVs, optionalThreshold] = ccvs.map(
|
|
1508
|
+
resultToObject,
|
|
1509
|
+
) as unknown as CleanAddressable<typeof ccvs>
|
|
1510
|
+
const verificationPolicy = {
|
|
1511
|
+
requiredCCVs,
|
|
1512
|
+
optionalCCVs,
|
|
1513
|
+
optionalThreshold: Number(optionalThreshold),
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
if (this.apiClient) {
|
|
1517
|
+
const apiRes = await this.apiClient.getMessageById(request.message.messageId)
|
|
1518
|
+
if ('verifiers' in apiRes.message) {
|
|
1519
|
+
const verifiers = apiRes.message.verifiers as {
|
|
1520
|
+
items: {
|
|
1521
|
+
destAddress: string
|
|
1522
|
+
sourceAddress: string
|
|
1523
|
+
verification: { data: string; timestamp: string }
|
|
1524
|
+
}[]
|
|
1525
|
+
}
|
|
1526
|
+
return {
|
|
1527
|
+
verificationPolicy,
|
|
1528
|
+
verifications: verifiers.items.map((item) => ({
|
|
1529
|
+
destAddress: item.destAddress,
|
|
1530
|
+
sourceAddress: item.sourceAddress,
|
|
1531
|
+
ccvData: item.verification.data,
|
|
1532
|
+
timestamp: new Date(item.verification.timestamp).getTime() / 1e3,
|
|
1533
|
+
})),
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
const url = `${CCV_INDEXER_URL}/v1/verifierresults/${request.message.messageId}`
|
|
1539
|
+
const res = await fetch(url)
|
|
1540
|
+
const json = await res.json()
|
|
1541
|
+
return json as CCIPVerifications
|
|
1542
|
+
} else if (request.lane.version < CCIPVersion.V1_6) {
|
|
1543
|
+
// v1.2..v1.5 EVM (only) have separate CommitStore
|
|
1544
|
+
opts.offRamp = await this.getCommitStoreForOffRamp(opts.offRamp)
|
|
1545
|
+
}
|
|
1546
|
+
// fallback <=v1.6
|
|
1547
|
+
return super.getVerifications(opts)
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1410
1550
|
/** {@inheritDoc Chain.getExecutionReceipts} */
|
|
1411
1551
|
override async *getExecutionReceipts(
|
|
1412
1552
|
opts: Parameters<Chain['getExecutionReceipts']>[0],
|
|
@@ -1426,10 +1566,14 @@ export class EVMChain extends Chain<typeof ChainFamily.EVM> {
|
|
|
1426
1566
|
// onlyFallback: false,
|
|
1427
1567
|
}
|
|
1428
1568
|
} else /* >= V1.6 */ {
|
|
1569
|
+
const topicHash =
|
|
1570
|
+
version === CCIPVersion.V1_6
|
|
1571
|
+
? interfaces.OffRamp_v1_6.getEvent('ExecutionStateChanged')!.topicHash
|
|
1572
|
+
: interfaces.OffRamp_v2_0.getEvent('ExecutionStateChanged')!.topicHash
|
|
1429
1573
|
opts_ = {
|
|
1430
1574
|
...opts,
|
|
1431
1575
|
topics: [
|
|
1432
|
-
|
|
1576
|
+
topicHash,
|
|
1433
1577
|
sourceChainSelector ? toBeHex(sourceChainSelector, 32) : null,
|
|
1434
1578
|
null,
|
|
1435
1579
|
messageId ?? null,
|