four-flap-meme-sdk 1.4.29 → 1.4.30

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.
@@ -14,7 +14,6 @@ export interface PancakeBuyFirstSignConfig {
14
14
  chainId?: number;
15
15
  reserveGasBNB?: number;
16
16
  skipQuoteOnError?: boolean;
17
- skipApprovalCheck?: boolean;
18
17
  bribeAmount?: number;
19
18
  }
20
19
  export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
@@ -43,7 +42,6 @@ export interface PancakeBuyFirstConfig extends CommonBundleConfig {
43
42
  reserveGasBNB?: number;
44
43
  waitForConfirmation?: boolean;
45
44
  waitTimeoutMs?: number;
46
- skipApprovalCheck?: boolean;
47
45
  }
48
46
  export interface PancakeBundleBuyFirstSignParams {
49
47
  buyerPrivateKey: string;
@@ -74,7 +72,6 @@ export type PancakeBuyFirstResult = {
74
72
  sellerAddress: string;
75
73
  buyAmount: string;
76
74
  sellAmount: string;
77
- hasApproval?: boolean;
78
75
  profitAmount?: string;
79
76
  };
80
77
  };
@@ -7,7 +7,7 @@ import { ethers, Contract, Wallet } from 'ethers';
7
7
  import { NonceManager, getDeadline } from '../utils/bundle-helpers.js';
8
8
  import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA, ZERO_ADDRESS } from '../utils/constants.js';
9
9
  import { quoteV2, quoteV3, getTokenToNativeQuote, getWrappedNativeAddress } from '../utils/quote-helpers.js';
10
- import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI } from '../abis/common.js';
10
+ import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI } from '../abis/common.js';
11
11
  /**
12
12
  * 获取 Gas Limit
13
13
  */
@@ -44,8 +44,6 @@ const PANCAKE_V3_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV3Router;
44
44
  // 常量
45
45
  const FLAT_FEE = 0n;
46
46
  const WBNB_ADDRESS = ADDRESSES.BSC.WBNB;
47
- // ✅ getDeadline 从 bundle-helpers.js 导入
48
- const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
49
47
  export async function pancakeBundleBuyFirstMerkle(params) {
50
48
  const { buyerPrivateKey, sellerPrivateKey, tokenAddress, routeParams, buyerFunds, buyerFundsPercentage, config, quoteToken, quoteTokenDecimals = 18, startNonces // ✅ 可选:前端预获取的 nonces
51
49
  } = params;
@@ -70,7 +68,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
70
68
  buyerFundsWei: buyerFundsInfo.buyerFundsWei,
71
69
  provider: context.provider
72
70
  });
73
- const decimals = await getTokenDecimals(context.provider, tokenAddress);
74
71
  const swapUnsigned = await buildRouteTransactions({
75
72
  routeParams,
76
73
  buyerFundsWei: buyerFundsInfo.buyerFundsWei,
@@ -95,17 +92,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
95
92
  const gasPrice = await getGasPrice(context.provider, config);
96
93
  const txType = config.txType ?? 0;
97
94
  const nonceManager = new NonceManager(context.provider);
98
- const approvalTx = await ensureSellerApproval({
99
- tokenAddress,
100
- seller,
101
- provider: context.provider,
102
- decimals,
103
- chainId: context.chainId,
104
- config,
105
- nonceManager,
106
- gasPrice,
107
- txType
108
- });
109
95
  // ✅ 修复:基于买入金额估算利润,而不是基于卖出预估(因为代币可能还没有流动性)
110
96
  // 在先买后卖的场景中,卖出收益 ≈ 买入金额(忽略滑点和手续费)
111
97
  const estimatedProfitFromSell = await estimateProfitAmount({
@@ -124,12 +110,11 @@ export async function pancakeBundleBuyFirstMerkle(params) {
124
110
  const needBribeTx = bribeAmount > 0n;
125
111
  // ✅ 如果前端传入了 startNonces,直接使用(性能优化,避免 nonce 冲突)
126
112
  const noncePlan = startNonces && startNonces.length >= (sameAddress ? 1 : 2)
127
- ? buildNoncePlanFromStartNonces(startNonces, sameAddress, !!approvalTx, profitAmount > 0n, needBribeTx)
113
+ ? buildNoncePlanFromStartNonces(startNonces, sameAddress, profitAmount > 0n, needBribeTx)
128
114
  : await planNonces({
129
115
  buyer,
130
116
  seller,
131
117
  sameAddress,
132
- approvalExists: !!approvalTx,
133
118
  extractProfit: profitAmount > 0n,
134
119
  needBribeTx,
135
120
  nonceManager
@@ -187,12 +172,10 @@ export async function pancakeBundleBuyFirstMerkle(params) {
187
172
  provider: context.provider,
188
173
  buyerAddress: buyer.address
189
174
  });
190
- // ✅ 组装顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
175
+ // ✅ 组装顺序:贿赂 → 买入 → 卖出 → 利润
191
176
  const allTransactions = [];
192
177
  if (bribeTx)
193
178
  allTransactions.push(bribeTx);
194
- if (approvalTx)
195
- allTransactions.push(approvalTx);
196
179
  allTransactions.push(signedBuy, signedSell);
197
180
  if (profitTx)
198
181
  allTransactions.push(profitTx);
@@ -205,7 +188,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
205
188
  ? ethers.formatEther(buyerFundsInfo.buyerFundsWei)
206
189
  : ethers.formatUnits(buyerFundsInfo.buyerFundsWei, quoteTokenDecimals),
207
190
  sellAmount: quoteResult.quotedTokenOut.toString(),
208
- hasApproval: !!approvalTx,
209
191
  profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
210
192
  }
211
193
  };
@@ -307,10 +289,6 @@ async function quoteTokenOutput({ routeParams, buyerFundsWei, provider }) {
307
289
  }
308
290
  return { quotedTokenOut: result.amountOut };
309
291
  }
310
- async function getTokenDecimals(provider, tokenAddress) {
311
- const erc20 = new Contract(tokenAddress, ['function decimals() view returns (uint8)'], provider);
312
- return await erc20.decimals();
313
- }
314
292
  /**
315
293
  * ✅ 使用 quote-helpers 统一报价(卖出 → 原生代币)
316
294
  */
@@ -332,30 +310,6 @@ function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas }) {
332
310
  : buyerBalance - reserveGas;
333
311
  return { buyerNeedTotal, maxBuyerValue };
334
312
  }
335
- async function ensureSellerApproval({ tokenAddress, seller, provider, decimals, chainId, config, nonceManager, gasPrice, txType }) {
336
- if (config.skipApprovalCheck) {
337
- return null;
338
- }
339
- const erc20Contract = new Contract(tokenAddress, ERC20_ALLOWANCE_ABI, provider);
340
- // ✅ 使用官方 V2 Router 作为授权目标
341
- const currentAllowance = await erc20Contract.allowance(seller.address, PANCAKE_V2_ROUTER_ADDRESS);
342
- // ✅ 阈值:MaxUint256 / 2,如果授权额度超过这个值,认为是"无限授权"
343
- const halfMaxUint = ethers.MaxUint256 / 2n;
344
- if (currentAllowance >= halfMaxUint) {
345
- return null;
346
- }
347
- const approvalNonce = await nonceManager.getNextNonce(seller);
348
- return await seller.signTransaction({
349
- to: tokenAddress,
350
- data: APPROVE_INTERFACE.encodeFunctionData('approve', [PANCAKE_V2_ROUTER_ADDRESS, ethers.MaxUint256]),
351
- value: 0n,
352
- nonce: approvalNonce,
353
- gasLimit: 80000n,
354
- gasPrice,
355
- chainId,
356
- type: txType
357
- });
358
- }
359
313
  async function buildRouteTransactions({ routeParams, buyerFundsWei, sellAmountToken, buyer, seller, tokenAddress, useNativeToken = true }) {
360
314
  const deadline = getDeadline();
361
315
  // ✅ ERC20 购买时,value 只需要 FLAT_FEE
@@ -425,25 +379,23 @@ async function estimateProfitAmount({ provider, tokenAddress, sellAmountToken, r
425
379
  }
426
380
  /**
427
381
  * ✅ 规划 nonce
428
- * 交易顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
382
+ * 交易顺序:贿赂 → 买入 → 卖出 → 利润
429
383
  */
430
- async function planNonces({ buyer, seller, sameAddress, approvalExists, extractProfit, needBribeTx, nonceManager }) {
384
+ async function planNonces({ buyer, seller, sameAddress, extractProfit, needBribeTx, nonceManager }) {
431
385
  if (sameAddress) {
432
- // 同一地址:贿赂(可选) + 授权(可选) + 买入 + 卖出 + 利润(可选)
433
- const txCount = countTruthy([needBribeTx, approvalExists, true, true, extractProfit]);
386
+ // 同一地址:贿赂(可选) + 买入 + 卖出 + 利润(可选)
387
+ const txCount = countTruthy([needBribeTx, true, true, extractProfit]);
434
388
  const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
435
389
  let idx = 0;
436
390
  const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
437
- if (approvalExists)
438
- idx++;
439
391
  const buyerNonce = nonces[idx++];
440
392
  const sellerNonce = nonces[idx++];
441
393
  const profitNonce = extractProfit ? nonces[idx] : undefined;
442
394
  return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
443
395
  }
444
- if (needBribeTx || approvalExists || extractProfit) {
445
- // 卖方需要多个 nonce:贿赂(可选) + 授权(可选) + 卖出 + 利润(可选)
446
- const sellerTxCount = countTruthy([needBribeTx, approvalExists, true, extractProfit]);
396
+ if (needBribeTx || extractProfit) {
397
+ // 卖方需要多个 nonce:贿赂(可选) + 卖出 + 利润(可选)
398
+ const sellerTxCount = countTruthy([needBribeTx, true, extractProfit]);
447
399
  // ✅ 并行获取 seller 和 buyer 的 nonce
448
400
  const [sellerNonces, buyerNonce] = await Promise.all([
449
401
  nonceManager.getNextNonceBatch(seller, sellerTxCount),
@@ -451,8 +403,6 @@ async function planNonces({ buyer, seller, sameAddress, approvalExists, extractP
451
403
  ]);
452
404
  let idx = 0;
453
405
  const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
454
- if (approvalExists)
455
- idx++;
456
406
  const sellerNonce = sellerNonces[idx++];
457
407
  const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
458
408
  return { buyerNonce, sellerNonce, bribeNonce, profitNonce };
@@ -520,14 +470,12 @@ function countTruthy(values) {
520
470
  * ✅ 从前端传入的 startNonces 构建 NoncePlan(用于性能优化,避免 nonce 冲突)
521
471
  * 顺序:同地址时 [baseNonce],不同地址时 [sellerNonce, buyerNonce]
522
472
  */
523
- function buildNoncePlanFromStartNonces(startNonces, sameAddress, approvalExists, profitNeeded, needBribeTx) {
473
+ function buildNoncePlanFromStartNonces(startNonces, sameAddress, profitNeeded, needBribeTx) {
524
474
  if (sameAddress) {
525
- // 同一地址:所有交易使用递增 nonce
475
+ // 同一地址:贿赂(可选) + 买入 + 卖出 + 利润(可选)
526
476
  let idx = 0;
527
477
  const baseNonce = startNonces[0];
528
478
  const bribeNonce = needBribeTx ? baseNonce + idx++ : undefined;
529
- if (approvalExists)
530
- idx++;
531
479
  const buyerNonce = baseNonce + idx++;
532
480
  const sellerNonce = baseNonce + idx++;
533
481
  const profitNonce = profitNeeded ? baseNonce + idx : undefined;
@@ -537,8 +485,6 @@ function buildNoncePlanFromStartNonces(startNonces, sameAddress, approvalExists,
537
485
  let sellerIdx = 0;
538
486
  const sellerBaseNonce = startNonces[0];
539
487
  const bribeNonce = needBribeTx ? sellerBaseNonce + sellerIdx++ : undefined;
540
- if (approvalExists)
541
- sellerIdx++;
542
488
  const sellerNonce = sellerBaseNonce + sellerIdx++;
543
489
  const profitNonce = profitNeeded ? sellerBaseNonce + sellerIdx : undefined;
544
490
  const buyerNonce = startNonces[1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.4.29",
3
+ "version": "1.4.30",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",