four-flap-meme-sdk 1.9.41 → 1.9.42
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/dex/direct-router.js +43 -10
- package/package.json +1 -1
|
@@ -535,16 +535,19 @@ export async function directV2BatchBuy(params) {
|
|
|
535
535
|
const flowAmounts = buyAmounts.map(amount => ethers.parseUnits(amount, quoteTokenDecimals));
|
|
536
536
|
const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
|
|
537
537
|
const baseProfitWei = calculateProfitAmount(totalFlowWei);
|
|
538
|
-
// ✅ 方案 B:并行获取 nonces、gasPrice
|
|
539
|
-
const
|
|
538
|
+
// ✅ 方案 B:并行获取 nonces、gasPrice、ERC20 报价 以及(非原生代币时)授权额度
|
|
539
|
+
const quoteTokenContract = (!useNative && quoteToken) ? new Contract(quoteToken, ERC20_ABI, provider) : null;
|
|
540
|
+
const [nonces, gasPrice, nativeProfitWei, buyAllowances] = await Promise.all([
|
|
540
541
|
startNonces && startNonces.length === wallets.length
|
|
541
542
|
? Promise.resolve(startNonces)
|
|
542
543
|
: new NonceManager(provider).getNextNoncesForWallets(wallets),
|
|
543
544
|
getGasPrice(provider, config),
|
|
544
|
-
// ERC20 报价提前并行获取(V2 买入用 V2 报价)
|
|
545
545
|
(!useNative && baseProfitWei > 0n && quoteToken)
|
|
546
546
|
? getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v2')
|
|
547
|
-
: Promise.resolve(baseProfitWei)
|
|
547
|
+
: Promise.resolve(baseProfitWei),
|
|
548
|
+
quoteTokenContract
|
|
549
|
+
? Promise.all(wallets.map(w => quoteTokenContract.allowance(w.address, routerAddress).catch(() => 0n)))
|
|
550
|
+
: Promise.resolve(wallets.map(() => ethers.MaxUint256)),
|
|
548
551
|
]);
|
|
549
552
|
// 确定最终利润金额(ENI 链额外补偿利润转账的 gas 成本)
|
|
550
553
|
let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
|
|
@@ -554,6 +557,29 @@ export async function directV2BatchBuy(params) {
|
|
|
554
557
|
const gasLimit = getGasLimit(config, 250000);
|
|
555
558
|
const txType = config.txType ?? 0;
|
|
556
559
|
const deadline = getDeadline();
|
|
560
|
+
// ✅ 自动授权:ERC20 报价代币买入时,检查钱包对 Router 的授权额度,不足则插入 approve
|
|
561
|
+
const buyApproveTxs = [];
|
|
562
|
+
if (!useNative && quoteTokenContract) {
|
|
563
|
+
for (let i = 0; i < wallets.length; i++) {
|
|
564
|
+
if (flowAmounts[i] <= 0n)
|
|
565
|
+
continue;
|
|
566
|
+
if (buyAllowances[i] < flowAmounts[i]) {
|
|
567
|
+
console.log(`🔓 [V2 Buy] 钱包 ${i} 报价代币授权不足 (${buyAllowances[i]} < ${flowAmounts[i]}), 自动 approve`);
|
|
568
|
+
const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]);
|
|
569
|
+
const approveTx = await wallets[i].signTransaction({
|
|
570
|
+
to: quoteToken,
|
|
571
|
+
data: approveData,
|
|
572
|
+
value: 0n,
|
|
573
|
+
nonce: nonces[i],
|
|
574
|
+
gasLimit: 60000n,
|
|
575
|
+
...buildGasFields(txType, gasPrice),
|
|
576
|
+
chainId,
|
|
577
|
+
});
|
|
578
|
+
buyApproveTxs.push({ walletIndex: i, tx: approveTx });
|
|
579
|
+
nonces[i]++;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
557
583
|
// 构建路径
|
|
558
584
|
const inputToken = useNative ? wrappedNative : quoteToken;
|
|
559
585
|
const path = [inputToken, tokenAddress];
|
|
@@ -613,10 +639,11 @@ export async function directV2BatchBuy(params) {
|
|
|
613
639
|
});
|
|
614
640
|
// ✅ 并行执行所有签名
|
|
615
641
|
const signedResults = await Promise.all(signPromises);
|
|
616
|
-
//
|
|
642
|
+
// 按类型分组并按顺序组装:approve → 贿赂 → 交易
|
|
643
|
+
const approveSignedTxs = buyApproveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map(a => a.tx);
|
|
617
644
|
const bribeTxs = signedResults.filter(r => r.type === 'bribe').map(r => r.tx);
|
|
618
645
|
const swapTxs = signedResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
|
|
619
|
-
const signedTxs = [...bribeTxs, ...swapTxs];
|
|
646
|
+
const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs];
|
|
620
647
|
// ✅ 检查是否使用分布式利润模式
|
|
621
648
|
const profitMode = config.profitMode || 'single';
|
|
622
649
|
const skipProfit = config.skipProfit === true;
|
|
@@ -704,20 +731,26 @@ export async function directV2BatchSell(params) {
|
|
|
704
731
|
const gasLimit = getGasLimit(config, 300000);
|
|
705
732
|
const txType = config.txType ?? 0;
|
|
706
733
|
const deadline = getDeadline();
|
|
707
|
-
// 计算卖出数量(同步操作,无 RPC
|
|
734
|
+
// 计算卖出数量(同步操作,无 RPC),并安全兜底不超过链上实际余额
|
|
708
735
|
const sellAmountsWei = [];
|
|
709
736
|
for (let i = 0; i < wallets.length; i++) {
|
|
737
|
+
let amount;
|
|
710
738
|
if (sellAmounts && sellAmounts[i]) {
|
|
711
739
|
const truncatedAmount = truncateDecimals(sellAmounts[i], tokenDecimals);
|
|
712
|
-
|
|
740
|
+
amount = ethers.parseUnits(truncatedAmount, tokenDecimals);
|
|
713
741
|
}
|
|
714
742
|
else if (sellPercentages && sellPercentages[i]) {
|
|
715
743
|
const pct = Math.min(100, Math.max(0, sellPercentages[i]));
|
|
716
|
-
|
|
744
|
+
amount = (balances[i] * BigInt(pct)) / 100n;
|
|
717
745
|
}
|
|
718
746
|
else {
|
|
719
|
-
|
|
747
|
+
amount = balances[i];
|
|
748
|
+
}
|
|
749
|
+
if (amount > balances[i]) {
|
|
750
|
+
console.log(`⚠️ [V2 Sell] 钱包 ${i} 卖出量(${amount}) > 链上余额(${balances[i]}),已自动调整为实际余额`);
|
|
751
|
+
amount = balances[i];
|
|
720
752
|
}
|
|
753
|
+
sellAmountsWei.push(amount);
|
|
721
754
|
}
|
|
722
755
|
const totalSellAmount = sellAmountsWei.reduce((sum, o) => sum + o, 0n);
|
|
723
756
|
// ✅ 自动授权:检查每个钱包对 Router 的授权额度,不足则插入 approve 交易
|