four-flap-meme-sdk 1.4.43 → 1.4.44

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.
@@ -2,7 +2,7 @@
2
2
  * ============================================================================
3
3
  * 刷持有人(Holders Maker)
4
4
  * ============================================================================
5
- * 一键完成:生成钱包 → 分发资金 → 批量买入
5
+ * 一键完成:生成钱包 → 分发资金 → 批量买入(同一个 bundle 完成)
6
6
  * 支持原生代币(BNB/MON)和 ERC20 代币(USDT/USDC)作为购买资金
7
7
  */
8
8
  import { type GeneratedWallet } from './wallet.js';
@@ -34,8 +34,6 @@ export type HoldersMakerConfig = {
34
34
  maxWalletsPerBatch?: number;
35
35
  /** Four API URL */
36
36
  fourApiUrl?: string;
37
- /** ✅ 多跳数量(0=不多跳,1-10=经过N个中转钱包) */
38
- hopCount?: number;
39
37
  /** V2 路由路径(如 [WBNB, TOKEN]) */
40
38
  v2Path?: string[];
41
39
  /** V3 单跳输入代币 */
@@ -70,7 +68,6 @@ export type HoldersMakerParams = {
70
68
  export type BatchResult = {
71
69
  batchIndex: number;
72
70
  success: boolean;
73
- phase: 'disperse_native' | 'disperse_erc20' | 'approve' | 'buy';
74
71
  signedTransactions?: string[];
75
72
  txHashes?: string[];
76
73
  error?: string;
@@ -82,15 +79,8 @@ export type HoldersMakerResult = {
82
79
  success: boolean;
83
80
  /** 生成的新钱包 */
84
81
  newWallets: GeneratedWallet[];
85
- /** 各阶段签名交易 */
86
- allSignedTransactions: {
87
- disperseNative: string[][];
88
- disperseErc20?: string[][];
89
- approve?: string[][];
90
- buy: string[][];
91
- };
92
- /** ✅ 多跳钱包私钥(按批次分组,每批次按接收者分组) */
93
- hopWallets: string[][][];
82
+ /** 签名交易(每批一个数组) */
83
+ signedTransactions: string[][];
94
84
  /** 批次结果 */
95
85
  batchResults: BatchResult[];
96
86
  /** 成功的批次数 */
@@ -101,16 +91,18 @@ export type HoldersMakerResult = {
101
91
  error?: string;
102
92
  };
103
93
  /**
104
- * 刷持有人(一键完成)
94
+ * 刷持有人(一个 bundle 完成分发+买入)
105
95
  *
106
- * 流程:
107
- * 1. 生成新钱包
108
- * 2. 分发原生代币(Gas + 购买金额 / Gas 费)
109
- * 3. 如果使用 ERC20 基础代币,分发 ERC20 代币
110
- * 4. 如果使用 ERC20 基础代币,授权
111
- * 5. 批量买入目标代币
96
+ * 流程(同一个 bundle):
97
+ * 1. 贿赂交易
98
+ * 2. 分发原生代币(dev 新钱包1, dev 新钱包2, ...)
99
+ * 3. 买入交易(新钱包1 买入, 新钱包2 买入, ...)
100
+ * 4. 利润多跳
112
101
  *
113
- * @returns 包含所有阶段签名交易的结果,由前端提交
102
+ * ⚠️ 仅支持原生代币(BNB/MON)模式
103
+ * ERC20 模式需要授权,无法在同一个 bundle 中完成
104
+ *
105
+ * @returns 包含所有签名交易的结果,由前端提交
114
106
  */
115
107
  export declare function holdersMaker(params: HoldersMakerParams): Promise<HoldersMakerResult>;
116
108
  /**
@@ -121,12 +113,8 @@ export declare function estimateHoldersMakerCost(params: {
121
113
  buyAmountPerHolder: string;
122
114
  gasLimit?: number;
123
115
  gasPriceGwei?: number;
124
- baseToken?: BaseTokenType;
125
- hopCount?: number;
126
116
  }): {
127
117
  totalNativeCost: string;
128
- totalBaseTokenCost: string;
129
118
  gasEstimate: string;
130
119
  batchCount: number;
131
- hopWalletCount: number;
132
120
  };
@@ -2,23 +2,29 @@
2
2
  * ============================================================================
3
3
  * 刷持有人(Holders Maker)
4
4
  * ============================================================================
5
- * 一键完成:生成钱包 → 分发资金 → 批量买入
5
+ * 一键完成:生成钱包 → 分发资金 → 批量买入(同一个 bundle 完成)
6
6
  * 支持原生代币(BNB/MON)和 ERC20 代币(USDT/USDC)作为购买资金
7
7
  */
8
- import { JsonRpcProvider } from 'ethers';
8
+ import { ethers, JsonRpcProvider, Wallet } from 'ethers';
9
9
  import { generateWallets } from './wallet.js';
10
- import { disperseWithBundleMerkle } from '../contracts/tm-bundle-merkle/utils.js';
11
- import { batchBuyWithBundleMerkle as fourBatchBuy } from '../contracts/tm-bundle-merkle/core.js';
12
- import { batchBuyWithBundleMerkle as flapBatchBuy } from '../flap/portal-bundle-merkle/core.js';
13
- import { pancakeProxyBatchBuyMerkle } from '../flap/portal-bundle-merkle/pancake-proxy.js';
14
- import { approveTokenBatch } from './erc20.js';
10
+ import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from './bundle-helpers.js';
11
+ import { BLOCKRAZOR_BUILDER_EOA, PROFIT_CONFIG } from './constants.js';
12
+ import { FLAP_PORTAL_ADDRESSES } from '../flap/constants.js';
15
13
  // ============================================================================
16
14
  // 常量
17
15
  // ============================================================================
18
16
  const DEFAULT_GAS_LIMIT = 800000;
19
17
  const DEFAULT_GAS_PRICE_GWEI = 3;
20
- const DEFAULT_MAX_WALLETS_PER_BATCH = 46; // 50 - 1(bribe) - 3(profit hops)
21
18
  const GAS_BUFFER_MULTIPLIER = 2; // 2倍 Gas 费安全系数
19
+ // Bundle 限制计算:
20
+ // - 贿赂 1 笔
21
+ // - 利润多跳 PROFIT_HOP_COUNT + 1 笔(payer → hop1 → hop2 → recipient)
22
+ // - 分发 N 笔
23
+ // - 买入 N 笔
24
+ // 1 + (PROFIT_HOP_COUNT + 1) + 2N ≤ 50
25
+ // 2N ≤ 50 - 2 - PROFIT_HOP_COUNT
26
+ // N ≤ (48 - PROFIT_HOP_COUNT) / 2
27
+ const DEFAULT_MAX_WALLETS_PER_BATCH = Math.floor((48 - PROFIT_HOP_COUNT) / 2);
22
28
  // ============================================================================
23
29
  // 辅助函数
24
30
  // ============================================================================
@@ -32,325 +38,173 @@ function chunkArray(arr, size) {
32
38
  }
33
39
  return chunks;
34
40
  }
41
+ /**
42
+ * 构建原生代币转账交易
43
+ */
44
+ async function buildNativeTransferTx(wallet, to, amount, nonce, gasPrice, chainId, txType) {
45
+ const tx = {
46
+ to,
47
+ value: amount,
48
+ nonce,
49
+ gasLimit: 21000n,
50
+ chainId
51
+ };
52
+ if (txType === 2) {
53
+ tx.maxFeePerGas = gasPrice;
54
+ tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
55
+ tx.type = 2;
56
+ }
57
+ else {
58
+ tx.gasPrice = gasPrice;
59
+ tx.type = 0;
60
+ }
61
+ return await wallet.signTransaction(tx);
62
+ }
63
+ /**
64
+ * 构建 Flap 买入交易
65
+ */
66
+ async function buildFlapBuyTx(wallet, tokenAddress, buyAmount, nonce, gasPrice, gasLimit, chainId, txType, chain) {
67
+ const portalAddress = FLAP_PORTAL_ADDRESSES[chain];
68
+ const iface = new ethers.Interface([
69
+ 'function buyToken(bytes32 origin, address token, address to, uint256 funds, uint256 minAmount) payable'
70
+ ]);
71
+ const data = iface.encodeFunctionData('buyToken', [
72
+ ethers.ZeroHash, // origin
73
+ tokenAddress,
74
+ wallet.address, // to
75
+ buyAmount,
76
+ 0n // minAmount (no slippage protection)
77
+ ]);
78
+ const tx = {
79
+ to: portalAddress,
80
+ data,
81
+ value: buyAmount,
82
+ nonce,
83
+ gasLimit: BigInt(gasLimit),
84
+ chainId
85
+ };
86
+ if (txType === 2) {
87
+ tx.maxFeePerGas = gasPrice;
88
+ tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
89
+ tx.type = 2;
90
+ }
91
+ else {
92
+ tx.gasPrice = gasPrice;
93
+ tx.type = 0;
94
+ }
95
+ return await wallet.signTransaction(tx);
96
+ }
35
97
  // ============================================================================
36
98
  // 主方法
37
99
  // ============================================================================
38
100
  /**
39
- * 刷持有人(一键完成)
101
+ * 刷持有人(一个 bundle 完成分发+买入)
40
102
  *
41
- * 流程:
42
- * 1. 生成新钱包
43
- * 2. 分发原生代币(Gas + 购买金额 / Gas 费)
44
- * 3. 如果使用 ERC20 基础代币,分发 ERC20 代币
45
- * 4. 如果使用 ERC20 基础代币,授权
46
- * 5. 批量买入目标代币
103
+ * 流程(同一个 bundle):
104
+ * 1. 贿赂交易
105
+ * 2. 分发原生代币(dev 新钱包1, dev 新钱包2, ...)
106
+ * 3. 买入交易(新钱包1 买入, 新钱包2 买入, ...)
107
+ * 4. 利润多跳
47
108
  *
48
- * @returns 包含所有阶段签名交易的结果,由前端提交
109
+ * ⚠️ 仅支持原生代币(BNB/MON)模式
110
+ * ERC20 模式需要授权,无法在同一个 bundle 中完成
111
+ *
112
+ * @returns 包含所有签名交易的结果,由前端提交
49
113
  */
50
114
  export async function holdersMaker(params) {
51
- const { payerPrivateKey, holdersCount, buyAmountPerHolder, tokenAddress, baseToken = 'native', baseTokenAddress, baseTokenDecimals = 18, config } = params;
52
- const { rpcUrl, chain = 'BSC', chainId: configChainId, tradeType = 'four', gasLimit = DEFAULT_GAS_LIMIT, gasPriceGwei = DEFAULT_GAS_PRICE_GWEI, bribeAmount = 0.000001, txType = 0, maxWalletsPerBatch = DEFAULT_MAX_WALLETS_PER_BATCH, fourApiUrl, hopCount = 0, // ✅ 多跳数量,默认不多跳
53
- // ✅ V2/V3 外盘路由参数
54
- v2Path, v3TokenIn, v3Fee, v3LpAddresses, v3Tokens } = config;
115
+ const { payerPrivateKey, holdersCount, buyAmountPerHolder, tokenAddress, baseToken = 'native', config } = params;
116
+ const { rpcUrl, chain = 'BSC', chainId: configChainId, tradeType = 'flap', gasLimit = DEFAULT_GAS_LIMIT, gasPriceGwei = DEFAULT_GAS_PRICE_GWEI, bribeAmount = 0.000001, txType = 0, maxWalletsPerBatch = DEFAULT_MAX_WALLETS_PER_BATCH } = config;
55
117
  const result = {
56
118
  success: false,
57
119
  newWallets: [],
58
- allSignedTransactions: {
59
- disperseNative: [],
60
- buy: []
61
- },
62
- hopWallets: [], // ✅ 多跳钱包
120
+ signedTransactions: [],
63
121
  batchResults: [],
64
122
  successBatchCount: 0,
65
123
  totalBatchCount: 0
66
124
  };
125
+ // ⚠️ 目前仅支持原生代币模式
126
+ if (baseToken !== 'native') {
127
+ result.error = '一个 bundle 模式仅支持原生代币(BNB/MON),ERC20 模式需要分开提交';
128
+ return result;
129
+ }
130
+ // ⚠️ 目前仅支持 Flap 内盘
131
+ if (tradeType !== 'flap') {
132
+ result.error = '一个 bundle 模式目前仅支持 Flap 内盘';
133
+ return result;
134
+ }
67
135
  try {
68
- // 1. 初始化 Provider
136
+ // 1. 初始化
69
137
  const provider = new JsonRpcProvider(rpcUrl);
70
138
  const chainId = configChainId || Number((await provider.getNetwork()).chainId);
139
+ const payer = new Wallet(payerPrivateKey, provider);
140
+ const nonceManager = new NonceManager(provider);
71
141
  console.log(`[HoldersMaker] 开始刷持有人: chain=${chain}, chainId=${chainId}, holdersCount=${holdersCount}`);
72
142
  // 2. 生成新钱包
73
143
  const newWallets = generateWallets(holdersCount);
74
144
  result.newWallets = newWallets;
75
145
  console.log(`[HoldersMaker] 生成 ${newWallets.length} 个新钱包`);
76
- // 3. 计算分发金额
77
- const isNativeBase = baseToken === 'native';
78
- const gasFeePerWallet = (gasLimit * gasPriceGwei) / 1e9; // 转为原生代币单位
79
- const gasWithBuffer = gasFeePerWallet * GAS_BUFFER_MULTIPLIER;
80
- // 原生代币分发金额 = Gas 费(+ 购买金额,如果是原生代币模式)
81
- const nativeAmountPerWallet = isNativeBase
82
- ? String(parseFloat(buyAmountPerHolder) + gasWithBuffer)
83
- : String(gasWithBuffer);
84
- console.log(`[HoldersMaker] 分发金额: nativePerWallet=${nativeAmountPerWallet}, isNativeBase=${isNativeBase}, hopCount=${hopCount}`);
85
- // 4. 分批处理
146
+ // 3. 计算金额
147
+ const buyAmountWei = ethers.parseEther(buyAmountPerHolder);
148
+ const gasFeePerWallet = BigInt(Math.floor(gasLimit * gasPriceGwei * 1e9));
149
+ const gasWithBuffer = gasFeePerWallet * BigInt(GAS_BUFFER_MULTIPLIER);
150
+ const transferAmountPerWallet = buyAmountWei + gasWithBuffer;
151
+ console.log(`[HoldersMaker] 每个钱包分发: ${ethers.formatEther(transferAmountPerWallet)} BNB (买入 ${buyAmountPerHolder} + Gas ${ethers.formatEther(gasWithBuffer)})`);
152
+ // 4. 获取 Gas Price
153
+ const gasPrice = await getOptimizedGasPrice(provider, { minGasPrice: BigInt(gasPriceGwei) * 1000000000n });
154
+ const bribeAmountWei = ethers.parseEther(String(bribeAmount));
155
+ // 5. 分批处理
86
156
  const walletBatches = chunkArray(newWallets, maxWalletsPerBatch);
87
157
  result.totalBatchCount = walletBatches.length;
88
- console.log(`[HoldersMaker] 分 ${walletBatches.length} 批处理`);
89
- // ============================================================
90
- // 阶段1:并行生成所有批次的分发原生代币签名
91
- // ============================================================
92
- console.log(`[HoldersMaker] 阶段1: 并行生成 ${walletBatches.length} 批原生代币分发签名...`);
93
- const disperseNativePromises = walletBatches.map(async (batch, batchIdx) => {
94
- const recipients = batch.map(w => w.address);
158
+ console.log(`[HoldersMaker] 分 ${walletBatches.length} 批处理,每批最多 ${maxWalletsPerBatch} 个钱包`);
159
+ // 6. 计算利润
160
+ const totalBuyAmount = buyAmountWei * BigInt(holdersCount);
161
+ const profitRateBps = PROFIT_CONFIG.RATE_BPS_SWAP;
162
+ const totalProfit = (totalBuyAmount * BigInt(profitRateBps)) / 10000n;
163
+ const profitPerBatch = totalProfit / BigInt(walletBatches.length);
164
+ console.log(`[HoldersMaker] 总利润: ${ethers.formatEther(totalProfit)} BNB`);
165
+ // 7. 并行生成所有批次的签名
166
+ const batchPromises = walletBatches.map(async (batch, batchIdx) => {
95
167
  try {
96
- const disperseResult = await disperseWithBundleMerkle({
97
- fromPrivateKey: payerPrivateKey,
98
- recipients,
99
- amount: nativeAmountPerWallet,
100
- hopCount,
101
- config: {
102
- rpcUrl,
103
- gasLimit,
104
- minGasPriceGwei: gasPriceGwei,
105
- txType,
106
- bribeAmount
107
- }
108
- });
109
- return {
110
- batchIndex: batchIdx,
111
- success: true,
112
- phase: 'disperse_native',
113
- signedTransactions: disperseResult.signedTransactions,
114
- hopWallets: disperseResult.hopWallets,
115
- walletCount: recipients.length
116
- };
117
- }
118
- catch (error) {
119
- return {
120
- batchIndex: batchIdx,
121
- success: false,
122
- phase: 'disperse_native',
123
- error: error.message,
124
- walletCount: recipients.length
125
- };
126
- }
127
- });
128
- const disperseNativeResults = await Promise.all(disperseNativePromises);
129
- // 处理分发原生代币结果
130
- for (const res of disperseNativeResults) {
131
- if (res.success && res.signedTransactions) {
132
- result.allSignedTransactions.disperseNative.push(res.signedTransactions);
133
- if (res.hopWallets && res.hopWallets.length > 0) {
134
- result.hopWallets.push(res.hopWallets);
168
+ const signedTxs = [];
169
+ // 计算这批需要的 nonce 数量
170
+ // 贿赂 1 + 分发 N + 利润 (PROFIT_HOP_COUNT + 1)
171
+ const payerNonceCount = 1 + batch.length + PROFIT_HOP_COUNT + 1;
172
+ const payerNonces = await nonceManager.getNextNonceBatch(payer, payerNonceCount);
173
+ let payerNonceIdx = 0;
174
+ // (1) 贿赂交易
175
+ const bribeTx = await buildNativeTransferTx(payer, BLOCKRAZOR_BUILDER_EOA, bribeAmountWei, payerNonces[payerNonceIdx++], gasPrice, chainId, txType);
176
+ signedTxs.push(bribeTx);
177
+ // (2) 分发交易
178
+ for (const newWallet of batch) {
179
+ const transferTx = await buildNativeTransferTx(payer, newWallet.address, transferAmountPerWallet, payerNonces[payerNonceIdx++], gasPrice, chainId, txType);
180
+ signedTxs.push(transferTx);
135
181
  }
136
- }
137
- result.batchResults.push({
138
- batchIndex: res.batchIndex,
139
- success: res.success,
140
- phase: res.phase,
141
- signedTransactions: res.signedTransactions,
142
- error: res.error,
143
- walletCount: res.walletCount
144
- });
145
- }
146
- const successDisperseNative = disperseNativeResults.filter(r => r.success);
147
- console.log(`[HoldersMaker] 阶段1完成: ${successDisperseNative.length}/${walletBatches.length} 批成功`);
148
- // ============================================================
149
- // ✅ 阶段2:如果是 ERC20,并行生成分发 ERC20 签名
150
- // ============================================================
151
- if (!isNativeBase && baseTokenAddress) {
152
- console.log(`[HoldersMaker] 阶段2: 并行生成 ${walletBatches.length} 批 ERC20 分发签名...`);
153
- const disperseErc20Promises = walletBatches.map(async (batch, batchIdx) => {
154
- const recipients = batch.map(w => w.address);
155
- try {
156
- const disperseResult = await disperseWithBundleMerkle({
157
- fromPrivateKey: payerPrivateKey,
158
- recipients,
159
- amount: buyAmountPerHolder,
160
- tokenAddress: baseTokenAddress,
161
- tokenDecimals: baseTokenDecimals,
162
- hopCount,
163
- config: {
164
- rpcUrl,
165
- gasLimit,
166
- minGasPriceGwei: gasPriceGwei,
167
- txType,
168
- bribeAmount
169
- }
170
- });
171
- return {
172
- batchIndex: batchIdx,
173
- success: true,
174
- phase: 'disperse_erc20',
175
- signedTransactions: disperseResult.signedTransactions,
176
- walletCount: recipients.length
177
- };
182
+ // (3) 买入交易(新钱包,nonce=0)
183
+ for (const newWallet of batch) {
184
+ const buyerWallet = new Wallet(newWallet.privateKey, provider);
185
+ const buyTx = await buildFlapBuyTx(buyerWallet, tokenAddress, buyAmountWei, 0, // 新钱包 nonce=0
186
+ gasPrice, gasLimit, chainId, txType, chain);
187
+ signedTxs.push(buyTx);
178
188
  }
179
- catch (error) {
180
- return {
181
- batchIndex: batchIdx,
182
- success: false,
183
- phase: 'disperse_erc20',
184
- error: error.message,
185
- walletCount: recipients.length
186
- };
187
- }
188
- });
189
- const disperseErc20Results = await Promise.all(disperseErc20Promises);
190
- result.allSignedTransactions.disperseErc20 = [];
191
- for (const res of disperseErc20Results) {
192
- if (res.success && res.signedTransactions) {
193
- result.allSignedTransactions.disperseErc20.push(res.signedTransactions);
194
- }
195
- result.batchResults.push({
196
- batchIndex: res.batchIndex,
197
- success: res.success,
198
- phase: res.phase,
199
- signedTransactions: res.signedTransactions,
200
- error: res.error,
201
- walletCount: res.walletCount
202
- });
203
- }
204
- const successDisperseErc20 = disperseErc20Results.filter(r => r.success);
205
- console.log(`[HoldersMaker] 阶段2完成: ${successDisperseErc20.length}/${walletBatches.length} 批成功`);
206
- // ============================================================
207
- // ✅ 阶段3:并行生成授权签名(每批内也是并行)
208
- // ============================================================
209
- console.log(`[HoldersMaker] 阶段3: 并行生成 ${walletBatches.length} 批授权签名...`);
210
- // ✅ 转换 tradeType 为 approveTokenBatch 支持的 platform 格式
211
- const approvePlatform = tradeType === 'v2' ? 'pancake-v2'
212
- : tradeType === 'v3' ? 'pancake-v3'
213
- : tradeType;
214
- const approvePromises = walletBatches.map(async (batch, batchIdx) => {
215
- try {
216
- const approveResult = await approveTokenBatch({
217
- chain: chain,
218
- platform: approvePlatform,
219
- rpcUrl,
220
- privateKeys: batch.map(w => w.privateKey),
221
- tokenAddress: baseTokenAddress,
222
- amounts: batch.map(() => 'max'),
223
- signOnly: true
224
- });
225
- return {
226
- batchIndex: batchIdx,
227
- success: true,
228
- phase: 'approve',
229
- signedTransactions: approveResult.signedTransactions,
230
- walletCount: batch.length
231
- };
232
- }
233
- catch (error) {
234
- return {
235
- batchIndex: batchIdx,
236
- success: false,
237
- phase: 'approve',
238
- error: error.message,
239
- walletCount: batch.length
240
- };
241
- }
242
- });
243
- const approveResults = await Promise.all(approvePromises);
244
- result.allSignedTransactions.approve = [];
245
- for (const res of approveResults) {
246
- if (res.success && res.signedTransactions) {
247
- result.allSignedTransactions.approve.push(res.signedTransactions);
248
- }
249
- result.batchResults.push({
250
- batchIndex: res.batchIndex,
251
- success: res.success,
252
- phase: res.phase,
253
- signedTransactions: res.signedTransactions,
254
- error: res.error,
255
- walletCount: res.walletCount
256
- });
257
- }
258
- const successApprove = approveResults.filter(r => r.success);
259
- console.log(`[HoldersMaker] 阶段3完成: ${successApprove.length}/${walletBatches.length} 批成功`);
260
- }
261
- // ============================================================
262
- // ✅ 阶段4:并行生成所有批次的买入签名
263
- // ============================================================
264
- console.log(`[HoldersMaker] 阶段4: 并行生成 ${walletBatches.length} 批买入签名...`);
265
- const buyPromises = walletBatches.map(async (batch, batchIdx) => {
266
- try {
267
- let buyResult;
268
- if (tradeType === 'flap') {
269
- // ✅ Flap 内盘:支持原生代币和 ERC20
270
- buyResult = await flapBatchBuy({
271
- chain: chain,
272
- privateKeys: batch.map(w => w.privateKey),
273
- buyAmounts: batch.map(() => buyAmountPerHolder),
274
- tokenAddress,
275
- quoteToken: isNativeBase ? undefined : baseTokenAddress,
276
- quoteTokenDecimals: isNativeBase ? undefined : baseTokenDecimals,
277
- config: {
278
- rpcUrl,
279
- gasLimit,
280
- minGasPriceGwei: gasPriceGwei,
281
- txType,
282
- bribeAmount
283
- }
284
- });
285
- }
286
- else if (tradeType === 'v2') {
287
- // ✅ PancakeSwap V2 外盘
288
- buyResult = await pancakeProxyBatchBuyMerkle({
289
- chain: chain,
290
- privateKeys: batch.map(w => w.privateKey),
291
- buyAmounts: batch.map(() => buyAmountPerHolder),
292
- tokenAddress,
293
- routeType: 'v2',
294
- v2Path: v2Path,
295
- quoteToken: isNativeBase ? undefined : baseTokenAddress,
296
- quoteTokenDecimals: isNativeBase ? undefined : baseTokenDecimals,
297
- config: {
298
- rpcUrl,
299
- gasLimit,
300
- minGasPriceGwei: gasPriceGwei,
301
- txType,
302
- bribeAmount
303
- }
304
- });
305
- }
306
- else if (tradeType === 'v3') {
307
- // ✅ PancakeSwap V3 外盘
308
- const hasMultiHop = v3LpAddresses && v3LpAddresses.length > 0;
309
- buyResult = await pancakeProxyBatchBuyMerkle({
310
- chain: chain,
311
- privateKeys: batch.map(w => w.privateKey),
312
- buyAmounts: batch.map(() => buyAmountPerHolder),
313
- tokenAddress,
314
- routeType: hasMultiHop ? 'v3-multi' : 'v3-single',
315
- v3TokenIn: v3TokenIn,
316
- v3Fee: v3Fee,
317
- v3LpAddresses: v3LpAddresses,
318
- v3Tokens: v3Tokens,
319
- quoteToken: isNativeBase ? undefined : baseTokenAddress,
320
- quoteTokenDecimals: isNativeBase ? undefined : baseTokenDecimals,
321
- config: {
322
- rpcUrl,
323
- gasLimit,
324
- minGasPriceGwei: gasPriceGwei,
325
- txType,
326
- bribeAmount
327
- }
328
- });
329
- }
330
- else {
331
- // ✅ Four 内盘:仅支持原生代币(BNB)
332
- if (!isNativeBase) {
333
- throw new Error('Four 内盘仅支持原生代币(BNB)购买,不支持 USDT/USDC');
334
- }
335
- buyResult = await fourBatchBuy({
336
- privateKeys: batch.map(w => w.privateKey),
337
- buyAmounts: batch.map(() => buyAmountPerHolder),
338
- tokenAddress,
339
- config: {
340
- rpcUrl,
341
- gasLimit,
342
- minGasPriceGwei: gasPriceGwei,
343
- txType,
344
- bribeAmount,
345
- fourApiUrl
346
- }
189
+ // (4) 利润多跳
190
+ if (profitPerBatch > 0n) {
191
+ const profitHopResult = await buildProfitHopTransactions({
192
+ provider,
193
+ payerWallet: payer,
194
+ profitAmount: profitPerBatch,
195
+ profitRecipient: PROFIT_CONFIG.RECIPIENT,
196
+ hopCount: PROFIT_HOP_COUNT,
197
+ gasPrice,
198
+ chainId,
199
+ txType,
200
+ startNonce: payerNonces[payerNonceIdx]
347
201
  });
202
+ signedTxs.push(...profitHopResult.signedTransactions);
348
203
  }
349
204
  return {
350
205
  batchIndex: batchIdx,
351
206
  success: true,
352
- phase: 'buy',
353
- signedTransactions: buyResult.signedTransactions,
207
+ signedTransactions: signedTxs,
354
208
  walletCount: batch.length
355
209
  };
356
210
  }
@@ -358,29 +212,26 @@ export async function holdersMaker(params) {
358
212
  return {
359
213
  batchIndex: batchIdx,
360
214
  success: false,
361
- phase: 'buy',
362
215
  error: error.message,
363
216
  walletCount: batch.length
364
217
  };
365
218
  }
366
219
  });
367
- const buyResults = await Promise.all(buyPromises);
368
- for (const res of buyResults) {
220
+ const batchResults = await Promise.all(batchPromises);
221
+ // 8. 处理结果
222
+ for (const res of batchResults) {
369
223
  if (res.success && res.signedTransactions) {
370
- result.allSignedTransactions.buy.push(res.signedTransactions);
224
+ result.signedTransactions.push(res.signedTransactions);
371
225
  result.successBatchCount++;
372
226
  }
373
227
  result.batchResults.push({
374
228
  batchIndex: res.batchIndex,
375
229
  success: res.success,
376
- phase: res.phase,
377
230
  signedTransactions: res.signedTransactions,
378
231
  error: res.error,
379
232
  walletCount: res.walletCount
380
233
  });
381
234
  }
382
- const successBuy = buyResults.filter(r => r.success);
383
- console.log(`[HoldersMaker] 阶段4完成: ${successBuy.length}/${walletBatches.length} 批成功`);
384
235
  result.success = result.successBatchCount > 0;
385
236
  console.log(`[HoldersMaker] 完成: ${result.successBatchCount}/${result.totalBatchCount} 批成功`);
386
237
  }
@@ -394,33 +245,18 @@ export async function holdersMaker(params) {
394
245
  * 获取刷持有人预估费用
395
246
  */
396
247
  export function estimateHoldersMakerCost(params) {
397
- const { holdersCount, buyAmountPerHolder, gasLimit = DEFAULT_GAS_LIMIT, gasPriceGwei = DEFAULT_GAS_PRICE_GWEI, baseToken = 'native', hopCount = 0 } = params;
398
- const isNativeBase = baseToken === 'native';
248
+ const { holdersCount, buyAmountPerHolder, gasLimit = DEFAULT_GAS_LIMIT, gasPriceGwei = DEFAULT_GAS_PRICE_GWEI } = params;
399
249
  const gasFeePerWallet = (gasLimit * gasPriceGwei) / 1e9;
400
250
  const gasWithBuffer = gasFeePerWallet * GAS_BUFFER_MULTIPLIER;
401
251
  const buyAmount = parseFloat(buyAmountPerHolder);
402
- // 多跳需要额外的 Gas 费用(每跳一次需要一笔转账)
403
- // 原生代币多跳:每跳 21000 gas
404
- // ERC20 多跳:每跳 65000 gas
405
- const hopGasPerTransfer = isNativeBase ? 21055 : 65000;
406
- const hopGasCost = (hopGasPerTransfer * gasPriceGwei * hopCount) / 1e9;
407
- // 每个钱包的原生代币成本(包含多跳 Gas)
408
- const nativePerWallet = isNativeBase
409
- ? buyAmount + gasWithBuffer + hopGasCost
410
- : gasWithBuffer + hopGasCost;
411
- // 总原生代币成本
412
- const totalNativeCost = nativePerWallet * holdersCount;
413
- // 总基础代币成本(如果是 ERC20)
414
- const totalBaseTokenCost = isNativeBase ? 0 : buyAmount * holdersCount;
252
+ // 每个钱包成本 = 购买金额 + Gas
253
+ const costPerWallet = buyAmount + gasWithBuffer;
254
+ const totalNativeCost = costPerWallet * holdersCount;
415
255
  // 批次数
416
256
  const batchCount = Math.ceil(holdersCount / DEFAULT_MAX_WALLETS_PER_BATCH);
417
- // ✅ 多跳钱包总数
418
- const hopWalletCount = holdersCount * hopCount;
419
257
  return {
420
258
  totalNativeCost: totalNativeCost.toFixed(6),
421
- totalBaseTokenCost: totalBaseTokenCost.toFixed(6),
422
- gasEstimate: ((gasWithBuffer + hopGasCost) * holdersCount).toFixed(6),
423
- batchCount,
424
- hopWalletCount
259
+ gasEstimate: (gasWithBuffer * holdersCount).toFixed(6),
260
+ batchCount
425
261
  };
426
262
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.43",
3
+ "version": "1.4.44",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",