four-flap-meme-sdk 1.2.72 → 1.2.74

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 @@ import { ethers, Wallet } from 'ethers';
2
2
  import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
3
3
  import { ADDRESSES } from '../../utils/constants.js';
4
4
  import { FourClient, buildLoginMessage } from '../../clients/four.js';
5
- import { sendBatchPrivateTransactions } from '../../clients/club48.js';
5
+ import axios from 'axios';
6
6
  import { getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
7
7
  import { batchCheckAllowances } from '../../utils/erc20.js';
8
8
  import { trySell } from '../tm.js';
@@ -141,35 +141,83 @@ export async function createTokenWithBundleBuyMerkle(params) {
141
141
  }
142
142
  nonceManager.clearTemp();
143
143
  console.log(`✅ 总共生成了 ${signedTxs.length} 个交易签名 (1创建 + ${buyerKeys.length}买入 + 利润)`);
144
- // ✅ 内部提交到 48.club Bundle
145
- console.log('📡 开始提交到 48.club Bundle...');
146
- let bundleUuid;
147
- if (config.customSubmitFn) {
148
- // ✅ 方式 1:使用自定义提交函数(通过服务器代理)
149
- bundleUuid = await config.customSubmitFn(signedTxs);
150
- console.log(`✅ Bundle 提交成功!UUID: ${bundleUuid}`);
144
+ // ✅ 使用 48.club 的 eth_sendRawTransaction 捆绑提交
145
+ console.log('📡 开始通过 48.club 捆绑提交交易...');
146
+ const club48Endpoint = config.club48Endpoint || 'https://puissant-bsc.48.club';
147
+ const txHashes = [];
148
+ // ✅ 使用 eth_sendRawTransaction 逐个提交(48.club 会自动捆绑连续的交易)
149
+ for (let i = 0; i < signedTxs.length; i++) {
150
+ try {
151
+ const tx = signedTxs[i];
152
+ console.log(`📤 提交第 ${i + 1}/${signedTxs.length} 个交易...`);
153
+ const response = await axios.post(club48Endpoint, {
154
+ jsonrpc: "2.0",
155
+ id: i + 1,
156
+ method: "eth_sendRawTransaction",
157
+ params: [tx]
158
+ });
159
+ if (response.data.error) {
160
+ throw new Error(`交易 ${i + 1} 提交失败: ${response.data.error.message}`);
161
+ }
162
+ const txHash = response.data.result;
163
+ txHashes.push(txHash);
164
+ console.log(`✅ 交易 ${i + 1} 提交成功: ${txHash}`);
165
+ }
166
+ catch (error) {
167
+ console.error(`❌ 交易 ${i + 1} 提交失败:`, error.message);
168
+ throw new Error(`交易 ${i + 1} 提交失败: ${error.message}`);
169
+ }
151
170
  }
152
- else if (config.spPrivateKey) {
153
- // ✅ 方式 2:使用 48SP 批量提交(支持浏览器直接调用)
154
- console.log('📡 使用 48SP 批量提交...');
155
- await sendBatchPrivateTransactions(signedTxs, config.spPrivateKey, config.club48Endpoint || 'https://puissant-bsc.48.club', {
156
- spMode: config.spMode,
157
- spVMode: config.spVMode
158
- });
159
- // 批量提交不返回 bundleUuid,使用第一笔交易的 hash 作为标识
160
- bundleUuid = ethers.keccak256(signedTxs[0]);
161
- console.log(`✅ 48SP 批量提交成功!`);
171
+ console.log(`✅ 所有交易提交成功!共 ${txHashes.length} 笔`);
172
+ // 等待创建交易确认并解析代币地址
173
+ console.log(' 等待创建交易确认并解析代币地址...');
174
+ const createTxHash = txHashes[0];
175
+ // 使用公共 RPC 查询交易收据(避免 CORS)
176
+ let receipt = null;
177
+ let retries = 0;
178
+ const maxRetries = 60; // 最多等待 60
179
+ while (!receipt && retries < maxRetries) {
180
+ try {
181
+ receipt = await provider.getTransactionReceipt(createTxHash);
182
+ if (receipt)
183
+ break;
184
+ }
185
+ catch (e) {
186
+ // 忽略查询错误
187
+ }
188
+ await new Promise(resolve => setTimeout(resolve, 1000));
189
+ retries++;
190
+ if (retries % 5 === 0) {
191
+ console.log(`⏳ 等待交易确认... (${retries}/${maxRetries})`);
192
+ }
193
+ }
194
+ if (!receipt) {
195
+ throw new Error('等待交易确认超时');
196
+ }
197
+ console.log(`✅ 创建交易已确认,区块: ${receipt.blockNumber}`);
198
+ // 解析 TokenCreated 事件
199
+ let tokenAddress;
200
+ for (const log of receipt.logs) {
201
+ try {
202
+ // TokenCreated(address indexed token, ...)
203
+ if (log.topics[0] === ethers.id('TokenCreated(address,address,string,string,uint256,uint256,uint256)')) {
204
+ tokenAddress = ethers.getAddress('0x' + log.topics[1].slice(26));
205
+ break;
206
+ }
207
+ }
208
+ catch (e) {
209
+ // 忽略解析错误
210
+ }
162
211
  }
163
- else {
164
- throw new Error('❌ 浏览器环境必须提供 customSubmitFn 或 spPrivateKey 来提交 Bundle(避免 CORS 限制)');
212
+ if (!tokenAddress) {
213
+ throw new Error('无法从交易收据中解析代币地址');
165
214
  }
166
- // 等待交易上链并解析代币地址
167
- const tokenAddress = await waitAndParseTokenAddress(provider, signedTxs[0], bundleUuid);
215
+ console.log(`✅ 代币地址: ${tokenAddress}`);
168
216
  return {
169
217
  signedTransactions: signedTxs,
170
218
  tokenAddress,
171
219
  metadata,
172
- bundleUuid
220
+ txHashes
173
221
  };
174
222
  }
175
223
  /**
@@ -70,8 +70,8 @@ export type MerkleSignedResult = {
70
70
  metadata?: {
71
71
  [key: string]: any;
72
72
  };
73
- /** Bundle UUID(内部提交时返回) */
74
- bundleUuid?: string;
73
+ /** 交易哈希数组(内部提交时返回) */
74
+ txHashes?: string[];
75
75
  };
76
76
  /** ✅ 创建代币 + 购买参数(Merkle 版本 - 完整) */
77
77
  export type FourCreateWithBundleBuyMerkleParams = {
@@ -160,9 +160,17 @@ export async function disperseWithBundleMerkle(params) {
160
160
  const nonceManager = new NonceManager(provider);
161
161
  for (let i = 0; i < recipients.length; i++) {
162
162
  const finalRecipient = recipients[i];
163
- const amountWei = isNative
163
+ const originalAmountWei = isNative
164
164
  ? ethers.parseEther(normalizedAmounts[i])
165
165
  : ethers.parseUnits(normalizedAmounts[i], decimals);
166
+ // ✅ 计算利润并扣除
167
+ totalAmountBeforeProfit += originalAmountWei;
168
+ let amountWei = originalAmountWei;
169
+ if (extractProfit) {
170
+ const { profit, remaining } = calculateProfit(originalAmountWei, config);
171
+ amountWei = remaining;
172
+ totalProfit += profit;
173
+ }
166
174
  const hopChain = preparedHops[i];
167
175
  if (hopChain.length === 0) {
168
176
  // 该接收者无跳转,直接转账
@@ -257,6 +265,36 @@ export async function disperseWithBundleMerkle(params) {
257
265
  }
258
266
  }
259
267
  }
268
+ // ✅ 添加利润转账(多跳模式)
269
+ if (extractProfit && totalProfit > 0n) {
270
+ const profitNonce = await nonceManager.getNextNonce(mainWallet);
271
+ if (isNative) {
272
+ const profitTx = await mainWallet.signTransaction({
273
+ to: getProfitRecipient(),
274
+ value: totalProfit,
275
+ nonce: profitNonce,
276
+ gasPrice,
277
+ gasLimit: 21000n,
278
+ chainId: chainIdNum,
279
+ type: txType
280
+ });
281
+ signedTxs.push(profitTx);
282
+ }
283
+ else {
284
+ const profitData = iface.encodeFunctionData('transfer', [getProfitRecipient(), totalProfit]);
285
+ const profitTx = await mainWallet.signTransaction({
286
+ to: tokenAddress,
287
+ data: profitData,
288
+ value: 0n,
289
+ nonce: profitNonce,
290
+ gasPrice,
291
+ gasLimit: 60000n,
292
+ chainId: chainIdNum,
293
+ type: txType
294
+ });
295
+ signedTxs.push(profitTx);
296
+ }
297
+ }
260
298
  }
261
299
  // ✅ 简化返回:只返回签名交易、多跳钱包和元数据
262
300
  return {
@@ -641,6 +679,8 @@ export async function sweepWithBundleMerkle(params) {
641
679
  _batchGetBalances(provider, sourceAddresses, tokenAddress),
642
680
  isNative ? Promise.resolve([]) : _batchGetBalances(provider, sourceAddresses)
643
681
  ]);
682
+ // ✅ 用于记录每个钱包的归集金额(用于计算利润)
683
+ const sweepAmounts = new Array(sourceWallets.length).fill(0n);
644
684
  // 处理无跳转的地址(批量)
645
685
  if (withoutHopIndexes.length > 0) {
646
686
  for (let idx = 0; idx < withoutHopIndexes.length; idx++) {
@@ -676,6 +716,8 @@ export async function sweepWithBundleMerkle(params) {
676
716
  toSend = amt;
677
717
  }
678
718
  if (toSend > 0n) {
719
+ sweepAmounts[i] = toSend; // ✅ 记录归集金额
720
+ totalAmountBeforeProfit += toSend;
679
721
  const nonce = await nonceManager.getNextNonce(sourceWallet);
680
722
  const tx = await sourceWallet.signTransaction({
681
723
  to: target,
@@ -711,6 +753,8 @@ export async function sweepWithBundleMerkle(params) {
711
753
  toSend = ethers.parseUnits(amountStrForI, decimals);
712
754
  }
713
755
  if (toSend > 0n && (!skipIfInsufficient || bal >= toSend)) {
756
+ sweepAmounts[i] = toSend; // ✅ 记录归集金额
757
+ totalAmountBeforeProfit += toSend;
714
758
  const nonce = await nonceManager.getNextNonce(sourceWallet);
715
759
  const data = iface.encodeFunctionData('transfer', [target, toSend]);
716
760
  const tx = await sourceWallet.signTransaction({
@@ -794,6 +838,9 @@ export async function sweepWithBundleMerkle(params) {
794
838
  }
795
839
  if (toSend <= 0n)
796
840
  continue;
841
+ // ✅ 记录归集金额
842
+ sweepAmounts[i] = toSend;
843
+ totalAmountBeforeProfit += toSend;
797
844
  // 构建跳转链: 子钱包 -> 中转1 -> 中转2 -> ... -> 目标地址
798
845
  const fullChain = [sourceWallet, ...hopChain.map(pk => new Wallet(pk, provider))];
799
846
  const addresses = [...fullChain.map(w => w.address), target];
@@ -860,6 +907,56 @@ export async function sweepWithBundleMerkle(params) {
860
907
  }
861
908
  }
862
909
  }
910
+ // ✅ 多跳模式:计算利润并添加利润转账
911
+ if (extractProfit && totalAmountBeforeProfit > 0n) {
912
+ // 找出归集金额最大的钱包作为支付者
913
+ let maxSweepIndex = -1;
914
+ let maxSweepAmount = 0n;
915
+ for (let i = 0; i < sweepAmounts.length; i++) {
916
+ if (sweepAmounts[i] > maxSweepAmount) {
917
+ maxSweepAmount = sweepAmounts[i];
918
+ maxSweepIndex = i;
919
+ }
920
+ }
921
+ // 计算总利润
922
+ for (let i = 0; i < sweepAmounts.length; i++) {
923
+ if (sweepAmounts[i] > 0n) {
924
+ const { profit } = calculateProfit(sweepAmounts[i], config);
925
+ totalProfit += profit;
926
+ }
927
+ }
928
+ // 由归集金额最大的钱包支付利润
929
+ if (totalProfit > 0n && maxSweepIndex >= 0) {
930
+ const payerWallet = sourceWallets[maxSweepIndex];
931
+ const profitNonce = await nonceManager.getNextNonce(payerWallet);
932
+ if (isNative) {
933
+ const profitTx = await payerWallet.signTransaction({
934
+ to: getProfitRecipient(),
935
+ value: totalProfit,
936
+ nonce: profitNonce,
937
+ gasPrice,
938
+ gasLimit: 21000n,
939
+ chainId: chainIdNum,
940
+ type: txType
941
+ });
942
+ signedTxs.push(profitTx);
943
+ }
944
+ else {
945
+ const profitData = iface.encodeFunctionData('transfer', [getProfitRecipient(), totalProfit]);
946
+ const profitTx = await payerWallet.signTransaction({
947
+ to: tokenAddress,
948
+ data: profitData,
949
+ value: 0n,
950
+ nonce: profitNonce,
951
+ gasPrice,
952
+ gasLimit: finalGasLimit,
953
+ chainId: chainIdNum,
954
+ type: txType
955
+ });
956
+ signedTxs.push(profitTx);
957
+ }
958
+ }
959
+ }
863
960
  }
864
961
  // ✅ 简化返回:只返回签名交易、多跳钱包和元数据
865
962
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.2.72",
3
+ "version": "1.2.74",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",