four-flap-meme-sdk 1.5.27 → 1.5.28

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.
@@ -284,6 +284,7 @@ export type DisperseMerkleResult = MerkleSignedResult;
284
284
  export type SweepMerkleParams = {
285
285
  sourcePrivateKeys: string[];
286
286
  target: string;
287
+ targetPrivateKey?: string;
287
288
  ratioPct?: number;
288
289
  ratios?: number[];
289
290
  amount?: AmountLike;
@@ -306,6 +307,8 @@ export type SweepMerkleParams = {
306
307
  export type SweepSignParams = {
307
308
  sourcePrivateKeys: string[];
308
309
  target: string;
310
+ /** ✅ 新增:归集目标地址的私钥(用于支付利润,不提供则由归集金额最大的源钱包支付) */
311
+ targetPrivateKey?: string;
309
312
  ratioPct?: number;
310
313
  ratios?: number[];
311
314
  amount?: AmountLike;
@@ -641,7 +641,7 @@ export async function disperseWithBundleMerkle(params) {
641
641
  * ✅ 优化版:支持 startNonce 参数避免并行调用时的 nonce 冲突
642
642
  */
643
643
  export async function sweepWithBundleMerkle(params) {
644
- const { sourcePrivateKeys, target, ratioPct, ratios, amount, amounts, tokenAddress, tokenDecimals, skipIfInsufficient = true, hopCount = 0, hopPrivateKeys, sources, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native', userType = 'v0' } = params;
644
+ const { sourcePrivateKeys, target, targetPrivateKey, ratioPct, ratios, amount, amounts, tokenAddress, tokenDecimals, skipIfInsufficient = true, hopCount = 0, hopPrivateKeys, sources, config, startNonce, tokenPoolType = 'v2', quoteToken = 'native', userType = 'v0' } = params;
645
645
  // 快速返回空结果
646
646
  if (!sourcePrivateKeys || sourcePrivateKeys.length === 0) {
647
647
  return {
@@ -658,6 +658,8 @@ export async function sweepWithBundleMerkle(params) {
658
658
  });
659
659
  const isNative = _isNativeTokenAddress(tokenAddress);
660
660
  const txType = getTxType(config);
661
+ // ✅ 如果提供了 targetPrivateKey,创建 targetWallet 用于支付利润
662
+ const targetWallet = targetPrivateKey ? new Wallet(targetPrivateKey, provider) : null;
661
663
  // 归集比例处理
662
664
  const clamp = (n) => (typeof n === 'number' && Number.isFinite(n)
663
665
  ? Math.max(0, Math.min(100, Math.floor(n)))
@@ -787,17 +789,19 @@ export async function sweepWithBundleMerkle(params) {
787
789
  }
788
790
  }
789
791
  }
790
- // ✅ 第二步:生成归集交易(扣除利润后的金额)
792
+ // ✅ 第二步:生成归集交易
793
+ // ✅ 确定利润支付者:优先使用 targetWallet,否则使用归集金额最大的源钱包
794
+ const useTargetAsPayer = targetWallet !== null;
795
+ const profitPayerWallet = useTargetAsPayer ? targetWallet : (maxSweepIndex >= 0 ? wallets[maxSweepIndex] : null);
791
796
  // ✅ 先为支付者预留 nonce,确保 nonce 连续
792
797
  let payerProfitNonce;
793
- if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0) {
794
- const payerWallet = wallets[maxSweepIndex];
795
- const nonces = await nonceManager.getNextNonceBatch(payerWallet, 2);
796
- payerProfitNonce = nonces[1]; // 利润交易的 nonce
798
+ if (extractProfit && totalProfit > 0n && profitPayerWallet) {
799
+ const nonces = await nonceManager.getNextNonceBatch(profitPayerWallet, useTargetAsPayer ? 1 : 2);
800
+ payerProfitNonce = useTargetAsPayer ? nonces[0] : nonces[1]; // targetWallet 只需要 1 个 nonce
797
801
  }
798
802
  // ✅ 优化:批量获取所有钱包的 nonce(JSON-RPC 批量请求)
799
- // 过滤出需要归集的钱包
800
- const walletsToSweep = wallets.filter((_, i) => sweepAmounts[i] > 0n && i !== maxSweepIndex);
803
+ // 过滤出需要归集的钱包(如果用 targetWallet 支付利润,则不排除 maxSweepIndex)
804
+ const walletsToSweep = wallets.filter((_, i) => sweepAmounts[i] > 0n && (useTargetAsPayer || i !== maxSweepIndex));
801
805
  const nonces = walletsToSweep.length > 0
802
806
  ? await nonceManager.getNextNoncesForWallets(walletsToSweep)
803
807
  : [];
@@ -807,8 +811,8 @@ export async function sweepWithBundleMerkle(params) {
807
811
  if (toSend <= 0n)
808
812
  return null;
809
813
  let actualToSend = toSend;
810
- if (extractProfit) {
811
- // ✅ 如果是支付者,扣除所有利润总和;其他钱包不扣利润,归集干净
814
+ if (extractProfit && !useTargetAsPayer) {
815
+ // ✅ 如果由源钱包支付利润,支付者扣除所有利润总和;其他钱包不扣利润,归集干净
812
816
  if (i === maxSweepIndex && totalProfit > 0n) {
813
817
  actualToSend = toSend - totalProfit; // 支付者扣除所有利润总和
814
818
  }
@@ -816,9 +820,10 @@ export async function sweepWithBundleMerkle(params) {
816
820
  actualToSend = toSend; // 其他钱包不扣利润,归集全部
817
821
  }
818
822
  }
823
+ // ✅ 如果由 targetWallet 支付利润,所有源钱包都归集全部金额
819
824
  // ✅ 支付者使用预留的第一个 nonce,其他钱包使用批量获取的 nonce
820
825
  let nonce;
821
- if (i === maxSweepIndex && payerProfitNonce !== undefined) {
826
+ if (!useTargetAsPayer && i === maxSweepIndex && payerProfitNonce !== undefined) {
822
827
  nonce = payerProfitNonce - 1; // 使用预留的第一个 nonce
823
828
  }
824
829
  else {
@@ -838,11 +843,10 @@ export async function sweepWithBundleMerkle(params) {
838
843
  const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
839
844
  signedTxs.push(...allTxs);
840
845
  // ✅ 第三步:利润多跳转账(强制 2 跳中转)
841
- if (extractProfit && totalProfit > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
842
- const payerWallet = wallets[maxSweepIndex];
846
+ if (extractProfit && totalProfit > 0n && profitPayerWallet && payerProfitNonce !== undefined) {
843
847
  const profitHopResult = await buildProfitHopTransactions({
844
848
  provider,
845
- payerWallet,
849
+ payerWallet: profitPayerWallet,
846
850
  profitAmount: totalProfit,
847
851
  profitRecipient: getProfitRecipient(),
848
852
  hopCount: PROFIT_HOP_COUNT,
@@ -926,10 +930,15 @@ export async function sweepWithBundleMerkle(params) {
926
930
  if (extractProfit && totalProfit > 0n) {
927
931
  nativeProfitAmount = await getTokenToNativeQuote(provider, tokenAddress, totalProfit, chainIdNum, tokenPoolType, quoteToken, config.rpcUrl);
928
932
  }
933
+ // ✅ 确定利润支付者:优先使用 targetWallet,否则使用归集金额最大的源钱包
934
+ const useTargetAsPayerErc20 = targetWallet !== null;
935
+ const profitPayerWalletErc20 = useTargetAsPayerErc20 ? targetWallet : (maxSweepIndex >= 0 ? wallets[maxSweepIndex] : null);
929
936
  // ✅ 如果需要提取利润,检查支付者是否有足够 BNB 支付利润转账的额外 gas
930
- if (extractProfit && nativeProfitAmount > 0n && maxSweepIndex >= 0 && config.checkBnbForErc20NoHop) {
931
- const payerBnbBalance = bnbBalances[maxSweepIndex] ?? 0n;
932
- const payerNeedGas = finalGasLimit * gasPrice + profitTxGas + nativeProfitAmount; // 支付者需要 gas + 利润
937
+ if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20 && config.checkBnbForErc20NoHop) {
938
+ const payerBnbBalance = useTargetAsPayerErc20
939
+ ? await provider.getBalance(target)
940
+ : (bnbBalances[maxSweepIndex] ?? 0n);
941
+ const payerNeedGas = (useTargetAsPayerErc20 ? 0n : finalGasLimit * gasPrice) + profitTxGas + nativeProfitAmount;
933
942
  // 如果支付者 BNB 余额不足,跳过利润提取
934
943
  if (payerBnbBalance < payerNeedGas) {
935
944
  nativeProfitAmount = 0n; // 跳过利润提取
@@ -938,14 +947,13 @@ export async function sweepWithBundleMerkle(params) {
938
947
  // ✅ 第二步:生成归集交易(ERC20 归集不扣除代币,利润从 BNB 支付)
939
948
  // ✅ 先为支付者预留 nonce,确保 nonce 连续
940
949
  let payerProfitNonce;
941
- if (extractProfit && nativeProfitAmount > 0n && maxSweepIndex >= 0) {
942
- const payerWallet = wallets[maxSweepIndex];
943
- const nonces = await nonceManager.getNextNonceBatch(payerWallet, 2);
944
- payerProfitNonce = nonces[1]; // 利润交易的 nonce
950
+ if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20) {
951
+ const nonces = await nonceManager.getNextNonceBatch(profitPayerWalletErc20, useTargetAsPayerErc20 ? 1 : 2);
952
+ payerProfitNonce = useTargetAsPayerErc20 ? nonces[0] : nonces[1];
945
953
  }
946
954
  // ✅ 优化:批量获取所有钱包的 nonce(JSON-RPC 批量请求)
947
- // 过滤出需要归集的钱包(排除支付者,因为支付者已经预留了 nonce
948
- const walletsToSweepErc20 = wallets.filter((_, i) => sweepAmounts[i] > 0n && i !== maxSweepIndex);
955
+ // 过滤出需要归集的钱包(如果用 targetWallet 支付利润,则不排除 maxSweepIndex
956
+ const walletsToSweepErc20 = wallets.filter((_, i) => sweepAmounts[i] > 0n && (useTargetAsPayerErc20 || i !== maxSweepIndex));
949
957
  const noncesErc20 = walletsToSweepErc20.length > 0
950
958
  ? await nonceManager.getNextNoncesForWallets(walletsToSweepErc20)
951
959
  : [];
@@ -958,7 +966,7 @@ export async function sweepWithBundleMerkle(params) {
958
966
  const actualToSend = toSend;
959
967
  // ✅ 支付者使用预留的第一个 nonce,其他钱包使用批量获取的 nonce
960
968
  let nonce;
961
- if (i === maxSweepIndex && payerProfitNonce !== undefined) {
969
+ if (!useTargetAsPayerErc20 && i === maxSweepIndex && payerProfitNonce !== undefined) {
962
970
  nonce = payerProfitNonce - 1; // 使用预留的第一个 nonce
963
971
  }
964
972
  else {
@@ -980,12 +988,11 @@ export async function sweepWithBundleMerkle(params) {
980
988
  const allTxs = (await Promise.all(txPromises)).filter(tx => tx !== null);
981
989
  signedTxs.push(...allTxs);
982
990
  // ✅ 第三步:利润多跳转账(强制 2 跳中转)- ERC20 利润转等值原生代币
983
- if (extractProfit && nativeProfitAmount > 0n && maxSweepIndex >= 0 && payerProfitNonce !== undefined) {
984
- const payerWallet = wallets[maxSweepIndex];
991
+ if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20 && payerProfitNonce !== undefined) {
985
992
  totalProfit = nativeProfitAmount; // 更新为原生代币利润
986
993
  const profitHopResult = await buildProfitHopTransactions({
987
994
  provider,
988
- payerWallet,
995
+ payerWallet: profitPayerWalletErc20,
989
996
  profitAmount: nativeProfitAmount,
990
997
  profitRecipient: getProfitRecipient(),
991
998
  hopCount: PROFIT_HOP_COUNT,
@@ -1326,7 +1333,7 @@ export async function sweepWithBundleMerkle(params) {
1326
1333
  }
1327
1334
  // ========== 第7步:计算利润并添加利润转账 ==========
1328
1335
  if (extractProfit && totalAmountBeforeProfit > 0n) {
1329
- // 找出归集金额最大的钱包作为支付者
1336
+ // ✅ 确定利润支付者:优先使用 targetWallet,否则使用归集金额最大的源钱包
1330
1337
  let maxSweepIndex = -1;
1331
1338
  let maxSweepAmount = 0n;
1332
1339
  for (let i = 0; i < sweepAmounts.length; i++) {
@@ -1335,6 +1342,8 @@ export async function sweepWithBundleMerkle(params) {
1335
1342
  maxSweepIndex = i;
1336
1343
  }
1337
1344
  }
1345
+ const useTargetAsPayerHop = targetWallet !== null;
1346
+ const profitPayerWalletHop = useTargetAsPayerHop ? targetWallet : (maxSweepIndex >= 0 ? sourceWallets[maxSweepIndex] : null);
1338
1347
  // 计算总代币利润
1339
1348
  let totalTokenProfit = 0n;
1340
1349
  for (let i = 0; i < sweepAmounts.length; i++) {
@@ -1355,12 +1364,11 @@ export async function sweepWithBundleMerkle(params) {
1355
1364
  totalProfit = nativeProfitAmount;
1356
1365
  }
1357
1366
  // ✅ 利润多跳转账(强制 2 跳中转)
1358
- if (nativeProfitAmount > 0n && maxSweepIndex >= 0) {
1359
- const payerWallet = sourceWallets[maxSweepIndex];
1360
- const profitNonce = await nonceManager.getNextNonce(payerWallet);
1367
+ if (nativeProfitAmount > 0n && profitPayerWalletHop) {
1368
+ const profitNonce = await nonceManager.getNextNonce(profitPayerWalletHop);
1361
1369
  const profitHopResult = await buildProfitHopTransactions({
1362
1370
  provider,
1363
- payerWallet,
1371
+ payerWallet: profitPayerWalletHop,
1364
1372
  profitAmount: nativeProfitAmount,
1365
1373
  profitRecipient: getProfitRecipient(),
1366
1374
  hopCount: PROFIT_HOP_COUNT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.27",
3
+ "version": "1.5.28",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",