@chainlink/ccip-cli 0.0.0 → 0.90.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/LICENSE +21 -0
- package/README.md +238 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/manual-exec.d.ts +56 -0
- package/dist/commands/manual-exec.d.ts.map +1 -0
- package/dist/commands/manual-exec.js +405 -0
- package/dist/commands/manual-exec.js.map +1 -0
- package/dist/commands/parse.d.ts +9 -0
- package/dist/commands/parse.d.ts.map +1 -0
- package/dist/commands/parse.js +47 -0
- package/dist/commands/parse.js.map +1 -0
- package/dist/commands/send.d.ts +80 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +258 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/show.d.ts +18 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +112 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/supported-tokens.d.ts +37 -0
- package/dist/commands/supported-tokens.d.ts.map +1 -0
- package/dist/commands/supported-tokens.js +214 -0
- package/dist/commands/supported-tokens.js.map +1 -0
- package/dist/commands/types.d.ts +7 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +6 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands/utils.d.ts +40 -0
- package/dist/commands/utils.d.ts.map +1 -0
- package/dist/commands/utils.js +330 -0
- package/dist/commands/utils.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/aptos.d.ts +15 -0
- package/dist/providers/aptos.d.ts.map +1 -0
- package/dist/providers/aptos.js +74 -0
- package/dist/providers/aptos.js.map +1 -0
- package/dist/providers/evm.d.ts +2 -0
- package/dist/providers/evm.d.ts.map +1 -0
- package/dist/providers/evm.js +42 -0
- package/dist/providers/evm.js.map +1 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +104 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/solana.d.ts +13 -0
- package/dist/providers/solana.d.ts.map +1 -0
- package/dist/providers/solana.js +79 -0
- package/dist/providers/solana.js.map +1 -0
- package/package.json +57 -8
- package/src/commands/index.ts +1 -0
- package/src/commands/manual-exec.ts +468 -0
- package/src/commands/parse.ts +52 -0
- package/src/commands/send.ts +316 -0
- package/src/commands/show.ts +151 -0
- package/src/commands/supported-tokens.ts +245 -0
- package/src/commands/types.ts +6 -0
- package/src/commands/utils.ts +404 -0
- package/src/index.ts +70 -0
- package/src/providers/aptos.ts +100 -0
- package/src/providers/evm.ts +48 -0
- package/src/providers/index.ts +141 -0
- package/src/providers/solana.ts +93 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CCIPRequest,
|
|
3
|
+
type CCIPVersion,
|
|
4
|
+
type ChainStatic,
|
|
5
|
+
type EVMChain,
|
|
6
|
+
type ExecutionReport,
|
|
7
|
+
ChainFamily,
|
|
8
|
+
bigIntReplacer,
|
|
9
|
+
calculateManualExecProof,
|
|
10
|
+
discoverOffRamp,
|
|
11
|
+
estimateExecGasForRequest,
|
|
12
|
+
fetchAllMessagesInBatch,
|
|
13
|
+
fetchCCIPRequestsInTx,
|
|
14
|
+
} from '@chainlink/ccip-sdk/src/index.ts'
|
|
15
|
+
import type { Argv } from 'yargs'
|
|
16
|
+
|
|
17
|
+
import type { GlobalOpts } from '../index.ts'
|
|
18
|
+
import { Format } from './types.ts'
|
|
19
|
+
import {
|
|
20
|
+
logParsedError,
|
|
21
|
+
prettyCommit,
|
|
22
|
+
prettyReceipt,
|
|
23
|
+
prettyRequest,
|
|
24
|
+
selectRequest,
|
|
25
|
+
withDateTimestamp,
|
|
26
|
+
} from './utils.ts'
|
|
27
|
+
import { fetchChainsFromRpcs } from '../providers/index.ts'
|
|
28
|
+
|
|
29
|
+
// const MAX_QUEUE = 1000
|
|
30
|
+
// const MAX_EXECS_IN_BATCH = 1
|
|
31
|
+
// const MAX_PENDING_TXS = 25
|
|
32
|
+
|
|
33
|
+
export const command = 'manualExec <tx-hash>'
|
|
34
|
+
export const describe = 'Execute manually pending or failed messages'
|
|
35
|
+
|
|
36
|
+
export const builder = (yargs: Argv) =>
|
|
37
|
+
yargs
|
|
38
|
+
.positional('tx-hash', {
|
|
39
|
+
type: 'string',
|
|
40
|
+
demandOption: true,
|
|
41
|
+
describe: 'transaction hash of the request (source) message',
|
|
42
|
+
})
|
|
43
|
+
.options({
|
|
44
|
+
'log-index': {
|
|
45
|
+
type: 'number',
|
|
46
|
+
describe: 'Log index of message to execute (if more than one in request tx)',
|
|
47
|
+
},
|
|
48
|
+
'gas-limit': {
|
|
49
|
+
alias: ['L', 'compute-units'],
|
|
50
|
+
type: 'number',
|
|
51
|
+
describe: 'Override gas limit or compute units for receivers callback (0 keeps original)',
|
|
52
|
+
},
|
|
53
|
+
'tokens-gas-limit': {
|
|
54
|
+
type: 'number',
|
|
55
|
+
describe: 'Override gas limit for tokens releaseOrMint calls (0 keeps original)',
|
|
56
|
+
},
|
|
57
|
+
'estimate-gas-limit': {
|
|
58
|
+
type: 'number',
|
|
59
|
+
describe:
|
|
60
|
+
'Estimate gas limit for receivers callback; argument is a % margin to add to the estimate',
|
|
61
|
+
example: '10',
|
|
62
|
+
conflicts: 'gas-limit',
|
|
63
|
+
},
|
|
64
|
+
wallet: {
|
|
65
|
+
alias: 'w',
|
|
66
|
+
type: 'string',
|
|
67
|
+
describe:
|
|
68
|
+
'Wallet to send transactions with; pass `ledger[:index_or_derivation]` to use Ledger USB hardware wallet, or private key in `USER_KEY` environment variable',
|
|
69
|
+
},
|
|
70
|
+
'force-buffer': {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
describe: 'Forces the usage of buffering for Solana execution.',
|
|
73
|
+
},
|
|
74
|
+
'force-lookup-table': {
|
|
75
|
+
type: 'boolean',
|
|
76
|
+
describe: 'Forces the creation & usage of an ad-hoc lookup table for Solana execution.',
|
|
77
|
+
},
|
|
78
|
+
'clear-leftover-accounts': {
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
describe:
|
|
81
|
+
'Clears buffers (if a previous attempt was aborted) or any ALT owned by this sender.',
|
|
82
|
+
},
|
|
83
|
+
'sender-queue': {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
describe: 'Execute all messages in sender queue, starting with the provided tx',
|
|
86
|
+
default: false,
|
|
87
|
+
},
|
|
88
|
+
'exec-failed': {
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
describe:
|
|
91
|
+
'Whether to re-execute failed messages (instead of just non-executed) in sender queue',
|
|
92
|
+
implies: 'sender-queue',
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
export async function handler(argv: Awaited<ReturnType<typeof builder>['argv']> & GlobalOpts) {
|
|
97
|
+
if (!argv.wallet) argv.wallet = process.env['USER_KEY'] || process.env['OWNER_KEY']
|
|
98
|
+
let destroy
|
|
99
|
+
const destroy$ = new Promise((resolve) => {
|
|
100
|
+
destroy = resolve
|
|
101
|
+
})
|
|
102
|
+
// argv.senderQueue
|
|
103
|
+
// ? manualExecSenderQueue(providers, argv.tx_hash, argv)
|
|
104
|
+
// : manualExec(argv, destroy$)
|
|
105
|
+
return manualExec(argv, destroy$)
|
|
106
|
+
.catch((err) => {
|
|
107
|
+
process.exitCode = 1
|
|
108
|
+
if (!logParsedError(err)) console.error(err)
|
|
109
|
+
})
|
|
110
|
+
.finally(destroy)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function manualExec(
|
|
114
|
+
argv: Awaited<ReturnType<typeof builder>['argv']> & GlobalOpts,
|
|
115
|
+
destroy: Promise<unknown>,
|
|
116
|
+
) {
|
|
117
|
+
// messageId not yet implemented for Solana
|
|
118
|
+
const [getChain, tx$] = fetchChainsFromRpcs(argv, argv.txHash, destroy)
|
|
119
|
+
const tx = await tx$
|
|
120
|
+
const source = tx.chain
|
|
121
|
+
const request = await selectRequest(await fetchCCIPRequestsInTx(tx), 'to know more', argv)
|
|
122
|
+
|
|
123
|
+
switch (argv.format) {
|
|
124
|
+
case Format.log: {
|
|
125
|
+
const logPrefix = 'log' in request ? `message ${request.log.index} = ` : 'message = '
|
|
126
|
+
console.log(logPrefix, withDateTimestamp(request))
|
|
127
|
+
break
|
|
128
|
+
}
|
|
129
|
+
case Format.pretty:
|
|
130
|
+
await prettyRequest(source, request)
|
|
131
|
+
break
|
|
132
|
+
case Format.json:
|
|
133
|
+
console.info(JSON.stringify(request, bigIntReplacer, 2))
|
|
134
|
+
break
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const dest = await getChain(request.lane.destChainSelector)
|
|
138
|
+
const offRamp = await discoverOffRamp(source, dest, request.lane.onRamp)
|
|
139
|
+
const commitStore = await dest.getCommitStoreForOffRamp(offRamp)
|
|
140
|
+
const commit = await dest.fetchCommitReport(commitStore, request, argv)
|
|
141
|
+
|
|
142
|
+
switch (argv.format) {
|
|
143
|
+
case Format.log:
|
|
144
|
+
console.log('commit =', commit)
|
|
145
|
+
break
|
|
146
|
+
case Format.pretty:
|
|
147
|
+
await prettyCommit(dest, commit, request)
|
|
148
|
+
break
|
|
149
|
+
case Format.json:
|
|
150
|
+
console.info(JSON.stringify(commit, bigIntReplacer, 2))
|
|
151
|
+
break
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const messagesInBatch = await fetchAllMessagesInBatch(source, request, commit.report, argv)
|
|
155
|
+
const execReportProof = calculateManualExecProof(
|
|
156
|
+
messagesInBatch,
|
|
157
|
+
request.lane,
|
|
158
|
+
request.message.header.messageId,
|
|
159
|
+
commit.report.merkleRoot,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
const offchainTokenData = await source.fetchOffchainTokenData(request)
|
|
163
|
+
const execReport: ExecutionReport = {
|
|
164
|
+
...execReportProof,
|
|
165
|
+
message: request.message,
|
|
166
|
+
offchainTokenData: offchainTokenData,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
argv.estimateGasLimit != null &&
|
|
171
|
+
'gasLimit' in request.message &&
|
|
172
|
+
'extraArgs' in request.message
|
|
173
|
+
) {
|
|
174
|
+
if (dest.network.family !== ChainFamily.EVM)
|
|
175
|
+
throw new Error('Gas estimation is only supported for EVM networks for now')
|
|
176
|
+
|
|
177
|
+
let estimated = await estimateExecGasForRequest(
|
|
178
|
+
source,
|
|
179
|
+
dest as unknown as EVMChain,
|
|
180
|
+
request as CCIPRequest<typeof CCIPVersion.V1_5 | typeof CCIPVersion.V1_6>,
|
|
181
|
+
)
|
|
182
|
+
console.info('Estimated gasLimit override:', estimated)
|
|
183
|
+
estimated += Math.ceil((estimated * argv.estimateGasLimit) / 100)
|
|
184
|
+
if (request.message.gasLimit >= estimated) {
|
|
185
|
+
console.warn(
|
|
186
|
+
'Estimated +',
|
|
187
|
+
argv.estimateGasLimit,
|
|
188
|
+
'% margin =',
|
|
189
|
+
estimated,
|
|
190
|
+
'< original gasLimit =',
|
|
191
|
+
request.message.gasLimit,
|
|
192
|
+
'. Leaving unchanged.',
|
|
193
|
+
)
|
|
194
|
+
} else {
|
|
195
|
+
argv.gasLimit = estimated
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const manualExecTx = await dest.executeReport(offRamp, execReport, argv)
|
|
200
|
+
|
|
201
|
+
console.log('🚀 manualExec tx =', manualExecTx.hash, 'to offRamp =', offRamp)
|
|
202
|
+
|
|
203
|
+
let found = false
|
|
204
|
+
for (const log of manualExecTx.logs) {
|
|
205
|
+
const execReceipt = (dest.constructor as ChainStatic).decodeReceipt(log)
|
|
206
|
+
if (!execReceipt) continue
|
|
207
|
+
const timestamp = await dest.getBlockTimestamp(log.blockNumber)
|
|
208
|
+
const receipt = { receipt: execReceipt, log, timestamp }
|
|
209
|
+
switch (argv.format) {
|
|
210
|
+
case Format.log:
|
|
211
|
+
console.log('receipt =', withDateTimestamp(receipt))
|
|
212
|
+
break
|
|
213
|
+
case Format.pretty:
|
|
214
|
+
if (!found) console.info('Receipts (dest):')
|
|
215
|
+
prettyReceipt(
|
|
216
|
+
receipt,
|
|
217
|
+
request,
|
|
218
|
+
receipt.log.tx?.from ??
|
|
219
|
+
(await dest.getTransaction(receipt.log.transactionHash).catch(() => null))?.from,
|
|
220
|
+
)
|
|
221
|
+
break
|
|
222
|
+
case Format.json:
|
|
223
|
+
console.info(JSON.stringify(execReceipt, bigIntReplacer, 2))
|
|
224
|
+
break
|
|
225
|
+
}
|
|
226
|
+
found = true
|
|
227
|
+
}
|
|
228
|
+
if (!found) throw new Error(`Could not find receipt in tx logs`)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/*
|
|
232
|
+
export async function manualExecSenderQueue(
|
|
233
|
+
providers: Providers,
|
|
234
|
+
txHash: string,
|
|
235
|
+
argv: {
|
|
236
|
+
gasLimit?: number
|
|
237
|
+
tokensGasLimit?: number
|
|
238
|
+
logIndex?: number
|
|
239
|
+
execFailed?: boolean
|
|
240
|
+
format: Format
|
|
241
|
+
page: number
|
|
242
|
+
wallet?: string
|
|
243
|
+
},
|
|
244
|
+
) {
|
|
245
|
+
const tx = await providers.getTxReceipt(txHash)
|
|
246
|
+
const source = tx.provider
|
|
247
|
+
|
|
248
|
+
let firstRequest
|
|
249
|
+
if (argv.logIndex != null) {
|
|
250
|
+
firstRequest = await fetchCCIPMessageInLog(tx, argv.logIndex)
|
|
251
|
+
} else {
|
|
252
|
+
firstRequest = await selectRequest(await fetchCCIPMessagesInTx(tx), 'to execute')
|
|
253
|
+
}
|
|
254
|
+
switch (argv.format) {
|
|
255
|
+
case Format.log:
|
|
256
|
+
console.log(`message ${firstRequest.log.index} =`, withDateTimestamp(firstRequest))
|
|
257
|
+
break
|
|
258
|
+
case Format.pretty:
|
|
259
|
+
await prettyRequest(source, firstRequest)
|
|
260
|
+
break
|
|
261
|
+
case Format.json:
|
|
262
|
+
console.info(JSON.stringify(firstRequest, bigIntReplacer, 2))
|
|
263
|
+
break
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const dest = await providers.forChainId(chainIdFromSelector(firstRequest.lane.destChainSelector))
|
|
267
|
+
|
|
268
|
+
const requests: Omit<CCIPRequest, 'timestamp' | 'tx'>[] = []
|
|
269
|
+
for await (const request of fetchRequestsForSender(source, firstRequest)) {
|
|
270
|
+
requests.push(request)
|
|
271
|
+
if (requests.length >= MAX_QUEUE) break
|
|
272
|
+
}
|
|
273
|
+
console.info('Found', requests.length, `requests for "${firstRequest.message.sender}"`)
|
|
274
|
+
if (!requests.length) return
|
|
275
|
+
|
|
276
|
+
let startBlock = await getSomeBlockNumberBefore(dest, firstRequest.timestamp)
|
|
277
|
+
const wallet = (await getWallet(argv)).connect(dest)
|
|
278
|
+
const offRampContract = await discoverOffRamp(wallet, firstRequest.lane, {
|
|
279
|
+
fromBlock: startBlock,
|
|
280
|
+
page: argv.page,
|
|
281
|
+
})
|
|
282
|
+
const senderNonce = await offRampContract.getSenderNonce(firstRequest.message.sender)
|
|
283
|
+
const origRequestsCnt = requests.length,
|
|
284
|
+
last = requests[requests.length - 1]
|
|
285
|
+
while (requests.length && requests[0].message.header.sequenceNumber <= senderNonce) {
|
|
286
|
+
requests.shift()
|
|
287
|
+
}
|
|
288
|
+
console.info(
|
|
289
|
+
'Found',
|
|
290
|
+
requests.length,
|
|
291
|
+
`requests for "${firstRequest.message.sender}", removed `,
|
|
292
|
+
origRequestsCnt - requests.length,
|
|
293
|
+
'already executed before senderNonce =',
|
|
294
|
+
senderNonce,
|
|
295
|
+
'. Last source txHash =',
|
|
296
|
+
last.log.transactionHash,
|
|
297
|
+
)
|
|
298
|
+
if (!requests.length) return
|
|
299
|
+
let nonce = await wallet.getNonce()
|
|
300
|
+
|
|
301
|
+
let lastBatch:
|
|
302
|
+
| readonly [CCIPCommit, Omit<CCIPRequest<CCIPVersion>, 'tx' | 'timestamp'>[]]
|
|
303
|
+
| undefined
|
|
304
|
+
const txsPending = []
|
|
305
|
+
for (let i = 0; i < requests.length; ) {
|
|
306
|
+
let commit, batch
|
|
307
|
+
if (!lastBatch || requests[i].message.header.sequenceNumber > lastBatch[0].report.maxSeqNr) {
|
|
308
|
+
commit = await fetchCommitReport(dest, requests[i], {
|
|
309
|
+
startBlock,
|
|
310
|
+
page: argv.page,
|
|
311
|
+
})
|
|
312
|
+
startBlock = commit.log.blockNumber + 1
|
|
313
|
+
|
|
314
|
+
batch = await fetchAllMessagesInBatch(
|
|
315
|
+
source,
|
|
316
|
+
requests[i].lane.destChainSelector,
|
|
317
|
+
requests[i].log,
|
|
318
|
+
commit.report,
|
|
319
|
+
{ page: argv.page },
|
|
320
|
+
)
|
|
321
|
+
lastBatch = [commit, batch]
|
|
322
|
+
} else {
|
|
323
|
+
;[commit, batch] = lastBatch
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const msgIdsToExec = [] as string[]
|
|
327
|
+
while (
|
|
328
|
+
i < requests.length &&
|
|
329
|
+
requests[i].message.header.sequenceNumber <= commit.report.maxSeqNr &&
|
|
330
|
+
msgIdsToExec.length < MAX_EXECS_IN_BATCH
|
|
331
|
+
) {
|
|
332
|
+
msgIdsToExec.push(requests[i++].message.header.messageId)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const manualExecReport = calculateManualExecProof(
|
|
336
|
+
batch.map(({ message }) => message),
|
|
337
|
+
firstRequest.lane,
|
|
338
|
+
msgIdsToExec,
|
|
339
|
+
commit.report.merkleRoot,
|
|
340
|
+
)
|
|
341
|
+
const requestsToExec = manualExecReport.messages.map(
|
|
342
|
+
({ header }) =>
|
|
343
|
+
requests.find(({ message }) => message.header.messageId === header.messageId)!,
|
|
344
|
+
)
|
|
345
|
+
const offchainTokenData = await Promise.all(
|
|
346
|
+
requestsToExec.map(async (request) => {
|
|
347
|
+
const tx = await lazyCached(`tx ${request.log.transactionHash}`, () =>
|
|
348
|
+
source.getTransactionReceipt(request.log.transactionHash).then((res) => {
|
|
349
|
+
if (!res) throw new Error(`Tx not found: ${request.log.transactionHash}`)
|
|
350
|
+
return res
|
|
351
|
+
}),
|
|
352
|
+
)
|
|
353
|
+
return fetchOffchainTokenData({ ...request, tx })
|
|
354
|
+
}),
|
|
355
|
+
)
|
|
356
|
+
const execReport = { ...manualExecReport, offchainTokenData }
|
|
357
|
+
const getGasLimitOverride = (message: { gasLimit: bigint } | { extraArgs: string }): bigint => {
|
|
358
|
+
if (argv.gasLimit != null) {
|
|
359
|
+
const argvGasLimit = BigInt(argv.gasLimit)
|
|
360
|
+
let msgGasLimit
|
|
361
|
+
if ('gasLimit' in message) {
|
|
362
|
+
msgGasLimit = message.gasLimit
|
|
363
|
+
} else {
|
|
364
|
+
const parsedArgs = parseExtraArgs(message.extraArgs, source.network.family)
|
|
365
|
+
if (!parsedArgs || !('gasLimit' in parsedArgs) || !parsedArgs.gasLimit) {
|
|
366
|
+
throw new Error(`Missing gasLimit argument`)
|
|
367
|
+
}
|
|
368
|
+
msgGasLimit = BigInt(parsedArgs.gasLimit)
|
|
369
|
+
}
|
|
370
|
+
if (argvGasLimit > msgGasLimit) {
|
|
371
|
+
return argvGasLimit
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return 0n
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
let manualExecTx
|
|
378
|
+
if (firstRequest.lane.version === CCIPVersion.V1_2) {
|
|
379
|
+
const gasOverrides = manualExecReport.messages.map((message) =>
|
|
380
|
+
getGasLimitOverride(message as CCIPMessage<typeof CCIPVersion.V1_2>),
|
|
381
|
+
)
|
|
382
|
+
manualExecTx = await (
|
|
383
|
+
offRampContract as CCIPContract<typeof CCIPContractType.OffRamp, typeof CCIPVersion.V1_2>
|
|
384
|
+
).manuallyExecute(
|
|
385
|
+
execReport as {
|
|
386
|
+
offchainTokenData: string[][]
|
|
387
|
+
messages: CCIPMessage<typeof CCIPVersion.V1_2>[]
|
|
388
|
+
proofs: string[]
|
|
389
|
+
proofFlagBits: bigint
|
|
390
|
+
},
|
|
391
|
+
gasOverrides,
|
|
392
|
+
{ nonce: nonce++, gasLimit: argv.gasLimit ? argv.gasLimit : undefined },
|
|
393
|
+
)
|
|
394
|
+
} else if (firstRequest.lane.version === CCIPVersion.V1_5) {
|
|
395
|
+
const gasOverrides = manualExecReport.messages.map((message) => ({
|
|
396
|
+
receiverExecutionGasLimit: getGasLimitOverride(
|
|
397
|
+
message as CCIPMessage<typeof CCIPVersion.V1_5>,
|
|
398
|
+
),
|
|
399
|
+
tokenGasOverrides: message.tokenAmounts.map(() => BigInt(argv.tokensGasLimit ?? 0)),
|
|
400
|
+
}))
|
|
401
|
+
manualExecTx = await (
|
|
402
|
+
offRampContract as CCIPContract<typeof CCIPContractType.OffRamp, typeof CCIPVersion.V1_5>
|
|
403
|
+
).manuallyExecute(
|
|
404
|
+
execReport as {
|
|
405
|
+
offchainTokenData: string[][]
|
|
406
|
+
messages: CCIPMessage<typeof CCIPVersion.V1_5>[]
|
|
407
|
+
proofs: string[]
|
|
408
|
+
proofFlagBits: bigint
|
|
409
|
+
},
|
|
410
|
+
gasOverrides,
|
|
411
|
+
{ nonce: nonce++, gasLimit: argv.gasLimit ? argv.gasLimit : undefined },
|
|
412
|
+
)
|
|
413
|
+
} else {
|
|
414
|
+
const gasOverrides = manualExecReport.messages.map((message) => ({
|
|
415
|
+
receiverExecutionGasLimit: getGasLimitOverride(
|
|
416
|
+
message as CCIPMessage<typeof CCIPVersion.V1_6>,
|
|
417
|
+
),
|
|
418
|
+
tokenGasOverrides: message.tokenAmounts.map(() => BigInt(argv.tokensGasLimit ?? 0)),
|
|
419
|
+
}))
|
|
420
|
+
manualExecTx = await (
|
|
421
|
+
offRampContract as CCIPContract<typeof CCIPContractType.OffRamp, typeof CCIPVersion.V1_6>
|
|
422
|
+
).manuallyExecute(
|
|
423
|
+
[
|
|
424
|
+
{
|
|
425
|
+
sourceChainSelector: firstRequest.lane.sourceChainSelector,
|
|
426
|
+
messages: execReport.messages as (CCIPMessage<typeof CCIPVersion.V1_6> & {
|
|
427
|
+
gasLimit: bigint
|
|
428
|
+
})[],
|
|
429
|
+
proofs: execReport.proofs,
|
|
430
|
+
proofFlagBits: execReport.proofFlagBits,
|
|
431
|
+
offchainTokenData: execReport.offchainTokenData,
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
[gasOverrides],
|
|
435
|
+
{ nonce: nonce++, gasLimit: argv.gasLimit ? argv.gasLimit : undefined },
|
|
436
|
+
)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const toExec = requests[i - 1] // log only request data for last msg in msgIdsToExec
|
|
440
|
+
console.log(
|
|
441
|
+
`🚀 [${i}/${requests.length}, ${batch.length} batch, ${msgIdsToExec.length} to exec]`,
|
|
442
|
+
'source tx =',
|
|
443
|
+
toExec.log.transactionHash,
|
|
444
|
+
'msgId =',
|
|
445
|
+
toExec.message.header.messageId,
|
|
446
|
+
'nonce =',
|
|
447
|
+
toExec.message.header.nonce,
|
|
448
|
+
'manualExec tx =',
|
|
449
|
+
manualExecTx.hash,
|
|
450
|
+
'to =',
|
|
451
|
+
manualExecTx.to,
|
|
452
|
+
'gasLimit =',
|
|
453
|
+
manualExecTx.gasLimit,
|
|
454
|
+
)
|
|
455
|
+
txsPending.push(manualExecTx)
|
|
456
|
+
if (txsPending.length >= MAX_PENDING_TXS) {
|
|
457
|
+
console.debug(
|
|
458
|
+
'awaiting',
|
|
459
|
+
txsPending.length,
|
|
460
|
+
'txs:',
|
|
461
|
+
txsPending.map((tx) => tx.hash),
|
|
462
|
+
)
|
|
463
|
+
await txsPending[txsPending.length - 1].wait()
|
|
464
|
+
txsPending.length = 0
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
*/
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { bigIntReplacer, supportedChains } from '@chainlink/ccip-sdk/src/index.ts'
|
|
2
|
+
import type { Argv } from 'yargs'
|
|
3
|
+
|
|
4
|
+
import type { GlobalOpts } from '../index.ts'
|
|
5
|
+
import { Format } from './types.ts'
|
|
6
|
+
import { prettyTable } from './utils.ts'
|
|
7
|
+
|
|
8
|
+
export const command = ['parse <data>', 'parseBytes <data>', 'parseData <data>']
|
|
9
|
+
export const describe =
|
|
10
|
+
'Try to parse and print errors, revert reasons or function call or event data'
|
|
11
|
+
|
|
12
|
+
export const builder = (yargs: Argv) =>
|
|
13
|
+
yargs.positional('data', {
|
|
14
|
+
type: 'string',
|
|
15
|
+
demandOption: true,
|
|
16
|
+
describe: 'router contract address on source',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export function handler(argv: Awaited<ReturnType<typeof builder>['argv']> & GlobalOpts) {
|
|
20
|
+
try {
|
|
21
|
+
parseBytes(argv)
|
|
22
|
+
} catch (err) {
|
|
23
|
+
process.exitCode = 1
|
|
24
|
+
console.error(err)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseBytes(argv: Parameters<typeof handler>[0]) {
|
|
29
|
+
let parsed
|
|
30
|
+
for (const chain of Object.values(supportedChains)) {
|
|
31
|
+
try {
|
|
32
|
+
parsed = chain.parse?.(argv.data)
|
|
33
|
+
if (parsed) break
|
|
34
|
+
} catch (_) {
|
|
35
|
+
// pass
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!parsed) throw new Error('Unknown data')
|
|
39
|
+
|
|
40
|
+
switch (argv.format) {
|
|
41
|
+
case Format.log: {
|
|
42
|
+
console.log(`parsed =`, parsed)
|
|
43
|
+
break
|
|
44
|
+
}
|
|
45
|
+
case Format.pretty:
|
|
46
|
+
prettyTable(parsed)
|
|
47
|
+
break
|
|
48
|
+
case Format.json:
|
|
49
|
+
console.info(JSON.stringify(parsed, bigIntReplacer, 2))
|
|
50
|
+
break
|
|
51
|
+
}
|
|
52
|
+
}
|