four-flap-meme-sdk
Version:
SDK for Flap bonding curve and four.meme TokenManager
169 lines (168 loc) • 6.67 kB
JavaScript
/**
* 私募转账签名工具
*
* ✅ 优化:能批量的批量,能并行的并行
* - 贿赂交易:向 BlockRazor Builder EOA 转账 BNB 提高优先级
* - 利润提取:千分之三(30 bps)
*/
import { ethers, Wallet, JsonRpcProvider } from 'ethers';
import { PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA } from './constants.js';
import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT } from './bundle-helpers.js';
// ============================================================================
// 核心功能
// ============================================================================
/**
* 生成私募转账签名交易(带贿赂和利润提取)
*
* ✅ 优化:
* 1. 批量获取 nonce(单次 RPC 请求)
* 2. 并行签名所有交易(贿赂 + 转账 + 利润)
* 3. 批量创建钱包实例
*
* 交易顺序:
* 1. 贿赂交易(第一个发送者 → BlockRazor)
* 2. 转账交易(各发送者 → 合约)
* 3. 利润交易(第一个发送者 → 利润地址)
*
* @param params 批量转账参数
* @returns 签名交易结果
*/
export async function batchPrivateSaleMerkle(params) {
const { transfers, config } = params;
if (transfers.length === 0) {
throw new Error('转账列表不能为空');
}
// ✅ 配置参数(提前计算,避免重复)
const chainId = config.chainId || 56;
const gasLimit = BigInt(config.gasLimit || 21000);
const gasPrice = ethers.parseUnits(String(config.gasPriceGwei || 0.1), 'gwei');
const bribeAmount = ethers.parseEther(String(config.bribeAmount || 0.000001));
const extractProfit = config.extractProfit !== false;
const profitBps = config.profitBps ?? PROFIT_CONFIG.RATE_BPS;
// 创建 Provider
const provider = new JsonRpcProvider(config.rpcUrl);
const nonceManager = new NonceManager(provider);
// ✅ 批量创建钱包实例(使用 Map 去重)
const walletMap = new Map();
const transferWallets = [];
for (const transfer of transfers) {
const key = new Wallet(transfer.senderPrivateKey).address.toLowerCase();
if (!walletMap.has(key)) {
const wallet = new Wallet(transfer.senderPrivateKey, provider);
walletMap.set(key, wallet);
}
transferWallets.push(walletMap.get(key));
}
// 第一个发送者(负责贿赂和利润交易)
const firstWallet = transferWallets[0];
const firstWalletKey = firstWallet.address.toLowerCase();
// ✅ 批量计算总金额(使用 reduce)
const totalAmountWei = transfers.reduce((sum, t) => sum + ethers.parseEther(String(t.amount)), 0n);
const profitWei = extractProfit ? (totalAmountWei * BigInt(profitBps)) / 10000n : 0n;
const hasProfit = extractProfit && profitWei > 0n;
// ✅ 批量获取所有 nonce(单次 RPC 请求)
const uniqueWallets = Array.from(walletMap.values());
const noncesArray = await nonceManager.getNextNoncesForWallets(uniqueWallets);
// 构建 nonce 映射
const nonceMap = new Map();
uniqueWallets.forEach((wallet, i) => {
nonceMap.set(wallet.address.toLowerCase(), noncesArray[i]);
});
// ✅ 预计算每个钱包的 nonce 分配
// 第一个钱包:baseNonce(贿赂) → baseNonce+1...+N(转账) → 最后(利润)
const firstWalletBaseNonce = nonceMap.get(firstWalletKey);
// 统计第一个钱包的转账数量
let firstWalletTransferCount = 0;
for (let i = 0; i < transfers.length; i++) {
if (transferWallets[i].address.toLowerCase() === firstWalletKey) {
firstWalletTransferCount++;
}
}
// ✅ 为每个转账预分配 nonce
const transferNonces = [];
const currentNonces = new Map();
// 初始化 nonce(第一个钱包跳过贿赂交易的 nonce)
for (const [key, nonce] of nonceMap) {
currentNonces.set(key, key === firstWalletKey ? nonce + 1 : nonce);
}
// 为每个转账分配 nonce
for (let i = 0; i < transfers.length; i++) {
const walletKey = transferWallets[i].address.toLowerCase();
const nonce = currentNonces.get(walletKey);
transferNonces.push(nonce);
currentNonces.set(walletKey, nonce + 1);
}
// 利润交易的 nonce
const profitNonce = hasProfit ? currentNonces.get(firstWalletKey) : 0;
// ✅ 签名交易数组
const signedTransactions = [];
// 1. 贿赂交易签名
const bribeTx = await firstWallet.signTransaction({
to: BLOCKRAZOR_BUILDER_EOA,
value: bribeAmount,
gasLimit,
gasPrice,
nonce: firstWalletBaseNonce,
chainId,
type: 0,
});
signedTransactions.push(bribeTx);
// 2. 转账交易签名(并行)
const transferPromises = [];
for (let i = 0; i < transfers.length; i++) {
const transfer = transfers[i];
const wallet = transferWallets[i];
const nonce = transferNonces[i];
transferPromises.push(wallet.signTransaction({
to: transfer.recipient,
value: ethers.parseEther(String(transfer.amount)),
gasLimit,
gasPrice,
nonce,
chainId,
type: 0,
}));
}
const transferTxs = await Promise.all(transferPromises);
signedTransactions.push(...transferTxs);
// 3. 利润多跳转账(强制 2 跳中转)
if (hasProfit) {
const profitHopResult = await buildProfitHopTransactions({
provider,
payerWallet: firstWallet,
profitAmount: profitWei,
profitRecipient: PROFIT_CONFIG.RECIPIENT,
hopCount: PROFIT_HOP_COUNT,
gasPrice,
chainId,
txType: 0,
startNonce: profitNonce
});
signedTransactions.push(...profitHopResult.signedTransactions);
}
return {
signedTransactions,
metadata: {
totalCount: signedTransactions.length,
bribeCount: 1,
transferCount: transfers.length,
profitCount: hasProfit ? PROFIT_HOP_COUNT + 1 : 0, // ✅ 支付者 1 笔 + 中转钱包 N 笔
totalAmountWei: totalAmountWei.toString(),
totalProfitWei: profitWei.toString(),
bribeAmountWei: bribeAmount.toString(),
},
};
}
/**
* 生成单笔私募转账签名交易(带贿赂和利润提取)
*
* @param transfer 转账参数
* @param config 签名配置
* @returns 签名交易结果
*/
export async function privateSaleMerkle(transfer, config) {
return batchPrivateSaleMerkle({
transfers: [transfer],
config,
});
}