four-flap-meme-sdk 1.3.12 → 1.3.13
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.
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { ethers, Wallet } from 'ethers';
|
|
1
|
+
import { ethers, Wallet, Contract, Interface } from 'ethers';
|
|
2
2
|
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
3
3
|
import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
|
|
4
4
|
import { CHAIN_ID_MAP, PORTAL_ABI, getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
|
|
5
5
|
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
6
|
+
const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
|
|
7
|
+
const MULTICALL3_ABI = [
|
|
8
|
+
'function aggregate3(tuple(address target, bool allowFailure, bytes callData)[] calls) external payable returns (tuple(bool success, bytes returnData)[])'
|
|
9
|
+
];
|
|
6
10
|
/**
|
|
7
11
|
* 获取 Gas Limit
|
|
8
12
|
* 优先使用 config.gasLimit,否则使用默认值 * multiplier
|
|
@@ -233,11 +237,11 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
233
237
|
const portals = wallets.map(w => new ethers.Contract(portalAddr, PORTAL_ABI, w));
|
|
234
238
|
// ✅ 确定 outputToken:如果传入了 quoteToken 且非零地址,则使用它;否则使用零地址(原生代币)
|
|
235
239
|
const outputToken = quoteToken && quoteToken !== ZERO_ADDRESS ? quoteToken : ZERO_ADDRESS;
|
|
236
|
-
// ✅ 优化:并行执行 gasPrice、quoteSellOutputs
|
|
240
|
+
// ✅ 优化:并行执行 gasPrice、quoteSellOutputs(Multicall3)和 nonces(批量获取)
|
|
237
241
|
const [gasPrice, quotedOutputs, nonces] = await Promise.all([
|
|
238
242
|
resolveGasPrice(provider, config),
|
|
239
243
|
quoteSellOutputsWithQuote(readOnlyPortal, tokenAddress, amountsWei, outputToken),
|
|
240
|
-
|
|
244
|
+
nonceManager.getNextNoncesForWallets(wallets) // ✅ 批量获取 nonce
|
|
241
245
|
]);
|
|
242
246
|
const minOuts = resolveMinOutputs(minOutputAmounts, wallets.length, quotedOutputs);
|
|
243
247
|
// ✅ 优化:构建未签名交易(这里是本地操作,但仍然并行执行以提高效率)
|
|
@@ -399,21 +403,70 @@ function buildProfitMetadata(extractProfit, totalBuyAmount, totalProfit, buyerCo
|
|
|
399
403
|
};
|
|
400
404
|
}
|
|
401
405
|
/**
|
|
402
|
-
* ✅
|
|
406
|
+
* ✅ 使用 Multicall3 批量获取卖出报价(单次 RPC)
|
|
407
|
+
* 比 Promise.all 更高效,N 个报价只需 1 次网络请求
|
|
403
408
|
*/
|
|
404
409
|
async function quoteSellOutputsWithQuote(portal, tokenAddress, amountsWei, outputToken) {
|
|
405
|
-
|
|
410
|
+
if (amountsWei.length === 0)
|
|
411
|
+
return [];
|
|
412
|
+
// 如果只有 1 个,直接调用(避免 multicall 开销)
|
|
413
|
+
if (amountsWei.length === 1) {
|
|
406
414
|
try {
|
|
407
|
-
|
|
415
|
+
const result = await portal.quoteExactInput.staticCall({
|
|
408
416
|
inputToken: tokenAddress,
|
|
409
|
-
outputToken,
|
|
410
|
-
inputAmount:
|
|
417
|
+
outputToken,
|
|
418
|
+
inputAmount: amountsWei[0]
|
|
411
419
|
});
|
|
420
|
+
return [result];
|
|
412
421
|
}
|
|
413
422
|
catch {
|
|
414
|
-
return 0n;
|
|
423
|
+
return [0n];
|
|
415
424
|
}
|
|
425
|
+
}
|
|
426
|
+
const provider = portal.runner;
|
|
427
|
+
const portalAddress = await portal.getAddress();
|
|
428
|
+
const portalIface = new Interface(PORTAL_ABI);
|
|
429
|
+
const multicall = new Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
|
|
430
|
+
// 构建批量调用
|
|
431
|
+
const calls = amountsWei.map(amount => ({
|
|
432
|
+
target: portalAddress,
|
|
433
|
+
allowFailure: true, // 允许单个失败
|
|
434
|
+
callData: portalIface.encodeFunctionData('quoteExactInput', [{
|
|
435
|
+
inputToken: tokenAddress,
|
|
436
|
+
outputToken,
|
|
437
|
+
inputAmount: amount
|
|
438
|
+
}])
|
|
416
439
|
}));
|
|
440
|
+
try {
|
|
441
|
+
const results = await multicall.aggregate3.staticCall(calls);
|
|
442
|
+
return results.map((r) => {
|
|
443
|
+
if (r.success && r.returnData && r.returnData !== '0x') {
|
|
444
|
+
try {
|
|
445
|
+
const decoded = portalIface.decodeFunctionResult('quoteExactInput', r.returnData);
|
|
446
|
+
return BigInt(decoded[0]);
|
|
447
|
+
}
|
|
448
|
+
catch {
|
|
449
|
+
return 0n;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return 0n;
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
// Multicall 失败,回退到并行调用
|
|
457
|
+
return await Promise.all(amountsWei.map(async (amount) => {
|
|
458
|
+
try {
|
|
459
|
+
return await portal.quoteExactInput.staticCall({
|
|
460
|
+
inputToken: tokenAddress,
|
|
461
|
+
outputToken,
|
|
462
|
+
inputAmount: amount
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
return 0n;
|
|
467
|
+
}
|
|
468
|
+
}));
|
|
469
|
+
}
|
|
417
470
|
}
|
|
418
471
|
function resolveMinOutputs(provided, walletCount, quotedOutputs) {
|
|
419
472
|
if (provided && provided.length === walletCount) {
|