UNPKG

four-flap-meme-sdk

Version:

SDK for Flap bonding curve and four.meme TokenManager

210 lines (209 loc) 8.9 kB
/** * Four.meme 内盘捆绑换手(Merkle Bundle)- 先买后卖 * * 功能:钱包B先买入代币 → 钱包A卖出相同数量 → 原子执行 */ import { ethers, Contract, Wallet } from 'ethers'; import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js'; import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from '../../utils/constants.js'; import { TM_ABI, HELPER3_ABI, TM_ADDRESS } from './swap-internal.js'; import { getTxType, getGasPriceConfig, getProfitRecipient, getBribeAmount } from './config.js'; import { trySell } from '../tm.js'; // ✅ 本地 getGasLimit(FourAnyConfig 支持 bigint gasLimit) function getGasLimit(config, defaultGas = 800000) { if (config.gasLimit !== undefined) { return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit); } const multiplier = config.gasLimitMultiplier ?? 1.0; return BigInt(Math.ceil(defaultGas * multiplier)); } export async function fourBundleBuyFirstMerkle(params) { const { buyerPrivateKey, buyerFunds, buyerFundsPercentage, sellerPrivateKey, tokenAddress, config } = params; const chainIdNum = config.chainId ?? 56; const provider = new ethers.JsonRpcProvider(config.rpcUrl, { chainId: chainIdNum, name: 'BSC' }); const buyer = new Wallet(buyerPrivateKey, provider); const seller = new Wallet(sellerPrivateKey, provider); const sameAddress = buyer.address.toLowerCase() === seller.address.toLowerCase(); const finalGasLimit = getGasLimit(config); const txType = getTxType(config); const nonceManager = new NonceManager(provider); const reserveGas = ethers.parseEther((config.reserveGasBNB || 0.0005).toString()); // ✅ 优化:第一批并行 - buyerBalance、gasPrice const [buyerBalance, gasPrice] = await Promise.all([ provider.getBalance(buyer.address), getOptimizedGasPrice(provider, getGasPriceConfig(config)) ]); // 计算买方投入资金 let buyerFundsWei; if (buyerFunds !== undefined) { buyerFundsWei = ethers.parseEther(String(buyerFunds)); } else if (buyerFundsPercentage !== undefined) { const pct = Math.max(0, Math.min(100, buyerFundsPercentage)); const spendable = buyerBalance > reserveGas ? buyerBalance - reserveGas : 0n; buyerFundsWei = (spendable * BigInt(Math.round(pct * 100))) / 10000n; } else { throw new Error('必须提供 buyerFunds 或 buyerFundsPercentage'); } if (buyerFundsWei <= 0n) { throw new Error('buyerFunds 需要大于 0'); } // ✅ 优化:第二批并行 - buyQuote、sellerTokenBal、decimals const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider); const erc20 = new Contract(tokenAddress, [ 'function balanceOf(address) view returns (uint256)', 'function decimals() view returns (uint8)' ], provider); const [buyQuote, sellerTokenBal, decimals] = await Promise.all([ helper3.tryBuy(tokenAddress, 0n, buyerFundsWei), erc20.balanceOf(seller.address), erc20.decimals() ]); const estimatedTokenAmount = buyQuote.estimatedAmount ?? buyQuote[2]; if (!estimatedTokenAmount || estimatedTokenAmount <= 0n) { throw new Error('报价失败:无法估算可买入的代币数量'); } const sellAmountWei = estimatedTokenAmount; // 卖方余额检查 if (!sameAddress && sellerTokenBal < sellAmountWei) { throw new Error(`卖方代币余额不足: 需要 ${ethers.formatUnits(sellAmountWei, decimals)},实际 ${ethers.formatUnits(sellerTokenBal, decimals)}`); } // ✅ 优化:第三批并行 - trySell、构建交易、获取 nonces const tmBuyer = new Contract(TM_ADDRESS, TM_ABI, buyer); const tmSeller = new Contract(TM_ADDRESS, TM_ABI, seller); // 预先规划 nonces const extractProfit = true; const profitRateBps = PROFIT_CONFIG.RATE_BPS_SWAP; // 万分之六 // ✅ 获取贿赂金额 const bribeAmount = getBribeAmount(config); const needBribeTx = bribeAmount > 0n; // 计算需要的 nonce 数量 let buyerNonceCount = 1; // 买入交易 let sellerNonceCount = 1; // 卖出交易 if (needBribeTx) sellerNonceCount++; // 贿赂交易(由卖方发送) if (extractProfit) sellerNonceCount++; // 利润交易 // ✅ 优化:使用批量 nonce 获取(单次网络往返) const getNoncesPromise = sameAddress ? nonceManager.getNextNonceBatch(seller, buyerNonceCount + sellerNonceCount) .then(nonces => ({ buyerNonces: [], sellerNonces: nonces })) : nonceManager.getNextNoncesForWallets([buyer, seller]) .then(initialNonces => ({ // buyer 只需要 1 个 nonce buyerNonces: [initialNonces[0]], // seller 需要 sellerNonceCount 个连续 nonce,从初始 nonce 开始 sellerNonces: Array.from({ length: sellerNonceCount }, (_, i) => initialNonces[1] + i) })); const [sellResult, buyUnsigned, sellUnsigned, noncesResult] = await Promise.all([ trySell('BSC', config.rpcUrl, tokenAddress, sellAmountWei), tmBuyer.buyTokenAMAP.populateTransaction(0n, tokenAddress, buyer.address, buyerFundsWei, 0n, { value: buyerFundsWei }), tmSeller.sellToken.populateTransaction(0n, tokenAddress, sellAmountWei, 0n), getNoncesPromise ]); const { buyerNonces, sellerNonces } = noncesResult; const estimatedSellFunds = sellResult.funds; const profitAmount = extractProfit ? (estimatedSellFunds * BigInt(profitRateBps)) / 10000n : 0n; // 分配 nonces let buyerNonce; let sellerNonce; let bribeNonce; let profitNonce; if (sameAddress) { let idx = 0; if (needBribeTx) bribeNonce = sellerNonces[idx++]; buyerNonce = sellerNonces[idx++]; sellerNonce = sellerNonces[idx++]; if (extractProfit) profitNonce = sellerNonces[idx]; } else { buyerNonce = buyerNonces[0]; let idx = 0; if (needBribeTx) bribeNonce = sellerNonces[idx++]; sellerNonce = sellerNonces[idx++]; if (extractProfit) profitNonce = sellerNonces[idx]; } // ✅ 并行签名所有交易 const signPromises = []; // ✅ 贿赂交易放在首位 let bribeTx = null; if (needBribeTx && bribeNonce !== undefined) { signPromises.push(seller.signTransaction({ to: BLOCKRAZOR_BUILDER_EOA, value: bribeAmount, nonce: bribeNonce, gasPrice, gasLimit: 21000n, chainId: chainIdNum, type: txType })); } // 买入和卖出交易 signPromises.push(buyer.signTransaction({ ...buyUnsigned, from: buyer.address, nonce: buyerNonce, gasLimit: finalGasLimit, gasPrice, chainId: chainIdNum, type: txType, value: buyerFundsWei }), // ✅ 卖出交易 value 必须为 0,不能发送原生代币 seller.signTransaction({ ...sellUnsigned, from: seller.address, nonce: sellerNonce, gasLimit: finalGasLimit, gasPrice, chainId: chainIdNum, type: txType, value: 0n // ✅ 卖出交易不发送原生代币 })); const signedTxs = await Promise.all(signPromises); // 解析签名结果 let idx = 0; if (needBribeTx) bribeTx = signedTxs[idx++]; const signedBuy = signedTxs[idx++]; const signedSell = signedTxs[idx++]; nonceManager.clearTemp(); // ✅ 组装交易列表:贿赂 → 买入 → 卖出 const allTransactions = []; if (bribeTx) allTransactions.push(bribeTx); allTransactions.push(signedBuy, signedSell); // ✅ 利润多跳转账(强制 2 跳中转) if (extractProfit && profitAmount > 0n && profitNonce !== undefined) { const profitHopResult = await buildProfitHopTransactions({ provider, payerWallet: seller, profitAmount: profitAmount, profitRecipient: getProfitRecipient(), hopCount: PROFIT_HOP_COUNT, gasPrice, chainId: chainIdNum, txType, startNonce: profitNonce }); allTransactions.push(...profitHopResult.signedTransactions); } return { signedTransactions: allTransactions, metadata: { buyerAddress: buyer.address, sellerAddress: seller.address, buyAmount: ethers.formatEther(buyerFundsWei), sellAmount: ethers.formatUnits(sellAmountWei, decimals), profitAmount: extractProfit ? ethers.formatEther(profitAmount) : undefined } }; }