four-flap-meme-sdk 1.1.83 → 1.1.84
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/contracts/tm-bundle-merkle/core.js +64 -232
- package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +31 -104
- package/dist/contracts/tm-bundle-merkle/private.js +56 -207
- package/dist/contracts/tm-bundle-merkle/types.d.ts +1 -0
- package/dist/contracts/tm-bundle-merkle/utils.js +49 -75
- package/dist/flap/portal-bundle-merkle/core.js +48 -118
- package/dist/flap/portal-bundle-merkle/pancake-proxy.js +31 -104
- package/dist/flap/portal-bundle-merkle/private.js +45 -160
- package/dist/flap/portal-bundle-merkle/types.d.ts +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { MerkleClient } from '../../clients/merkle.js';
|
|
|
3
3
|
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
4
4
|
import { ADDRESSES } from '../../utils/constants.js';
|
|
5
5
|
import { FourClient, buildLoginMessage } from '../../clients/four.js';
|
|
6
|
-
import { getErrorMessage, getTxType,
|
|
6
|
+
import { getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit } from './config.js';
|
|
7
7
|
// ==================== TokenManager2 ABI(仅需要的方法)====================
|
|
8
8
|
const TM2_ABI = [
|
|
9
9
|
'function createToken(bytes args, bytes signature) payable',
|
|
@@ -201,111 +201,30 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
201
201
|
});
|
|
202
202
|
signedTxs.push(profitTx);
|
|
203
203
|
}
|
|
204
|
-
// ✅
|
|
205
|
-
if (config.skipSubmit) {
|
|
206
|
-
nonceManager.clearTemp();
|
|
207
|
-
const emptyStatus = {
|
|
208
|
-
bundleHash: '',
|
|
209
|
-
txHashes: [],
|
|
210
|
-
results: [],
|
|
211
|
-
successCount: 0,
|
|
212
|
-
totalGasUsed: 0n,
|
|
213
|
-
targetBlock: 0
|
|
214
|
-
};
|
|
215
|
-
return {
|
|
216
|
-
bundleHash: '',
|
|
217
|
-
tokenAddress: predictedTokenAddress,
|
|
218
|
-
status: emptyStatus,
|
|
219
|
-
createTx: signedCreateTx,
|
|
220
|
-
buyTxs: [],
|
|
221
|
-
signedTransactions: signedTxs,
|
|
222
|
-
metadata: extractProfit ? {
|
|
223
|
-
totalBuyAmount: ethers.formatEther(totalBuyAmount),
|
|
224
|
-
profitAmount: ethers.formatEther(totalProfit),
|
|
225
|
-
profitRecipient: config.profitRecipient,
|
|
226
|
-
buyerCount: buyers.length
|
|
227
|
-
} : undefined
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
// 5. 提交 Bundle(使用智能配置)
|
|
231
|
-
const bundleResult = await merkle.sendBundle({
|
|
232
|
-
transactions: signedTxs,
|
|
233
|
-
...getBundleOptions(config, blockOffset)
|
|
234
|
-
});
|
|
235
|
-
// 6. 根据配置决定是否等待确认
|
|
236
|
-
const waitForConfirmation = config.waitForConfirmation ?? false;
|
|
237
|
-
if (!waitForConfirmation) {
|
|
238
|
-
const status = {
|
|
239
|
-
bundleHash: bundleResult.bundleHash,
|
|
240
|
-
txHashes: bundleResult.txHashes,
|
|
241
|
-
results: [],
|
|
242
|
-
successCount: 0,
|
|
243
|
-
totalGasUsed: 0n,
|
|
244
|
-
targetBlock: bundleResult.targetBlock
|
|
245
|
-
};
|
|
246
|
-
// 清理临时 nonce 缓存
|
|
247
|
-
nonceManager.clearTemp();
|
|
248
|
-
return {
|
|
249
|
-
bundleHash: bundleResult.bundleHash,
|
|
250
|
-
tokenAddress: undefined,
|
|
251
|
-
status,
|
|
252
|
-
createTx: signedCreateTx,
|
|
253
|
-
buyTxs
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
// 7. 等待确认
|
|
257
|
-
const results = await merkle.waitForBundleConfirmation(bundleResult.txHashes, 1, config.waitTimeoutMs ?? 120000);
|
|
258
|
-
const successCount = results.filter(r => r.success).length;
|
|
259
|
-
const totalGasUsed = results.reduce((sum, r) => {
|
|
260
|
-
if (r.gasUsed) {
|
|
261
|
-
return sum + BigInt(r.gasUsed);
|
|
262
|
-
}
|
|
263
|
-
return sum;
|
|
264
|
-
}, 0n);
|
|
265
|
-
const status = {
|
|
266
|
-
bundleHash: bundleResult.bundleHash,
|
|
267
|
-
txHashes: bundleResult.txHashes,
|
|
268
|
-
results,
|
|
269
|
-
successCount,
|
|
270
|
-
totalGasUsed,
|
|
271
|
-
targetBlock: bundleResult.targetBlock
|
|
272
|
-
};
|
|
273
|
-
// 8. 解析 TokenCreate 事件
|
|
274
|
-
let createdTokenAddress;
|
|
275
|
-
if (results[0]?.success) {
|
|
276
|
-
try {
|
|
277
|
-
const createTxHash = bundleResult.txHashes[0];
|
|
278
|
-
if (createTxHash) {
|
|
279
|
-
const receipt = await provider.getTransactionReceipt(createTxHash);
|
|
280
|
-
if (receipt && receipt.logs) {
|
|
281
|
-
const tm2Interface = new ethers.Interface(TM2_ABI);
|
|
282
|
-
for (const log of receipt.logs) {
|
|
283
|
-
try {
|
|
284
|
-
const parsed = tm2Interface.parseLog({ topics: log.topics, data: log.data });
|
|
285
|
-
if (parsed && parsed.name === 'TokenCreate') {
|
|
286
|
-
createdTokenAddress = parsed.args.token;
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
catch (e) {
|
|
291
|
-
// 忽略
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
catch (e) {
|
|
298
|
-
console.warn('Failed to parse token address from receipt:', e);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
// 清理临时 nonce 缓存
|
|
204
|
+
// ✅ 清理临时 nonce 缓存
|
|
302
205
|
nonceManager.clearTemp();
|
|
206
|
+
// ✅ 直接返回签名交易(不提交到Merkle)
|
|
207
|
+
const emptyStatus = {
|
|
208
|
+
bundleHash: '',
|
|
209
|
+
txHashes: [],
|
|
210
|
+
results: [],
|
|
211
|
+
successCount: 0,
|
|
212
|
+
totalGasUsed: 0n,
|
|
213
|
+
targetBlock: 0
|
|
214
|
+
};
|
|
303
215
|
return {
|
|
304
|
-
bundleHash:
|
|
305
|
-
tokenAddress:
|
|
306
|
-
status,
|
|
216
|
+
bundleHash: '',
|
|
217
|
+
tokenAddress: predictedTokenAddress,
|
|
218
|
+
status: emptyStatus,
|
|
307
219
|
createTx: signedCreateTx,
|
|
308
|
-
buyTxs
|
|
220
|
+
buyTxs: [],
|
|
221
|
+
signedTransactions: signedTxs,
|
|
222
|
+
metadata: extractProfit ? {
|
|
223
|
+
totalBuyAmount: ethers.formatEther(totalBuyAmount),
|
|
224
|
+
profitAmount: ethers.formatEther(totalProfit),
|
|
225
|
+
profitRecipient: config.profitRecipient,
|
|
226
|
+
buyerCount: buyers.length
|
|
227
|
+
} : undefined
|
|
309
228
|
};
|
|
310
229
|
}
|
|
311
230
|
/**
|
|
@@ -379,67 +298,29 @@ export async function batchBuyWithBundleMerkle(params) {
|
|
|
379
298
|
});
|
|
380
299
|
signedTxs.push(profitTx);
|
|
381
300
|
}
|
|
382
|
-
// ✅
|
|
383
|
-
if (config.skipSubmit) {
|
|
384
|
-
nonceManager.clearTemp();
|
|
385
|
-
const emptyStatus = {
|
|
386
|
-
bundleHash: '',
|
|
387
|
-
txHashes: [],
|
|
388
|
-
results: [],
|
|
389
|
-
successCount: 0,
|
|
390
|
-
totalGasUsed: 0n,
|
|
391
|
-
targetBlock: 0
|
|
392
|
-
};
|
|
393
|
-
return {
|
|
394
|
-
bundleHash: '',
|
|
395
|
-
status: emptyStatus,
|
|
396
|
-
buyTxs: [],
|
|
397
|
-
signedTransactions: signedTxs,
|
|
398
|
-
metadata: extractProfit ? {
|
|
399
|
-
totalBuyAmount: ethers.formatEther(totalBuyAmount),
|
|
400
|
-
profitAmount: ethers.formatEther(totalProfit),
|
|
401
|
-
profitRecipient: config.profitRecipient,
|
|
402
|
-
buyerCount: buyers.length
|
|
403
|
-
} : undefined
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
const bundleResult = await merkle.sendBundle({
|
|
407
|
-
transactions: signedTxs,
|
|
408
|
-
...getBundleOptions(config, blockOffset)
|
|
409
|
-
});
|
|
410
|
-
const waitForConfirmation = config.waitForConfirmation ?? false;
|
|
411
|
-
if (!waitForConfirmation) {
|
|
412
|
-
const status = {
|
|
413
|
-
bundleHash: bundleResult.bundleHash,
|
|
414
|
-
txHashes: bundleResult.txHashes,
|
|
415
|
-
results: [],
|
|
416
|
-
successCount: 0,
|
|
417
|
-
totalGasUsed: 0n,
|
|
418
|
-
targetBlock: bundleResult.targetBlock
|
|
419
|
-
};
|
|
420
|
-
// 清理临时 nonce 缓存
|
|
421
|
-
nonceManager.clearTemp();
|
|
422
|
-
return { bundleHash: bundleResult.bundleHash, status, buyTxs: signedTxs };
|
|
423
|
-
}
|
|
424
|
-
const results = await merkle.waitForBundleConfirmation(bundleResult.txHashes, 1, config.waitTimeoutMs ?? 120000);
|
|
425
|
-
const successCount = results.filter(r => r.success).length;
|
|
426
|
-
const totalGasUsed = results.reduce((sum, r) => {
|
|
427
|
-
if (r.gasUsed) {
|
|
428
|
-
return sum + BigInt(r.gasUsed);
|
|
429
|
-
}
|
|
430
|
-
return sum;
|
|
431
|
-
}, 0n);
|
|
432
|
-
const status = {
|
|
433
|
-
bundleHash: bundleResult.bundleHash,
|
|
434
|
-
txHashes: bundleResult.txHashes,
|
|
435
|
-
results,
|
|
436
|
-
successCount,
|
|
437
|
-
totalGasUsed,
|
|
438
|
-
targetBlock: bundleResult.targetBlock
|
|
439
|
-
};
|
|
440
|
-
// 清理临时 nonce 缓存
|
|
301
|
+
// ✅ 清理临时 nonce 缓存
|
|
441
302
|
nonceManager.clearTemp();
|
|
442
|
-
|
|
303
|
+
// ✅ 直接返回签名交易(不提交到Merkle)
|
|
304
|
+
const emptyStatus = {
|
|
305
|
+
bundleHash: '',
|
|
306
|
+
txHashes: [],
|
|
307
|
+
results: [],
|
|
308
|
+
successCount: 0,
|
|
309
|
+
totalGasUsed: 0n,
|
|
310
|
+
targetBlock: 0
|
|
311
|
+
};
|
|
312
|
+
return {
|
|
313
|
+
bundleHash: '',
|
|
314
|
+
status: emptyStatus,
|
|
315
|
+
buyTxs: [],
|
|
316
|
+
signedTransactions: signedTxs,
|
|
317
|
+
metadata: extractProfit ? {
|
|
318
|
+
totalBuyAmount: ethers.formatEther(totalBuyAmount),
|
|
319
|
+
profitAmount: ethers.formatEther(totalProfit),
|
|
320
|
+
profitRecipient: config.profitRecipient,
|
|
321
|
+
buyerCount: buyers.length
|
|
322
|
+
} : undefined
|
|
323
|
+
};
|
|
443
324
|
}
|
|
444
325
|
/**
|
|
445
326
|
* four.meme: 批量卖出(Merkle 版本)
|
|
@@ -484,40 +365,11 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
484
365
|
console.log(` - 需要授权: ${needApprovalIndexes.length}`);
|
|
485
366
|
console.log(` - 已有授权: ${sellers.length - needApprovalIndexes.length}\n`);
|
|
486
367
|
// ✅ Step 2: 批量授权(如果需要)
|
|
368
|
+
// ⚠️ 注意:授权需要单独提交,SDK只返回签名交易
|
|
487
369
|
if (needApprovalIndexes.length > 0) {
|
|
488
|
-
console.log('
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const needApprovalSellers = needApprovalIndexes.map(i => sellers[i]);
|
|
492
|
-
const tokenContractsForApprove = needApprovalSellers.map((w) => new ethers.Contract(tokenAddress, ERC20_ABI, w));
|
|
493
|
-
const approveUnsigned = await Promise.all(tokenContractsForApprove.map((c) => c.approve.populateTransaction(tmAddr, ethers.MaxUint256 // 授权最大额度
|
|
494
|
-
)));
|
|
495
|
-
const approveGasLimit = getGasLimit(config, 80000);
|
|
496
|
-
const approveNonces = await Promise.all(needApprovalSellers.map((w) => nonceManager.getNextNonce(w)));
|
|
497
|
-
const signedApproves = await Promise.all(approveUnsigned.map((unsigned, i) => needApprovalSellers[i].signTransaction({
|
|
498
|
-
...unsigned,
|
|
499
|
-
from: needApprovalSellers[i].address,
|
|
500
|
-
nonce: approveNonces[i],
|
|
501
|
-
gasLimit: approveGasLimit,
|
|
502
|
-
gasPrice: gasPrice,
|
|
503
|
-
chainId: 56,
|
|
504
|
-
type: getTxType(config)
|
|
505
|
-
})));
|
|
506
|
-
approveSignedTxs.push(...signedApproves);
|
|
507
|
-
nonceManager.clearTemp();
|
|
508
|
-
// 提交授权 Bundle 并等待确认
|
|
509
|
-
const approveBundleResult = await merkle.sendBundle({
|
|
510
|
-
transactions: approveSignedTxs,
|
|
511
|
-
...getBundleOptions(config, blockOffset)
|
|
512
|
-
});
|
|
513
|
-
console.log(` Bundle Hash: ${approveBundleResult.bundleHash}`);
|
|
514
|
-
console.log('⏳ 等待授权确认...');
|
|
515
|
-
const approveResults = await merkle.waitForBundleConfirmation(approveBundleResult.txHashes, 1, config.waitTimeoutMs ?? 120000);
|
|
516
|
-
const approveSuccessCount = approveResults.filter(r => r.success).length;
|
|
517
|
-
console.log(`✅ 授权完成: ${approveSuccessCount}/${needApprovalIndexes.length}\n`);
|
|
518
|
-
if (approveSuccessCount !== needApprovalIndexes.length) {
|
|
519
|
-
throw new Error(`授权失败: 只有 ${approveSuccessCount}/${needApprovalIndexes.length} 笔授权成功`);
|
|
520
|
-
}
|
|
370
|
+
console.log('⚠️ 警告:检测到 ${needApprovalIndexes.length} 个钱包需要授权');
|
|
371
|
+
console.log(' 请先使用这些钱包的私钥调用授权方法,授权完成后再调用卖出方法');
|
|
372
|
+
throw new Error(`需要授权: ${needApprovalIndexes.length} 个钱包尚未授权。请先完成授权后再卖出。`);
|
|
521
373
|
}
|
|
522
374
|
// ✅ Step 3: 批量卖出
|
|
523
375
|
console.log('💰 提交卖出交易...');
|
|
@@ -539,41 +391,21 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
539
391
|
type: getTxType(config)
|
|
540
392
|
})));
|
|
541
393
|
signedTxs.push(...signedList);
|
|
542
|
-
|
|
543
|
-
transactions: signedTxs,
|
|
544
|
-
...getBundleOptions(config, blockOffset)
|
|
545
|
-
});
|
|
546
|
-
const waitForConfirmation = config.waitForConfirmation ?? false;
|
|
547
|
-
if (!waitForConfirmation) {
|
|
548
|
-
const status = {
|
|
549
|
-
bundleHash: bundleResult.bundleHash,
|
|
550
|
-
txHashes: bundleResult.txHashes,
|
|
551
|
-
results: [],
|
|
552
|
-
successCount: 0,
|
|
553
|
-
totalGasUsed: 0n,
|
|
554
|
-
targetBlock: bundleResult.targetBlock
|
|
555
|
-
};
|
|
556
|
-
// 清理临时 nonce 缓存
|
|
557
|
-
nonceManager.clearTemp();
|
|
558
|
-
return { bundleHash: bundleResult.bundleHash, status, sellTxs: signedTxs };
|
|
559
|
-
}
|
|
560
|
-
const results = await merkle.waitForBundleConfirmation(bundleResult.txHashes, 1, config.waitTimeoutMs ?? 120000);
|
|
561
|
-
const successCount = results.filter(r => r.success).length;
|
|
562
|
-
const totalGasUsed = results.reduce((sum, r) => {
|
|
563
|
-
if (r.gasUsed) {
|
|
564
|
-
return sum + BigInt(r.gasUsed);
|
|
565
|
-
}
|
|
566
|
-
return sum;
|
|
567
|
-
}, 0n);
|
|
568
|
-
const status = {
|
|
569
|
-
bundleHash: bundleResult.bundleHash,
|
|
570
|
-
txHashes: bundleResult.txHashes,
|
|
571
|
-
results,
|
|
572
|
-
successCount,
|
|
573
|
-
totalGasUsed,
|
|
574
|
-
targetBlock: bundleResult.targetBlock
|
|
575
|
-
};
|
|
576
|
-
// 清理临时 nonce 缓存
|
|
394
|
+
// ✅ 清理临时 nonce 缓存
|
|
577
395
|
nonceManager.clearTemp();
|
|
578
|
-
|
|
396
|
+
// ✅ 直接返回签名交易(不提交到Merkle)
|
|
397
|
+
const emptyStatus = {
|
|
398
|
+
bundleHash: '',
|
|
399
|
+
txHashes: [],
|
|
400
|
+
results: [],
|
|
401
|
+
successCount: 0,
|
|
402
|
+
totalGasUsed: 0n,
|
|
403
|
+
targetBlock: 0
|
|
404
|
+
};
|
|
405
|
+
return {
|
|
406
|
+
bundleHash: '',
|
|
407
|
+
status: emptyStatus,
|
|
408
|
+
sellTxs: [],
|
|
409
|
+
signedTransactions: signedTxs
|
|
410
|
+
};
|
|
579
411
|
}
|
|
@@ -332,32 +332,21 @@ export async function fourPancakeProxyBatchBuyMerkle(params) {
|
|
|
332
332
|
});
|
|
333
333
|
signedTxs.push(profitTx);
|
|
334
334
|
}
|
|
335
|
-
// ✅
|
|
336
|
-
if (config.skipSubmit) {
|
|
337
|
-
nonceManager.clearTemp();
|
|
338
|
-
return {
|
|
339
|
-
bundleHash: '',
|
|
340
|
-
status: {
|
|
341
|
-
bundleHash: '',
|
|
342
|
-
txHashes: [],
|
|
343
|
-
results: [],
|
|
344
|
-
successCount: 0,
|
|
345
|
-
totalGasUsed: 0n,
|
|
346
|
-
targetBlock: 0
|
|
347
|
-
},
|
|
348
|
-
buyTxs: signedTxs
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
const bundleResult = await merkle.sendBundle({
|
|
352
|
-
transactions: signedTxs,
|
|
353
|
-
...getBundleOptions(config, blockOffset)
|
|
354
|
-
});
|
|
335
|
+
// ✅ 清理临时 nonce 缓存
|
|
355
336
|
nonceManager.clearTemp();
|
|
356
|
-
|
|
337
|
+
// ✅ 直接返回签名交易(不提交到Merkle)
|
|
357
338
|
return {
|
|
358
|
-
bundleHash:
|
|
359
|
-
status
|
|
360
|
-
|
|
339
|
+
bundleHash: '',
|
|
340
|
+
status: {
|
|
341
|
+
bundleHash: '',
|
|
342
|
+
txHashes: [],
|
|
343
|
+
results: [],
|
|
344
|
+
successCount: 0,
|
|
345
|
+
totalGasUsed: 0n,
|
|
346
|
+
targetBlock: 0
|
|
347
|
+
},
|
|
348
|
+
buyTxs: [],
|
|
349
|
+
signedTransactions: signedTxs
|
|
361
350
|
};
|
|
362
351
|
}
|
|
363
352
|
/**
|
|
@@ -397,40 +386,12 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
|
|
|
397
386
|
console.log(` - 总钱包数: ${sellers.length}`);
|
|
398
387
|
console.log(` - 需要授权: ${needApprovalIndexes.length}`);
|
|
399
388
|
console.log(` - 已有授权: ${sellers.length - needApprovalIndexes.length}\n`);
|
|
400
|
-
// ✅ Step 2:
|
|
389
|
+
// ✅ Step 2: 如果需要授权,抛出错误提示
|
|
390
|
+
// ⚠️ SDK不再处理授权,需要前端先单独授权
|
|
401
391
|
if (needApprovalIndexes.length > 0) {
|
|
402
|
-
console.log('
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const needApprovalSellers = needApprovalIndexes.map(i => sellers[i]);
|
|
406
|
-
const tokenContractsForApprove = needApprovalSellers.map((w) => new Contract(tokenAddress, ERC20_ABI, w));
|
|
407
|
-
const approveUnsigned = await Promise.all(tokenContractsForApprove.map((c) => c.approve.populateTransaction(pancakeProxyAddress, ethers.MaxUint256)));
|
|
408
|
-
const approveGasLimit = getGasLimit(config, 80000);
|
|
409
|
-
const approveNonces = await Promise.all(needApprovalSellers.map((w) => nonceManager.getNextNonce(w)));
|
|
410
|
-
const signedApproves = await Promise.all(approveUnsigned.map((unsigned, i) => needApprovalSellers[i].signTransaction({
|
|
411
|
-
...unsigned,
|
|
412
|
-
from: needApprovalSellers[i].address,
|
|
413
|
-
nonce: approveNonces[i],
|
|
414
|
-
gasLimit: approveGasLimit,
|
|
415
|
-
gasPrice: gasPrice,
|
|
416
|
-
chainId: 56,
|
|
417
|
-
type: getTxType(config)
|
|
418
|
-
})));
|
|
419
|
-
approveSignedTxs.push(...signedApproves);
|
|
420
|
-
nonceManager.clearTemp();
|
|
421
|
-
// 提交授权 Bundle 并等待确认
|
|
422
|
-
const approveBundleResult = await merkle.sendBundle({
|
|
423
|
-
transactions: approveSignedTxs,
|
|
424
|
-
...getBundleOptions(config, blockOffset)
|
|
425
|
-
});
|
|
426
|
-
console.log(` Bundle Hash: ${approveBundleResult.bundleHash}`);
|
|
427
|
-
console.log('⏳ 等待授权确认...');
|
|
428
|
-
const approveResults = await merkle.waitForBundleConfirmation(approveBundleResult.txHashes, 1, config.waitTimeoutMs ?? 120000);
|
|
429
|
-
const approveSuccessCount = approveResults.filter(r => r.success).length;
|
|
430
|
-
console.log(`✅ 授权完成: ${approveSuccessCount}/${needApprovalIndexes.length}\n`);
|
|
431
|
-
if (approveSuccessCount !== needApprovalIndexes.length) {
|
|
432
|
-
throw new Error(`授权失败: 只有 ${approveSuccessCount}/${needApprovalIndexes.length} 笔授权成功`);
|
|
433
|
-
}
|
|
392
|
+
console.log('⚠️ 警告:检测到 ${needApprovalIndexes.length} 个钱包需要授权');
|
|
393
|
+
console.log(' 请先使用这些钱包完成授权后再调用卖出方法');
|
|
394
|
+
throw new Error(`需要授权: ${needApprovalIndexes.length} 个钱包尚未授权。请先完成授权后再卖出。`);
|
|
434
395
|
}
|
|
435
396
|
// ✅ Step 3: 批量卖出
|
|
436
397
|
console.log('💰 提交卖出交易...');
|
|
@@ -565,54 +526,20 @@ export async function fourPancakeProxyBatchSellMerkle(params) {
|
|
|
565
526
|
}
|
|
566
527
|
}
|
|
567
528
|
}
|
|
529
|
+
// ✅ 清理临时 nonce 缓存
|
|
568
530
|
nonceManager.clearTemp();
|
|
569
|
-
// ✅
|
|
570
|
-
if (config.skipSubmit) {
|
|
571
|
-
return {
|
|
572
|
-
bundleHash: '',
|
|
573
|
-
status: {
|
|
574
|
-
bundleHash: '',
|
|
575
|
-
txHashes: [],
|
|
576
|
-
results: [],
|
|
577
|
-
successCount: 0,
|
|
578
|
-
totalGasUsed: 0n,
|
|
579
|
-
targetBlock: 0
|
|
580
|
-
},
|
|
581
|
-
sellTxs: signedTxs
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
console.log('🚀 提交卖出 Bundle...\n');
|
|
585
|
-
let bundleResult;
|
|
586
|
-
try {
|
|
587
|
-
bundleResult = await merkle.sendBundle({
|
|
588
|
-
transactions: signedTxs,
|
|
589
|
-
...getBundleOptions(config, blockOffset)
|
|
590
|
-
});
|
|
591
|
-
console.log(` ✅ Bundle 已提交: ${bundleResult.bundleHash}`);
|
|
592
|
-
}
|
|
593
|
-
catch (error) {
|
|
594
|
-
console.error('❌ 提交 Bundle 失败:', error.message);
|
|
595
|
-
throw new Error(`卖出 Bundle 提交失败: ${error.message}`);
|
|
596
|
-
}
|
|
597
|
-
const status = await waitForBundleResult(merkle, bundleResult, config.waitForConfirmation ?? false, config.waitTimeoutMs ?? 120000);
|
|
598
|
-
if (status.successCount === sellers.length) {
|
|
599
|
-
console.log(`✅ 卖出完成: ${status.successCount}/${sellers.length} 全部成功\n`);
|
|
600
|
-
}
|
|
601
|
-
else {
|
|
602
|
-
console.log(`⚠️ 卖出完成: ${status.successCount}/${sellers.length} 成功`);
|
|
603
|
-
console.log(` 失败数量: ${sellers.length - status.successCount}\n`);
|
|
604
|
-
// 打印失败详情
|
|
605
|
-
if (status.results && status.results.length > 0) {
|
|
606
|
-
status.results.forEach((result, i) => {
|
|
607
|
-
if (!result.success && result.error) {
|
|
608
|
-
console.log(` 交易 ${i + 1} 失败: ${result.error}`);
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
}
|
|
531
|
+
// ✅ 直接返回签名交易(不提交到Merkle)
|
|
613
532
|
return {
|
|
614
|
-
bundleHash:
|
|
615
|
-
status
|
|
616
|
-
|
|
533
|
+
bundleHash: '',
|
|
534
|
+
status: {
|
|
535
|
+
bundleHash: '',
|
|
536
|
+
txHashes: [],
|
|
537
|
+
results: [],
|
|
538
|
+
successCount: 0,
|
|
539
|
+
totalGasUsed: 0n,
|
|
540
|
+
targetBlock: 0
|
|
541
|
+
},
|
|
542
|
+
sellTxs: [],
|
|
543
|
+
signedTransactions: signedTxs
|
|
617
544
|
};
|
|
618
545
|
}
|