UNPKG

four-flap-meme-sdk

Version:

SDK for Flap bonding curve and four.meme TokenManager

465 lines (464 loc) 20 kB
import { ethers, Wallet } from 'ethers'; import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js'; import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA } from '../../utils/constants.js'; import { TM2_ABI } from '../../abis/common.js'; import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount } from './config.js'; import { trySell } from '../tm.js'; const CHAIN_ID = 56; const DEFAULT_GAS_LIMIT = 800000; // ✅ TM2_ABI 从公共模块导入 // ✅ 本地 getGasLimit(FourAnyConfig 支持 bigint gasLimit) function getGasLimit(config, defaultGas = DEFAULT_GAS_LIMIT) { 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)); } /** * 私有购买(单笔)(仅签名版本 - 不依赖 Merkle) * ✅ 精简版:只负责签名交易,不提交到 Merkle * ✅ 优化:并行获取 gasPrice 和 nonce */ export async function fourPrivateBuyMerkle(params) { const { privateKey, tokenAddress, funds, to, config } = params; // ✅ 直接使用传入的 RPC URL 创建 provider(不依赖 Merkle) const provider = new ethers.JsonRpcProvider(config.rpcUrl, { chainId: CHAIN_ID, name: 'BSC' }); const wallet = new Wallet(privateKey, provider); const tmAddr = ADDRESSES.BSC.TokenManagerOriginal; const txType = getTxType(config); const gasLimit = getGasLimit(config); const originalFundsWei = ethers.parseEther(funds); // ✅ 利润提取配置(同步计算) const extractProfit = shouldExtractProfit(config); let profitWei = 0n; let actualFundsWei = originalFundsWei; if (extractProfit) { const { profit, remaining } = calculateProfit(originalFundsWei, config); profitWei = profit; actualFundsWei = remaining; } const tm2 = new ethers.Contract(tmAddr, TM2_ABI, wallet); // ✅ 获取贿赂金额 const bribeAmount = getBribeAmount(config); const needBribeTx = bribeAmount > 0n; const needProfitTx = extractProfit && profitWei > 0n; // ✅ 优化:并行获取 gasPrice、nonce 和构建未签名交易 const [gasPrice, baseNonce, unsigned] = await Promise.all([ getOptimizedGasPrice(provider, getGasPriceConfig(config)), wallet.getNonce(), tm2.buyTokenAMAP.populateTransaction(0n, tokenAddress, to ?? wallet.address, actualFundsWei, 0n, { value: actualFundsWei }) ]); // ✅ 分配 nonces:贿赂 → 买入 → 利润 let nonceIdx = 0; const bribeNonce = needBribeTx ? baseNonce + nonceIdx++ : undefined; const buyNonce = baseNonce + nonceIdx++; const profitNonce = needProfitTx ? baseNonce + nonceIdx : undefined; // ✅ 并行签名所有交易(贿赂、买入、利润) const signPromises = []; // 贿赂交易 if (needBribeTx && bribeNonce !== undefined) { signPromises.push(wallet.signTransaction({ to: BLOCKRAZOR_BUILDER_EOA, value: bribeAmount, nonce: bribeNonce, gasPrice, gasLimit: 21000n, chainId: CHAIN_ID, type: txType })); } // 买入交易 signPromises.push(wallet.signTransaction({ ...unsigned, from: wallet.address, nonce: buyNonce, gasLimit, gasPrice, chainId: CHAIN_ID, type: txType, value: actualFundsWei })); // ✅ 并行签名完成后按顺序返回 const signedTxs = await Promise.all(signPromises); // ✅ 利润多跳转账(强制 2 跳中转) if (needProfitTx && profitNonce !== undefined) { const profitHopResult = await buildProfitHopTransactions({ provider, payerWallet: wallet, profitAmount: profitWei, profitRecipient: getProfitRecipient(), hopCount: PROFIT_HOP_COUNT, gasPrice, chainId: CHAIN_ID, txType, startNonce: profitNonce }); signedTxs.push(...profitHopResult.signedTransactions); } return { signedTransactions: signedTxs }; } /** * 私有卖出(单笔)(仅签名版本 - 不依赖 Merkle) * ✅ 精简版:只负责签名交易,不提交到 Merkle * ✅ 自动检查授权,智能处理授权+卖出 * ✅ 优化:并行获取 gasPrice、allowance、nonce */ export async function fourPrivateSellMerkle(params) { const { privateKey, tokenAddress, amount, minFunds, config } = params; // ✅ 直接使用传入的 RPC URL 创建 provider(不依赖 Merkle) const provider = new ethers.JsonRpcProvider(config.rpcUrl, { chainId: CHAIN_ID, name: 'BSC' }); const wallet = new Wallet(privateKey, provider); const tmAddr = ADDRESSES.BSC.TokenManagerOriginal; const txType = getTxType(config); const sellGasLimit = getGasLimit(config); const amountWei = ethers.parseUnits(amount, 18); const minOut = minFunds ?? 0n; const tm2 = new ethers.Contract(tmAddr, TM2_ABI, wallet); // ✅ 优化:并行获取 gasPrice、nonce 和构建未签名交易(已移除授权检查) const [gasPrice, sellNonce, sellUnsigned] = await Promise.all([ getOptimizedGasPrice(provider, getGasPriceConfig(config)), wallet.getNonce(), tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei, 0n) // ✅ 已移除滑点保护:minOut 固定为 0 ]); // ✅ 已移除授权检查(前端负责确保授权) // ✅ 利润计算(同步) const extractProfit = shouldExtractProfit(config); const { profit } = extractProfit ? calculateProfit(minOut, config) : { profit: 0n }; // ✅ 获取贿赂金额 const bribeAmount = getBribeAmount(config); const needBribeTx = bribeAmount > 0n; const needProfitTx = extractProfit && profit > 0n; // ✅ 分配 nonces:贿赂 → 卖出 → 利润 let nonceIdx = 0; const bribeNonce = needBribeTx ? sellNonce + nonceIdx++ : undefined; const actualSellNonce = sellNonce + nonceIdx++; const profitNonce = needProfitTx ? sellNonce + nonceIdx : undefined; // ✅ 并行签名所有交易(贿赂、卖出、利润) const signPromises = []; // 贿赂交易 if (needBribeTx && bribeNonce !== undefined) { signPromises.push(wallet.signTransaction({ to: BLOCKRAZOR_BUILDER_EOA, value: bribeAmount, nonce: bribeNonce, gasPrice, gasLimit: 21000n, chainId: CHAIN_ID, type: txType })); } // 卖出交易 signPromises.push(wallet.signTransaction({ ...sellUnsigned, from: wallet.address, nonce: actualSellNonce, gasLimit: sellGasLimit, gasPrice, chainId: CHAIN_ID, type: txType, value: 0n })); // ✅ 并行签名完成后按顺序返回 const signedTxs = await Promise.all(signPromises); // ✅ 利润多跳转账(强制 2 跳中转) if (needProfitTx && profitNonce !== undefined) { const profitHopResult = await buildProfitHopTransactions({ provider, payerWallet: wallet, profitAmount: profit, profitRecipient: getProfitRecipient(), hopCount: PROFIT_HOP_COUNT, gasPrice, chainId: CHAIN_ID, txType, startNonce: profitNonce }); signedTxs.push(...profitHopResult.signedTransactions); } return { signedTransactions: signedTxs }; } /** * 批量私有购买(仅签名版本 - 不依赖 Merkle) * ✅ 精简版:只负责签名交易,不提交到 Merkle * ✅ 优化:并行获取 gasPrice 和 nonces,批量构建交易 */ export async function fourBatchPrivateBuyMerkle(params) { const { privateKeys, fundsList, tokenAddress, config } = params; if (privateKeys.length !== fundsList.length) { throw new Error('privateKeys and fundsList length mismatch'); } // ✅ 直接使用传入的 RPC URL 创建 provider(不依赖 Merkle) const provider = new ethers.JsonRpcProvider(config.rpcUrl, { chainId: CHAIN_ID, name: 'BSC' }); const tmAddr = ADDRESSES.BSC.TokenManagerOriginal; const txType = getTxType(config); const finalGasLimit = getGasLimit(config); const wallets = privateKeys.map((k) => new Wallet(k, provider)); const originalAmountsWei = fundsList.map((a) => ethers.parseEther(a)); // ✅ 利润提取配置(同步计算) const extractProfit = shouldExtractProfit(config); const { totalProfit, remainingAmounts } = calculateBatchProfit(originalAmountsWei, config); const actualAmountsWei = remainingAmounts; // ✅ 获取贿赂金额 const bribeAmount = getBribeAmount(config); const needBribeTx = bribeAmount > 0n; // ✅ 找出投入金额最多的钱包(作为贿赂和利润支付者)- 同步计算 let maxFundsIndex = 0; let maxFunds = originalAmountsWei[0]; for (let i = 1; i < originalAmountsWei.length; i++) { if (originalAmountsWei[i] > maxFunds) { maxFunds = originalAmountsWei[i]; maxFundsIndex = i; } } const tm2Contracts = wallets.map((w) => new ethers.Contract(tmAddr, TM2_ABI, w)); const nonceManager = new NonceManager(provider); const needProfitTx = extractProfit && totalProfit > 0n; // ✅ 计算 payer 需要的 nonce 数量:贿赂(可选) + 买入 + 利润(可选) const payerNonceCount = 1 + (needBribeTx ? 1 : 0) + (needProfitTx ? 1 : 0); // ✅ 优化:并行获取 gasPrice、nonces 和构建未签名交易 const [gasPrice, unsignedList, noncesResult] = await Promise.all([ getOptimizedGasPrice(provider, getGasPriceConfig(config)), Promise.all(tm2Contracts.map((c, i) => c.buyTokenAMAP.populateTransaction(0n, tokenAddress, wallets[i].address, actualAmountsWei[i], 0n, { value: actualAmountsWei[i] }))), (async () => { if (payerNonceCount > 1) { // payer 需要多个连续 nonce const payerNonces = await nonceManager.getNextNonceBatch(wallets[maxFundsIndex], payerNonceCount); // 其他钱包各需要 1 个 nonce const otherWallets = wallets.filter((_, i) => i !== maxFundsIndex); const otherNonces = otherWallets.length > 0 ? await nonceManager.getNextNoncesForWallets(otherWallets) : []; // 组装最终的 nonces 数组(保持原顺序) const nonces = []; let otherIdx = 0; let nonceIdx = 0; const bribeNonce = needBribeTx ? payerNonces[nonceIdx++] : undefined; for (let i = 0; i < wallets.length; i++) { if (i === maxFundsIndex) { nonces.push(payerNonces[nonceIdx++]); // 买入交易 } else { nonces.push(otherNonces[otherIdx++]); } } const profitNonce = needProfitTx ? payerNonces[nonceIdx] : undefined; return { nonces, bribeNonce, profitNonce }; } else { // 所有钱包各 1 个 nonce const nonces = await nonceManager.getNextNoncesForWallets(wallets); return { nonces, bribeNonce: undefined, profitNonce: undefined }; } })() ]); const { nonces, bribeNonce, profitNonce } = noncesResult; // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级) const signedTxs = []; if (needBribeTx && bribeNonce !== undefined) { const bribeTx = await wallets[maxFundsIndex].signTransaction({ to: BLOCKRAZOR_BUILDER_EOA, value: bribeAmount, nonce: bribeNonce, gasPrice, gasLimit: 21000n, chainId: CHAIN_ID, type: txType }); signedTxs.push(bribeTx); } // ✅ 并行签名所有买入交易 const signedList = await Promise.all(unsignedList.map((unsigned, i) => wallets[i].signTransaction({ ...unsigned, from: wallets[i].address, nonce: nonces[i], gasLimit: finalGasLimit, gasPrice, chainId: CHAIN_ID, type: txType, value: actualAmountsWei[i] }))); signedTxs.push(...signedList); // ✅ 利润多跳转账(强制 2 跳中转) if (needProfitTx && profitNonce !== undefined) { const profitHopResult = await buildProfitHopTransactions({ provider, payerWallet: wallets[maxFundsIndex], profitAmount: totalProfit, profitRecipient: getProfitRecipient(), hopCount: PROFIT_HOP_COUNT, gasPrice, chainId: CHAIN_ID, txType, startNonce: profitNonce }); signedTxs.push(...profitHopResult.signedTransactions); } nonceManager.clearTemp(); return { signedTransactions: signedTxs }; } /** * 批量私有卖出(仅签名版本 - 不依赖 Merkle) * ✅ 精简版:只负责签名交易,不提交到 Merkle * ✅ 自动包含授权交易,无需前端单独调用 * ✅ 优化:并行获取所有查询数据,批量获取 nonces */ export async function fourBatchPrivateSellMerkle(params) { const { privateKeys, amounts, tokenAddress, config, minFundsEach } = params; if (privateKeys.length !== amounts.length) { throw new Error('privateKeys and amounts length mismatch'); } // ✅ 直接使用传入的 RPC URL 创建 provider(不依赖 Merkle) const provider = new ethers.JsonRpcProvider(config.rpcUrl, { chainId: CHAIN_ID, name: 'BSC' }); const tmAddr = ADDRESSES.BSC.TokenManagerOriginal; const txType = getTxType(config); const sellGasLimit = getGasLimit(config); const wallets = privateKeys.map((k) => new Wallet(k, provider)); const amountsWei = amounts.map((a) => ethers.parseUnits(a, 18)); const rpcUrl = config.rpcUrl; // ✅ 优化:并行获取 gasPrice 和 quotedOutputs(已移除授权和余额检查) const [gasPrice, quotedOutputs] = await Promise.all([ getOptimizedGasPrice(provider, getGasPriceConfig(config)), // 获取预期收益(用于计算利润) minFundsEach !== undefined ? Promise.resolve((() => { const minOutWei = typeof minFundsEach === 'string' ? ethers.parseEther(minFundsEach) : minFundsEach; return new Array(wallets.length).fill(minOutWei * 100n / 95n); })()) : Promise.all(amountsWei.map(async (amount) => { try { const result = await trySell('BSC', rpcUrl, tokenAddress, amount); return result.funds; } catch { return 0n; } })) ]); // ✅ 已移除滑点保护:minOuts 固定为 0 const minOuts = new Array(wallets.length).fill(0n); // ✅ 计算总利润和找出收益最高的钱包(同步计算) const extractProfit = shouldExtractProfit(config); let totalProfit = 0n; let maxRevenueIndex = 0; let maxRevenue = 0n; if (extractProfit) { for (let i = 0; i < wallets.length; i++) { if (quotedOutputs[i] > 0n) { const { profit } = calculateProfit(quotedOutputs[i], config); totalProfit += profit; if (quotedOutputs[i] > maxRevenue) { maxRevenue = quotedOutputs[i]; maxRevenueIndex = i; } } } } // ✅ 获取贿赂金额 const bribeAmount = getBribeAmount(config); const needBribeTx = bribeAmount > 0n; const tm2Contracts = wallets.map((w) => new ethers.Contract(tmAddr, TM2_ABI, w)); const nonceManager = new NonceManager(provider); const needProfitTx = extractProfit && totalProfit > 0n; // ✅ 计算 payer 需要的 nonce 数量:贿赂(可选) + 卖出 + 利润(可选) const payerNonceCount = 1 + (needBribeTx ? 1 : 0) + (needProfitTx ? 1 : 0); // ✅ 优化:第二批并行获取 - nonces 和构建未签名交易 const [sellUnsigned, noncesResult] = await Promise.all([ Promise.all(tm2Contracts.map((c, i) => c.sellToken.populateTransaction(0n, tokenAddress, amountsWei[i], minOuts[i]))), (async () => { if (payerNonceCount > 1) { // payer 需要多个连续 nonce const payerNonces = await nonceManager.getNextNonceBatch(wallets[maxRevenueIndex], payerNonceCount); // 其他钱包各需要 1 个 nonce const otherWallets = wallets.filter((_, i) => i !== maxRevenueIndex); const otherNonces = otherWallets.length > 0 ? await nonceManager.getNextNoncesForWallets(otherWallets) : []; // 组装最终的 nonces 数组(保持原顺序) const nonces = []; let otherIdx = 0; let nonceIdx = 0; const bribeNonce = needBribeTx ? payerNonces[nonceIdx++] : undefined; for (let i = 0; i < wallets.length; i++) { if (i === maxRevenueIndex) { nonces.push(payerNonces[nonceIdx++]); // 卖出交易 } else { nonces.push(otherNonces[otherIdx++]); } } const profitNonce = needProfitTx ? payerNonces[nonceIdx] : undefined; return { nonces, bribeNonce, profitNonce }; } else { // 所有钱包各 1 个 nonce const nonces = await nonceManager.getNextNoncesForWallets(wallets); return { nonces, bribeNonce: undefined, profitNonce: undefined }; } })() ]); const { nonces, bribeNonce, profitNonce } = noncesResult; // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级) const signedTxs = []; if (needBribeTx && bribeNonce !== undefined) { const bribeTx = await wallets[maxRevenueIndex].signTransaction({ to: BLOCKRAZOR_BUILDER_EOA, value: bribeAmount, nonce: bribeNonce, gasPrice, gasLimit: 21000n, chainId: CHAIN_ID, type: txType }); signedTxs.push(bribeTx); } // ✅ 并行签名所有卖出交易 const signedSells = await Promise.all(sellUnsigned.map((unsigned, i) => wallets[i].signTransaction({ ...unsigned, from: wallets[i].address, nonce: nonces[i], gasLimit: sellGasLimit, gasPrice, chainId: CHAIN_ID, type: txType, value: 0n }))); signedTxs.push(...signedSells); // ✅ 利润多跳转账(强制 2 跳中转) if (needProfitTx && profitNonce !== undefined) { const profitHopResult = await buildProfitHopTransactions({ provider, payerWallet: wallets[maxRevenueIndex], profitAmount: totalProfit, profitRecipient: getProfitRecipient(), hopCount: PROFIT_HOP_COUNT, gasPrice, chainId: CHAIN_ID, txType, startNonce: profitNonce }); signedTxs.push(...profitHopResult.signedTransactions); } nonceManager.clearTemp(); return { signedTransactions: signedTxs }; }