four-flap-meme-sdk 1.2.72 → 1.2.73

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';
@@ -149,19 +149,26 @@ export async function createTokenWithBundleBuyMerkle(params) {
149
149
  bundleUuid = await config.customSubmitFn(signedTxs);
150
150
  console.log(`✅ Bundle 提交成功!UUID: ${bundleUuid}`);
151
151
  }
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 批量提交成功!`);
162
- }
163
152
  else {
164
- throw new Error('❌ 浏览器环境必须提供 customSubmitFn spPrivateKey 来提交 Bundle(避免 CORS 限制)');
153
+ // 方式 2:使用免费的 eth_sendBundle(不需要 48SP 签名)
154
+ console.log('📡 使用免费 Bundle 提交...');
155
+ const endpoint = config.club48Endpoint || 'https://puissant-bsc.48.club';
156
+ const bundleParams = {
157
+ txs: signedTxs,
158
+ maxTimestamp: Math.floor(Date.now() / 1000) + 300, // 5 分钟有效期
159
+ revertingTxHashes: []
160
+ };
161
+ const response = await axios.post(endpoint, {
162
+ jsonrpc: "2.0",
163
+ id: 1,
164
+ method: "eth_sendBundle",
165
+ params: [bundleParams]
166
+ });
167
+ if (response.data.error) {
168
+ throw new Error(`48.club bundle 提交失败: ${response.data.error.message}`);
169
+ }
170
+ bundleUuid = response.data.result;
171
+ console.log(`✅ 免费 Bundle 提交成功!UUID: ${bundleUuid}`);
165
172
  }
166
173
  // 等待交易上链并解析代币地址
167
174
  const tokenAddress = await waitAndParseTokenAddress(provider, signedTxs[0], bundleUuid);
@@ -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.73",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",