four-flap-meme-sdk 1.4.67 → 1.4.68

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.
@@ -105,34 +105,23 @@ export async function fourBundleBuyFirstMerkle(params) {
105
105
  if (buyerFundsWei <= 0n) {
106
106
  throw new Error('buyerFunds 需要大于 0');
107
107
  }
108
- // ✅ 优化:第二批并行 - buyQuote、sellerTokenBal、decimals、allowance
108
+ // ✅ 优化:第二批并行 - buyQuote、sellerTokenBal、decimals
109
109
  const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider);
110
110
  const erc20 = new Contract(tokenAddress, [
111
111
  'function balanceOf(address) view returns (uint256)',
112
- 'function decimals() view returns (uint8)',
113
- 'function allowance(address,address) view returns (uint256)'
112
+ 'function decimals() view returns (uint8)'
114
113
  ], provider);
115
- const [buyQuote, sellerTokenBal, decimals, currentAllowance] = await Promise.all([
114
+ const [buyQuote, sellerTokenBal, decimals] = await Promise.all([
116
115
  helper3.tryBuy(tokenAddress, 0n, buyerFundsWei),
117
116
  erc20.balanceOf(seller.address),
118
- erc20.decimals(),
119
- erc20.allowance(seller.address, TM_ADDRESS)
117
+ erc20.decimals()
120
118
  ]);
121
- // ✅ 检查是否需要授权(授权额度小于 10 亿代币时需要授权)
122
- const APPROVAL_THRESHOLD = ethers.parseUnits('1000000000', decimals);
123
- const needApproval = currentAllowance < APPROVAL_THRESHOLD;
124
119
  const estimatedTokenAmount = buyQuote.estimatedAmount ?? buyQuote[2];
125
120
  if (!estimatedTokenAmount || estimatedTokenAmount <= 0n) {
126
121
  throw new Error('报价失败:无法估算可买入的代币数量');
127
122
  }
128
- // ✅ 多笔买入时减少卖出数量以应对滑点
129
- // 原因:分批买入会推高价格,实际获得的代币 < 一次性买入的报价
130
- // 每多一笔买入,减少 0.5% 的卖出数量(保守估计)
131
- let sellAmountWei = estimatedTokenAmount;
132
- if (buyCount > 1) {
133
- const slippageReductionBps = BigInt((buyCount - 1) * 50); // 每多1笔减少 0.5% = 50 bps
134
- sellAmountWei = estimatedTokenAmount * (10000n - slippageReductionBps) / 10000n;
135
- }
123
+ // ✅ 直接使用报价的代币数量(与 Flap 一致,不做滑点调整)
124
+ const sellAmountWei = estimatedTokenAmount;
136
125
  // 卖方余额检查
137
126
  if (!sameAddress && sellerTokenBal < sellAmountWei) {
138
127
  throw new Error(`卖方代币余额不足: 需要 ${ethers.formatUnits(sellAmountWei, decimals)},实际 ${ethers.formatUnits(sellerTokenBal, decimals)}`);
@@ -151,7 +140,7 @@ export async function fourBundleBuyFirstMerkle(params) {
151
140
  // ✅ 构建多笔买入和卖出交易
152
141
  const buyUnsignedPromises = buyAmountsWei.map(amount => tmBuyer.buyTokenAMAP.populateTransaction(0n, tokenAddress, buyer.address, amount, 0n, { value: amount }));
153
142
  const sellUnsignedPromises = sellAmountsWei.map(amount => tmSeller.sellToken.populateTransaction(0n, tokenAddress, amount, 0n));
154
- // ✅ 规划多笔交易 nonce(包含授权交易)
143
+ // ✅ 规划多笔交易 nonce(与 Flap 一致,不含授权)
155
144
  const multiNoncePlan = await planMultiNonces({
156
145
  buyer,
157
146
  seller,
@@ -159,7 +148,6 @@ export async function fourBundleBuyFirstMerkle(params) {
159
148
  sellCount,
160
149
  extractProfit,
161
150
  needBribeTx,
162
- needApproval, // ✅ 新增
163
151
  sameAddress,
164
152
  nonceManager
165
153
  });
@@ -204,35 +192,16 @@ export async function fourBundleBuyFirstMerkle(params) {
204
192
  type: txType,
205
193
  value: 0n
206
194
  }));
207
- // ✅ 授权交易(放在买入后、卖出前)
208
- let approvalTx = null;
209
- if (needApproval && multiNoncePlan.approvalNonce !== undefined) {
210
- const approveInterface = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
211
- const approveData = approveInterface.encodeFunctionData('approve', [TM_ADDRESS, ethers.MaxUint256]);
212
- approvalTx = await seller.signTransaction({
213
- to: tokenAddress,
214
- data: approveData,
215
- value: 0n,
216
- nonce: multiNoncePlan.approvalNonce,
217
- gasLimit: 80000n,
218
- gasPrice,
219
- chainId: chainIdNum,
220
- type: txType
221
- });
222
- }
223
195
  const [signedBuys, signedSells] = await Promise.all([
224
196
  Promise.all(buySignPromises),
225
197
  Promise.all(sellSignPromises)
226
198
  ]);
227
199
  nonceManager.clearTemp();
228
- // ✅ 组装交易列表:贿赂 → 买入(多笔) → 授权 → 卖出(多笔)
200
+ // ✅ 组装交易列表:贿赂 → 买入(多笔) → 卖出(多笔)(与 Flap 一致)
229
201
  const allTransactions = [];
230
202
  if (bribeTx)
231
203
  allTransactions.push(bribeTx);
232
- allTransactions.push(...signedBuys);
233
- if (approvalTx)
234
- allTransactions.push(approvalTx);
235
- allTransactions.push(...signedSells);
204
+ allTransactions.push(...signedBuys, ...signedSells);
236
205
  // ✅ 利润多跳转账(强制 2 跳中转)
237
206
  let profitHopWallets;
238
207
  if (extractProfit && profitAmount > 0n && multiNoncePlan.profitNonce !== undefined) {
@@ -266,39 +235,38 @@ export async function fourBundleBuyFirstMerkle(params) {
266
235
  };
267
236
  }
268
237
  /**
269
- * ✅ 规划多笔交易 nonce
270
- * 交易顺序:贿赂 → 买入(多笔) → 授权 → 卖出(多笔) → 利润
238
+ * ✅ 规划多笔交易 nonce(与 Flap 一致)
239
+ * 交易顺序:贿赂 → 买入(多笔) → 卖出(多笔) → 利润
271
240
  */
272
- async function planMultiNonces({ buyer, seller, buyCount, sellCount, extractProfit, needBribeTx, needApproval, sameAddress, nonceManager }) {
241
+ async function planMultiNonces({ buyer, seller, buyCount, sellCount, extractProfit, needBribeTx, sameAddress, nonceManager }) {
273
242
  const profitNonceCount = extractProfit ? 1 : 0;
274
- const approvalTxCount = needApproval ? 1 : 0;
275
243
  if (sameAddress) {
276
- // 同地址:贿赂 买入(多笔) 授权 → 卖出(多笔) 利润
244
+ // 同一地址:贿赂(可选) + 买入(多笔) + 卖出(多笔) + 利润(可选)
277
245
  const bribeTxCount = needBribeTx ? 1 : 0;
278
- const totalTxCount = bribeTxCount + buyCount + approvalTxCount + sellCount + profitNonceCount;
246
+ const totalTxCount = bribeTxCount + buyCount + sellCount + profitNonceCount;
279
247
  const nonces = await nonceManager.getNextNonceBatch(buyer, totalTxCount);
280
248
  let idx = 0;
281
249
  const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
282
250
  const buyerNonces = nonces.slice(idx, idx + buyCount);
283
251
  idx += buyCount;
284
- const approvalNonce = needApproval ? nonces[idx++] : undefined;
285
252
  const sellerNonces = nonces.slice(idx, idx + sellCount);
286
253
  idx += sellCount;
287
254
  const profitNonce = extractProfit ? nonces[idx] : undefined;
288
- return { buyerNonces, sellerNonces, bribeNonce, approvalNonce, profitNonce };
255
+ return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
289
256
  }
290
- // 不同地址:买方只负责买入,卖方负责贿赂+授权+卖出+利润
257
+ // 不同地址
258
+ // 买方:buyCount 个 nonce
259
+ // 卖方:贿赂(可选) + sellCount + 利润(可选) 个 nonce
291
260
  const bribeTxCount = needBribeTx ? 1 : 0;
292
- const sellerTxCount = bribeTxCount + approvalTxCount + sellCount + profitNonceCount;
261
+ const sellerTxCount = bribeTxCount + sellCount + profitNonceCount;
293
262
  const [buyerNonces, sellerNoncesAll] = await Promise.all([
294
263
  nonceManager.getNextNonceBatch(buyer, buyCount),
295
264
  nonceManager.getNextNonceBatch(seller, sellerTxCount)
296
265
  ]);
297
266
  let idx = 0;
298
267
  const bribeNonce = needBribeTx ? sellerNoncesAll[idx++] : undefined;
299
- const approvalNonce = needApproval ? sellerNoncesAll[idx++] : undefined;
300
268
  const sellerNonces = sellerNoncesAll.slice(idx, idx + sellCount);
301
269
  idx += sellCount;
302
270
  const profitNonce = extractProfit ? sellerNoncesAll[idx] : undefined;
303
- return { buyerNonces, sellerNonces, bribeNonce, approvalNonce, profitNonce };
271
+ return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
304
272
  }
@@ -121,31 +121,10 @@ export async function pancakeBundleBuyFirstMerkle(params) {
121
121
  buyerFundsWei: buyerFundsInfo.buyerFundsWei,
122
122
  provider: context.provider
123
123
  });
124
- // ✅ 检查是否需要授权(卖出代币需要先授权给 Router)
125
- const approvalTarget = routeParams.routeType === 'v2'
126
- ? PANCAKE_V2_ROUTER_ADDRESS
127
- : PANCAKE_V3_ROUTER_ADDRESS;
128
- const erc20ForApproval = new Contract(tokenAddress, [
129
- 'function allowance(address,address) view returns (uint256)',
130
- 'function decimals() view returns (uint8)'
131
- ], context.provider);
132
- const [currentAllowance, tokenDecimals] = await Promise.all([
133
- erc20ForApproval.allowance(seller.address, approvalTarget),
134
- erc20ForApproval.decimals()
135
- ]);
136
- const APPROVAL_THRESHOLD = ethers.parseUnits('1000000000', tokenDecimals);
137
- const needApproval = currentAllowance < APPROVAL_THRESHOLD;
138
- // ✅ 多笔买入时减少卖出数量以应对滑点
139
- // 原因:分批买入会推高价格,实际获得的代币 < 一次性买入的报价
140
- // 每多一笔买入,减少 0.5% 的卖出数量(保守估计)
141
- let adjustedSellAmount = quoteResult.quotedTokenOut;
142
- if (buyCount > 1) {
143
- const slippageReductionBps = BigInt((buyCount - 1) * 50); // 每多1笔减少 0.5% = 50 bps
144
- adjustedSellAmount = quoteResult.quotedTokenOut * (10000n - slippageReductionBps) / 10000n;
145
- }
124
+ // ✅ 直接使用报价的代币数量(与 Flap 一致,不做滑点调整)
146
125
  // ✅ 拆分买入和卖出金额
147
126
  const buyAmountsWei = splitAmount(buyerFundsInfo.buyerFundsWei, buyCount);
148
- const sellAmountsWei = splitAmount(adjustedSellAmount, sellCount);
127
+ const sellAmountsWei = splitAmount(quoteResult.quotedTokenOut, sellCount);
149
128
  // ✅ 构建多笔买入和卖出交易
150
129
  const swapUnsignedArray = await buildMultiRouteTransactions({
151
130
  routeParams,
@@ -195,7 +174,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
195
174
  sameAddress,
196
175
  extractProfit: profitAmount > 0n,
197
176
  needBribeTx,
198
- needApproval, // ✅ 新增
199
177
  nonceManager
200
178
  });
201
179
  // ✅ 贿赂交易放在首位(由卖方发送,与利润交易同一钱包)
@@ -221,22 +199,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
221
199
  chainId: context.chainId,
222
200
  type: txType
223
201
  })));
224
- // ✅ 授权交易(放在买入后、卖出前)
225
- let approvalTx = null;
226
- if (needApproval && multiNoncePlan.approvalNonce !== undefined) {
227
- const approveInterface = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
228
- const approveData = approveInterface.encodeFunctionData('approve', [approvalTarget, ethers.MaxUint256]);
229
- approvalTx = await seller.signTransaction({
230
- to: tokenAddress,
231
- data: approveData,
232
- value: 0n,
233
- nonce: multiNoncePlan.approvalNonce,
234
- gasLimit: 80000n,
235
- gasPrice,
236
- chainId: context.chainId,
237
- type: txType
238
- });
239
- }
240
202
  // ✅ 并行签名所有卖出交易
241
203
  const signedSells = await Promise.all(swapUnsignedArray.sellUnsignedArray.map((unsigned, i) => seller.signTransaction({
242
204
  ...unsigned,
@@ -260,14 +222,11 @@ export async function pancakeBundleBuyFirstMerkle(params) {
260
222
  provider: context.provider,
261
223
  buyerAddress: buyer.address
262
224
  });
263
- // ✅ 组装顺序:贿赂 → 买入(多笔) → 授权 → 卖出(多笔)
225
+ // ✅ 组装顺序:贿赂 → 买入(多笔) → 卖出(多笔)(与 Flap 一致)
264
226
  const allTransactions = [];
265
227
  if (bribeTx)
266
228
  allTransactions.push(bribeTx);
267
- allTransactions.push(...signedBuys);
268
- if (approvalTx)
269
- allTransactions.push(approvalTx);
270
- allTransactions.push(...signedSells);
229
+ allTransactions.push(...signedBuys, ...signedSells);
271
230
  // ✅ 利润多跳转账(强制 2 跳中转)
272
231
  const profitResult = await buildProfitTransaction({
273
232
  provider: context.provider,
@@ -577,42 +536,40 @@ async function planNonces({ buyer, seller, sameAddress, extractProfit, needBribe
577
536
  return { buyerNonce, sellerNonce };
578
537
  }
579
538
  /**
580
- * ✅ 规划多笔交易 nonce
581
- * 交易顺序:贿赂 → 买入(多笔) → 授权 → 卖出(多笔) → 利润
539
+ * ✅ 规划多笔交易 nonce(与 Flap 一致)
540
+ * 交易顺序:贿赂 → 买入(多笔) → 卖出(多笔) → 利润
582
541
  */
583
- async function planMultiNonces({ buyer, seller, buyCount, sellCount, sameAddress, extractProfit, needBribeTx, needApproval, // ✅ 新增
584
- nonceManager }) {
542
+ async function planMultiNonces({ buyer, seller, buyCount, sellCount, sameAddress, extractProfit, needBribeTx, nonceManager }) {
585
543
  const profitNonceCount = extractProfit ? 1 : 0;
586
- const approvalTxCount = needApproval ? 1 : 0;
587
544
  if (sameAddress) {
588
- // 同地址:贿赂 买入(多笔) 授权 → 卖出(多笔) 利润
545
+ // 同一地址:贿赂(可选) + 买入(多笔) + 卖出(多笔) + 利润(可选)
589
546
  const bribeTxCount = needBribeTx ? 1 : 0;
590
- const totalTxCount = bribeTxCount + buyCount + approvalTxCount + sellCount + profitNonceCount;
547
+ const totalTxCount = bribeTxCount + buyCount + sellCount + profitNonceCount;
591
548
  const nonces = await nonceManager.getNextNonceBatch(buyer, totalTxCount);
592
549
  let idx = 0;
593
550
  const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
594
551
  const buyerNonces = nonces.slice(idx, idx + buyCount);
595
552
  idx += buyCount;
596
- const approvalNonce = needApproval ? nonces[idx++] : undefined;
597
553
  const sellerNonces = nonces.slice(idx, idx + sellCount);
598
554
  idx += sellCount;
599
555
  const profitNonce = extractProfit ? nonces[idx] : undefined;
600
- return { buyerNonces, sellerNonces, bribeNonce, approvalNonce, profitNonce };
556
+ return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
601
557
  }
602
- // 不同地址:买方只负责买入,卖方负责贿赂+授权+卖出+利润
558
+ // 不同地址
559
+ // 买方:buyCount 个 nonce
560
+ // 卖方:贿赂(可选) + sellCount + 利润(可选) 个 nonce
603
561
  const bribeTxCount = needBribeTx ? 1 : 0;
604
- const sellerTxCount = bribeTxCount + approvalTxCount + sellCount + profitNonceCount;
562
+ const sellerTxCount = bribeTxCount + sellCount + profitNonceCount;
605
563
  const [buyerNonces, sellerNoncesAll] = await Promise.all([
606
564
  nonceManager.getNextNonceBatch(buyer, buyCount),
607
565
  nonceManager.getNextNonceBatch(seller, sellerTxCount)
608
566
  ]);
609
567
  let idx = 0;
610
568
  const bribeNonce = needBribeTx ? sellerNoncesAll[idx++] : undefined;
611
- const approvalNonce = needApproval ? sellerNoncesAll[idx++] : undefined;
612
569
  const sellerNonces = sellerNoncesAll.slice(idx, idx + sellCount);
613
570
  idx += sellCount;
614
571
  const profitNonce = extractProfit ? sellerNoncesAll[idx] : undefined;
615
- return { buyerNonces, sellerNonces, bribeNonce, approvalNonce, profitNonce };
572
+ return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
616
573
  }
617
574
  /**
618
575
  * 构建利润多跳转账交易(强制 2 跳中转)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.67",
3
+ "version": "1.4.68",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",