four-flap-meme-sdk 1.4.55 → 1.4.57

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.
@@ -8,8 +8,176 @@ import { calculateSellAmount } from '../../utils/swap-helpers.js';
8
8
  import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../utils/bundle-helpers.js';
9
9
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
10
10
  import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
11
- import { ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
11
+ import { ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI, ERC20_BALANCE_ABI, ERC20_ABI } from '../../abis/common.js';
12
12
  import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
13
+ import { generateWallets } from '../../utils/wallet.js';
14
+ // ==================== 多跳转账常量 ====================
15
+ const NATIVE_TRANSFER_GAS_LIMIT = 21055n;
16
+ const ERC20_TRANSFER_GAS_LIMIT_HOP = 65000n;
17
+ /**
18
+ * 生成分发多跳路径
19
+ */
20
+ function generateDisperseHopPaths(targetAddresses, hopCount, provider) {
21
+ if (hopCount <= 0) {
22
+ return targetAddresses.map(addr => ({
23
+ targetAddress: addr,
24
+ hopWallets: [],
25
+ hopWalletsInfo: []
26
+ }));
27
+ }
28
+ return targetAddresses.map(targetAddress => {
29
+ const hopWalletsInfo = generateWallets(hopCount);
30
+ const hopWallets = hopWalletsInfo.map(w => new Wallet(w.privateKey, provider));
31
+ return { targetAddress, hopWallets, hopWalletsInfo };
32
+ });
33
+ }
34
+ /**
35
+ * 构建原生代币多跳转账链
36
+ */
37
+ async function buildNativeHopChain(payer, path, finalAmount, gasPrice, chainId, txType, payerNonce) {
38
+ const signedTxs = [];
39
+ const hopCount = path.hopWallets.length;
40
+ if (hopCount === 0) {
41
+ signedTxs.push(await payer.signTransaction({
42
+ to: path.targetAddress,
43
+ value: finalAmount,
44
+ nonce: payerNonce,
45
+ gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
46
+ gasPrice,
47
+ chainId,
48
+ type: txType
49
+ }));
50
+ return signedTxs;
51
+ }
52
+ const hopGasCost = NATIVE_TRANSFER_GAS_LIMIT * gasPrice;
53
+ // 计算每跳需要的金额
54
+ const amountsPerHop = [];
55
+ for (let i = 0; i < hopCount; i++) {
56
+ const remainingHops = hopCount - i;
57
+ amountsPerHop.push(finalAmount + hopGasCost * BigInt(remainingHops));
58
+ }
59
+ // payer → hop1
60
+ signedTxs.push(await payer.signTransaction({
61
+ to: path.hopWallets[0].address,
62
+ value: amountsPerHop[0],
63
+ nonce: payerNonce,
64
+ gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
65
+ gasPrice,
66
+ chainId,
67
+ type: txType
68
+ }));
69
+ // hop1 → hop2 → ... → target
70
+ for (let i = 0; i < hopCount; i++) {
71
+ const fromWallet = path.hopWallets[i];
72
+ const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
73
+ const amount = i === hopCount - 1 ? finalAmount : amountsPerHop[i + 1];
74
+ signedTxs.push(await fromWallet.signTransaction({
75
+ to: toAddress,
76
+ value: amount,
77
+ nonce: 0,
78
+ gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
79
+ gasPrice,
80
+ chainId,
81
+ type: txType
82
+ }));
83
+ }
84
+ return signedTxs;
85
+ }
86
+ /**
87
+ * 构建 ERC20 多跳转账链
88
+ */
89
+ async function buildERC20HopChain(payer, path, erc20Address, erc20Amount, gasPrice, chainId, txType, payerNonce) {
90
+ const signedTxs = [];
91
+ const hopCount = path.hopWallets.length;
92
+ const erc20Interface = new ethers.Interface(ERC20_ABI);
93
+ if (hopCount === 0) {
94
+ const data = erc20Interface.encodeFunctionData('transfer', [path.targetAddress, erc20Amount]);
95
+ signedTxs.push(await payer.signTransaction({
96
+ to: erc20Address,
97
+ data,
98
+ value: 0n,
99
+ nonce: payerNonce,
100
+ gasLimit: ERC20_TRANSFER_GAS_LIMIT_HOP,
101
+ gasPrice,
102
+ chainId,
103
+ type: txType
104
+ }));
105
+ return signedTxs;
106
+ }
107
+ // payer → hop1
108
+ const firstData = erc20Interface.encodeFunctionData('transfer', [path.hopWallets[0].address, erc20Amount]);
109
+ signedTxs.push(await payer.signTransaction({
110
+ to: erc20Address,
111
+ data: firstData,
112
+ value: 0n,
113
+ nonce: payerNonce,
114
+ gasLimit: ERC20_TRANSFER_GAS_LIMIT_HOP,
115
+ gasPrice,
116
+ chainId,
117
+ type: txType
118
+ }));
119
+ // hop1 → hop2 → ... → target (nonce=1,nonce=0 用于 BNB 转发)
120
+ for (let i = 0; i < hopCount; i++) {
121
+ const fromWallet = path.hopWallets[i];
122
+ const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
123
+ const data = erc20Interface.encodeFunctionData('transfer', [toAddress, erc20Amount]);
124
+ signedTxs.push(await fromWallet.signTransaction({
125
+ to: erc20Address,
126
+ data,
127
+ value: 0n,
128
+ nonce: 1, // nonce=0 已用于 BNB 转发
129
+ gasLimit: ERC20_TRANSFER_GAS_LIMIT_HOP,
130
+ gasPrice,
131
+ chainId,
132
+ type: txType
133
+ }));
134
+ }
135
+ return signedTxs;
136
+ }
137
+ /**
138
+ * 构建 BNB 多跳转账链(为 ERC20 中间钱包预留 gas)
139
+ */
140
+ async function buildBNBHopChainForERC20(payer, path, finalGasAmount, gasPrice, chainId, txType, payerNonce) {
141
+ const signedTxs = [];
142
+ const hopCount = path.hopWallets.length;
143
+ if (hopCount === 0) {
144
+ return signedTxs;
145
+ }
146
+ const hopGasCost = NATIVE_TRANSFER_GAS_LIMIT * gasPrice;
147
+ const erc20GasCost = ERC20_TRANSFER_GAS_LIMIT_HOP * gasPrice;
148
+ const gasPerHop = hopGasCost + erc20GasCost * 2n;
149
+ const amountsPerHop = [];
150
+ for (let i = 0; i < hopCount; i++) {
151
+ const remainingHops = hopCount - i;
152
+ amountsPerHop.push(finalGasAmount + gasPerHop * BigInt(remainingHops));
153
+ }
154
+ // payer → hop1
155
+ signedTxs.push(await payer.signTransaction({
156
+ to: path.hopWallets[0].address,
157
+ value: amountsPerHop[0],
158
+ nonce: payerNonce,
159
+ gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
160
+ gasPrice,
161
+ chainId,
162
+ type: txType
163
+ }));
164
+ // hop1 → hop2 → ... → target (nonce=0)
165
+ for (let i = 0; i < hopCount; i++) {
166
+ const fromWallet = path.hopWallets[i];
167
+ const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
168
+ const amount = i === hopCount - 1 ? finalGasAmount : amountsPerHop[i + 1];
169
+ signedTxs.push(await fromWallet.signTransaction({
170
+ to: toAddress,
171
+ value: amount,
172
+ nonce: 0,
173
+ gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
174
+ gasPrice,
175
+ chainId,
176
+ type: txType
177
+ }));
178
+ }
179
+ return signedTxs;
180
+ }
13
181
  /**
14
182
  * 获取 Gas Limit
15
183
  */
@@ -696,28 +864,44 @@ export async function flapBatchSwapMerkle(params) {
696
864
  /**
697
865
  * Flap 内盘快捷批量换手(资金利用率模式)
698
866
  *
699
- * 流程:[贿赂] → [卖出] → [转账1, 转账2, ...] → [买入1, 买入2, ...] → [利润]
867
+ * 流程:[贿赂] → [卖出] → [转账多跳...] → [买入1, 买入2, ...] → [利润]
700
868
  *
701
869
  * 特点:
702
870
  * - 子钱包不需要预先有余额
703
871
  * - 资金来自主钱包卖出代币所得
704
872
  * - 提升资金利用率
705
873
  * - 支持原生代币(BNB/OKB/ETH)和 ERC20(如 USDT)两种模式
874
+ * - ✅ 支持转账多跳,隐藏资金流向
706
875
  *
707
- * 限制:最多 23 个买方(2N + 3 ≤ 50)
876
+ * 限制:根据多跳数动态计算最大买方数量
708
877
  */
709
878
  export async function flapQuickBatchSwapMerkle(params) {
710
- const { chain, sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerRatios, buyerAmounts, tokenAddress, config, quoteToken, quoteTokenDecimals = 18, startNonces // ✅ 可选:前端预获取的 nonces
879
+ const { chain, sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerRatios, buyerAmounts, tokenAddress, config, quoteToken, quoteTokenDecimals = 18, disperseHopCount = 0, // ✅ 转账多跳数(默认0=直接转账)
880
+ startNonces // ✅ 可选:前端预获取的 nonces
711
881
  } = params;
712
- // ✅ 校验买方数量
713
- // BNB 模式:贿赂(1) + 卖出(1) + 转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
714
- // ERC20 模式:贿赂(1) + 卖出(1) + ERC20转账(N) + 买入(N) + 利润(1) ≤ 50 → 2N + 3 ≤ 50 → N ≤ 23
715
- const MAX_BUYERS = 23;
882
+ // ✅ 判断是否使用原生代币
883
+ const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
884
+ // 动态计算最大买方数量(根据多跳数)
885
+ // 固定开销: 贿赂(1) + 卖出(1) + 利润多跳(PROFIT_HOP_COUNT + 1)
886
+ const fixedOverhead = 1 + 1 + PROFIT_HOP_COUNT + 1;
887
+ const maxTxs = 50 - fixedOverhead;
888
+ let MAX_BUYERS;
889
+ if (useNativeToken) {
890
+ // 原生代币模式: N*(H+2) <= maxTxs
891
+ MAX_BUYERS = Math.floor(maxTxs / (disperseHopCount + 2));
892
+ }
893
+ else {
894
+ // ERC20 模式: N*(2H+3) <= maxTxs
895
+ MAX_BUYERS = Math.floor(maxTxs / (2 * disperseHopCount + 3));
896
+ }
897
+ MAX_BUYERS = Math.max(1, MAX_BUYERS);
898
+ console.log(`[flapQuickBatchSwapMerkle] 多跳数: ${disperseHopCount}, 最大买方数: ${MAX_BUYERS}`);
716
899
  if (buyerPrivateKeys.length === 0) {
717
900
  throw new Error('至少需要一个买方钱包');
718
901
  }
719
902
  if (buyerPrivateKeys.length > MAX_BUYERS) {
720
- throw new Error(`资金利用率模式买方钱包数量超过限制: ${buyerPrivateKeys.length} > ${MAX_BUYERS}`);
903
+ const mode = useNativeToken ? '原生代币' : 'ERC20';
904
+ throw new Error(`资金利用率模式(${mode}, ${disperseHopCount}跳)买方钱包数量超过限制: ${buyerPrivateKeys.length} > ${MAX_BUYERS}`);
721
905
  }
722
906
  // ✅ 校验分配模式
723
907
  if (!buyerRatios && !buyerAmounts) {
@@ -729,8 +913,6 @@ export async function flapQuickBatchSwapMerkle(params) {
729
913
  if (buyerAmounts && buyerAmounts.length !== buyerPrivateKeys.length) {
730
914
  throw new Error(`buyerAmounts 长度 (${buyerAmounts.length}) 与 buyerPrivateKeys 长度 (${buyerPrivateKeys.length}) 不匹配`);
731
915
  }
732
- // ✅ 判断是否使用原生代币
733
- const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
734
916
  const outputToken = useNativeToken ? ZERO_ADDRESS : quoteToken;
735
917
  const ERC20_TRANSFER_GAS = 65000n;
736
918
  const chainContext = createChainContext(chain, config);
@@ -856,51 +1038,88 @@ export async function flapQuickBatchSwapMerkle(params) {
856
1038
  });
857
1039
  const signedSell = await seller.signTransaction(sellTx);
858
1040
  console.log(`[flapQuickBatchSwapMerkle] 卖出交易已签名`);
859
- // ==================== 3. 转账交易(并行签名)====================
1041
+ // ==================== 3. 转账交易(支持多跳)====================
860
1042
  const reserveGas = ethers.parseEther((config.reserveGasETH || 0.0005).toString());
861
1043
  const buyerGasCost = gasPrice * finalGasLimit;
862
- // ✅ 预分配 nonce,然后并行签名
863
- const transferNonces = buyers.map((_, i) => sellerNonce + i);
864
- sellerNonce += buyers.length; // 更新 sellerNonce
865
- let transferTxs;
866
- if (useNativeToken) {
867
- // 原生代币模式:直接转账(并行签名)
868
- transferTxs = await Promise.all(buyers.map((buyer, i) => {
869
- const transferValue = transferAmountsWei[i] + reserveGas + buyerGasCost;
870
- return seller.signTransaction({
871
- to: buyer.address,
872
- value: transferValue,
873
- nonce: transferNonces[i],
874
- gasPrice,
875
- gasLimit: 21000n,
876
- chainId: chainContext.chainId,
877
- type: txType
878
- });
879
- }));
1044
+ // ✅ 生成多跳路径
1045
+ const hopPaths = generateDisperseHopPaths(buyers.map(b => b.address), disperseHopCount, chainContext.provider);
1046
+ // 收集所有中间钱包信息
1047
+ const allHopWallets = [];
1048
+ hopPaths.forEach(path => {
1049
+ allHopWallets.push(...path.hopWalletsInfo);
1050
+ });
1051
+ let transferTxs = [];
1052
+ if (disperseHopCount === 0) {
1053
+ // ✅ 无多跳:直接转账
1054
+ const transferNonces = buyers.map((_, i) => sellerNonce + i);
1055
+ sellerNonce += buyers.length;
1056
+ if (useNativeToken) {
1057
+ transferTxs = await Promise.all(buyers.map((buyer, i) => {
1058
+ const transferValue = transferAmountsWei[i] + reserveGas + buyerGasCost;
1059
+ return seller.signTransaction({
1060
+ to: buyer.address,
1061
+ value: transferValue,
1062
+ nonce: transferNonces[i],
1063
+ gasPrice,
1064
+ gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
1065
+ chainId: chainContext.chainId,
1066
+ type: txType
1067
+ });
1068
+ }));
1069
+ }
1070
+ else {
1071
+ const erc20Interface = new ethers.Interface(ERC20_ABI);
1072
+ transferTxs = await Promise.all(buyers.map((buyer, i) => {
1073
+ const transferData = erc20Interface.encodeFunctionData('transfer', [
1074
+ buyer.address,
1075
+ transferAmountsWei[i]
1076
+ ]);
1077
+ return seller.signTransaction({
1078
+ to: quoteToken,
1079
+ data: transferData,
1080
+ value: 0n,
1081
+ nonce: transferNonces[i],
1082
+ gasPrice,
1083
+ gasLimit: ERC20_TRANSFER_GAS,
1084
+ chainId: chainContext.chainId,
1085
+ type: txType
1086
+ });
1087
+ }));
1088
+ }
880
1089
  }
881
1090
  else {
882
- // ERC20 模式:ERC20 transfer(并行签名)
883
- const erc20Interface = new ethers.Interface([
884
- 'function transfer(address to, uint256 amount) returns (bool)'
885
- ]);
886
- transferTxs = await Promise.all(buyers.map((buyer, i) => {
887
- const transferData = erc20Interface.encodeFunctionData('transfer', [
888
- buyer.address,
889
- transferAmountsWei[i]
890
- ]);
891
- return seller.signTransaction({
892
- to: quoteToken,
893
- data: transferData,
894
- value: 0n,
895
- nonce: transferNonces[i],
896
- gasPrice,
897
- gasLimit: ERC20_TRANSFER_GAS,
898
- chainId: chainContext.chainId,
899
- type: txType
900
- });
901
- }));
1091
+ // 有多跳:构建多跳转账链
1092
+ if (useNativeToken) {
1093
+ // 原生代币多跳转账
1094
+ const hopChains = await Promise.all(hopPaths.map((path, i) => {
1095
+ const finalAmount = transferAmountsWei[i] + reserveGas + buyerGasCost;
1096
+ const payerNonce = sellerNonce + i * (disperseHopCount + 1);
1097
+ return buildNativeHopChain(seller, path, finalAmount, gasPrice, chainContext.chainId, txType, payerNonce);
1098
+ }));
1099
+ transferTxs = hopChains.flat();
1100
+ sellerNonce += buyers.length * (disperseHopCount + 1);
1101
+ }
1102
+ else {
1103
+ // ERC20 多跳转账:先转 BNB(给中间钱包 gas),再转 ERC20
1104
+ // 1. 构建 BNB 多跳链
1105
+ const bnbHopChains = await Promise.all(hopPaths.map((path, i) => {
1106
+ const finalGasAmount = buyerGasCost;
1107
+ const payerNonce = sellerNonce + i * (disperseHopCount + 1);
1108
+ return buildBNBHopChainForERC20(seller, path, finalGasAmount, gasPrice, chainContext.chainId, txType, payerNonce);
1109
+ }));
1110
+ const bnbTxs = bnbHopChains.flat();
1111
+ sellerNonce += buyers.length * (disperseHopCount + 1);
1112
+ // 2. 构建 ERC20 多跳链
1113
+ const erc20HopChains = await Promise.all(hopPaths.map((path, i) => {
1114
+ const payerNonce = sellerNonce + i * (disperseHopCount + 1);
1115
+ return buildERC20HopChain(seller, path, quoteToken, transferAmountsWei[i], gasPrice, chainContext.chainId, txType, payerNonce);
1116
+ }));
1117
+ const erc20Txs = erc20HopChains.flat();
1118
+ sellerNonce += buyers.length * (disperseHopCount + 1);
1119
+ transferTxs = [...bnbTxs, ...erc20Txs];
1120
+ }
902
1121
  }
903
- console.log(`[flapQuickBatchSwapMerkle] ${transferTxs.length} 笔转账交易已签名`);
1122
+ console.log(`[flapQuickBatchSwapMerkle] ${transferTxs.length} 笔转账交易已签名 (多跳数=${disperseHopCount})`);
904
1123
  // ==================== 4. 买入交易 ====================
905
1124
  // ✅ 如果前端传入了 startNonces,使用 buyer 部分(从索引 1 开始)
906
1125
  const buyerNonces = startNonces && startNonces.length > 1
@@ -960,6 +1179,7 @@ export async function flapQuickBatchSwapMerkle(params) {
960
1179
  console.log(` - 利润多跳: ${nativeProfitAmount > 0n ? PROFIT_HOP_COUNT + 1 : 0}`);
961
1180
  return {
962
1181
  signedTransactions,
1182
+ disperseHopWallets: allHopWallets.length > 0 ? allHopWallets : undefined, // ✅ 返回中间钱包信息
963
1183
  metadata: {
964
1184
  sellerAddress: seller.address,
965
1185
  buyerAddresses: buyers.map(b => b.address),
@@ -971,7 +1191,8 @@ export async function flapQuickBatchSwapMerkle(params) {
971
1191
  ? ethers.formatEther(amt)
972
1192
  : ethers.formatUnits(amt, quoteTokenDecimals)),
973
1193
  profitAmount: nativeProfitAmount > 0n ? ethers.formatEther(nativeProfitAmount) : undefined,
974
- useNativeToken
1194
+ useNativeToken,
1195
+ disperseHopCount: disperseHopCount > 0 ? disperseHopCount : undefined // ✅ 返回多跳数
975
1196
  }
976
1197
  };
977
1198
  }
@@ -1,4 +1,5 @@
1
1
  import { CommonBundleConfig } from '../utils/bundle-helpers.js';
2
+ import { type GeneratedWallet } from '../utils/wallet.js';
2
3
  export interface PancakeSwapSignConfig {
3
4
  rpcUrl: string;
4
5
  gasLimit?: number | bigint;
@@ -129,6 +130,7 @@ export interface PancakeQuickBatchSwapParams {
129
130
  config: PancakeSwapSignConfig;
130
131
  quoteToken?: string;
131
132
  quoteTokenDecimals?: number;
133
+ disperseHopCount?: number;
132
134
  startNonces?: number[];
133
135
  }
134
136
  /**
@@ -136,6 +138,7 @@ export interface PancakeQuickBatchSwapParams {
136
138
  */
137
139
  export interface PancakeQuickBatchSwapResult {
138
140
  signedTransactions: string[];
141
+ disperseHopWallets?: GeneratedWallet[];
139
142
  metadata?: {
140
143
  sellerAddress: string;
141
144
  buyerAddresses: string[];
@@ -144,19 +147,21 @@ export interface PancakeQuickBatchSwapResult {
144
147
  transferAmounts: string[];
145
148
  profitAmount?: string;
146
149
  useNativeToken: boolean;
150
+ disperseHopCount?: number;
147
151
  };
148
152
  }
149
153
  /**
150
154
  * PancakeSwap 快捷批量换手(资金自动流转)
151
155
  *
152
- * 流程:[贿赂] → [卖出] → [转账1, 转账2, ...] → [买入1, 买入2, ...] → [利润]
156
+ * 流程:[贿赂] → [卖出] → [转账多跳...] → [买入1, 买入2, ...] → [利润]
153
157
  *
154
158
  * 特点:
155
159
  * - 子钱包不需要预先有余额
156
160
  * - 资金来自主钱包卖出代币所得
157
161
  * - 提升资金利用率
158
162
  * - 支持 BNB 和 ERC20(如 USDT)两种模式
163
+ * - ✅ 支持转账多跳,隐藏资金流向
159
164
  *
160
- * 限制:最多 23 个买方(转账 + 买入 = 46 笔,加上贿赂/卖出/利润 = 50 笔限制)
165
+ * 限制:根据多跳数动态计算最大买方数量
161
166
  */
162
167
  export declare function pancakeQuickBatchSwapMerkle(params: PancakeQuickBatchSwapParams): Promise<PancakeQuickBatchSwapResult>;