four-flap-meme-sdk 1.7.62 → 1.7.63

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.
@@ -13,10 +13,22 @@ import type { BundleSwapParams as BaseBundleSwapParams, BundleBatchSwapParams as
13
13
  export interface BundleSwapParams extends BaseBundleSwapParams {
14
14
  /** 用户类型(影响利润率) */
15
15
  userType?: UserType;
16
+ /**
17
+ * 是否使用资金利用率模式(默认 false)
18
+ * - false(普通模式): 卖家卖出 OKB 留在卖家账户,买家用自己预存的 OKB 买入
19
+ * - true(资金利用率模式): 卖家卖出的 OKB 通过多跳转账给买家,买家用收到的 OKB 买入
20
+ */
21
+ useFundUtilization?: boolean;
16
22
  }
17
23
  export interface BundleBatchSwapParams extends BaseBundleBatchSwapParams {
18
24
  /** 用户类型(影响利润率) */
19
25
  userType?: UserType;
26
+ /**
27
+ * 是否使用资金利用率模式(默认 false)
28
+ * - false(普通模式): 卖家卖出 OKB 留在卖家账户,买家用自己预存的 OKB 买入
29
+ * - true(资金利用率模式): 卖家卖出的 OKB 通过多跳转账给买家,买家用收到的 OKB 买入
30
+ */
31
+ useFundUtilization?: boolean;
20
32
  }
21
33
  import { type UserType } from './utils.js';
22
34
  /**
@@ -291,8 +291,7 @@ tokenAddress, tradeType, routerAddress, fee) {
291
291
  * });
292
292
  */
293
293
  export async function bundleSwap(params) {
294
- const { sellerPrivateKey, buyerPrivateKey, tokenAddress, tokenDecimals = 18, sellAmount, hopCount = 2, // 设为 0 则不多跳,直接 seller buyer
295
- tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', // ✅ 用户类型(影响利润率)
294
+ const { sellerPrivateKey, buyerPrivateKey, tokenAddress, tokenDecimals = 18, sellAmount, hopCount = 0, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', useFundUtilization = false, // ✅ 默认普通模式
296
295
  config, } = params;
297
296
  const provider = getCachedProvider(config?.rpcUrl);
298
297
  const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
@@ -304,89 +303,140 @@ export async function bundleSwap(params) {
304
303
  // ========================================
305
304
  const sellerWallet = createWallet(sellerPrivateKey, provider);
306
305
  const buyerWallet = createWallet(buyerPrivateKey, provider);
307
- // 生成中间钱包(hopCount = 0 时不生成)
308
- const hopWalletInfos = hopCount > 0 ? generateRandomWallets(hopCount) : [];
306
+ // 资金利用率模式才需要中间钱包
307
+ const actualHopCount = useFundUtilization ? hopCount : 0;
308
+ const hopWalletInfos = actualHopCount > 0 ? generateRandomWallets(actualHopCount) : [];
309
309
  const hopWallets = hopWalletInfos.map(info => createWallet(info.privateKey, provider));
310
310
  const sellAmountWei = ethers.parseUnits(truncateDecimals(sellAmount, tokenDecimals), tokenDecimals);
311
- // ✅ 修复:获取卖出报价,基于预估的 OKB 输出计算利润
311
+ // 获取卖出报价
312
312
  const estimatedOkbOut = await quoteSellOutput(sellAmountWei, tokenAddress, tradeType, fee, config?.rpcUrl);
313
313
  // 使用双边费率计算利润(换手 = 卖 + 买)
314
314
  const profitAmount = estimatedOkbOut > 0n
315
- ? calculateProfitAmountByUserType(estimatedOkbOut, userType, true) // isDoubleMode = true
315
+ ? calculateProfitAmountByUserType(estimatedOkbOut, userType, true)
316
316
  : 0n;
317
317
  const profitRecipient = getProfitRecipient(config);
318
- // ✅ 计算买入金额:基于卖家卖出得到的 OKB(不是买家全部余额)
318
+ // 计算买入金额
319
319
  const buyAmountAfterProfit = estimatedOkbOut > profitAmount
320
320
  ? estimatedOkbOut - profitAmount
321
321
  : 0n;
322
+ const modeLabel = useFundUtilization ? '资金利用率' : '普通';
323
+ console.log(`[Bundle Swap] 模式: ${modeLabel}`);
322
324
  console.log(`[Bundle Swap] 卖出数量: ${sellAmount} Token`);
323
325
  console.log(`[Bundle Swap] 预估获得: ${ethers.formatEther(estimatedOkbOut)} OKB`);
324
326
  console.log(`[Bundle Swap] 利润: ${ethers.formatEther(profitAmount)} OKB (userType=${userType})`);
325
- console.log(`[Bundle Swap] 买家应买入: ${ethers.formatEther(buyAmountAfterProfit)} OKB(基于卖出所得)`);
327
+ console.log(`[Bundle Swap] 买入金额: ${ethers.formatEther(buyAmountAfterProfit)} OKB`);
326
328
  // ========================================
327
- // 并行获取所有异步数据
329
+ // 并行获取数据
328
330
  // ========================================
329
331
  const [nonces, feeData, buyerBalance] = await Promise.all([
330
- // 并行获取 seller 和 buyer 的 nonce
331
332
  batchGetNonces([sellerWallet.address, buyerWallet.address], provider),
332
- // 获取 gas 费用数据
333
333
  provider.getFeeData(),
334
- // 获取买家的 OKB 余额(验证是否足够)
335
334
  provider.getBalance(buyerWallet.address),
336
335
  ]);
337
336
  const sellerNonce = nonces[0];
338
337
  const buyerNonce = nonces[1];
339
- console.log(`[Bundle Swap] 买家 OKB 余额: ${ethers.formatEther(buyerBalance)} OKB`);
340
- // ✅ FLAP 模式需要买家有足够的 OKB(至少等于卖家卖出得到的 OKB)
341
- if (tradeType === 'FLAP') {
342
- if (buyAmountAfterProfit <= 0n) {
343
- throw new Error('FLAP 内盘模式需要有效的报价,请检查代币地址或稍后重试');
344
- }
338
+ // ========================================
339
+ // 验证余额
340
+ // ========================================
341
+ if (tradeType === 'FLAP' && buyAmountAfterProfit <= 0n) {
342
+ throw new Error('FLAP 内盘模式需要有效的报价,请检查代币地址或稍后重试');
343
+ }
344
+ // 普通模式:买家需要预存足够的 OKB
345
+ if (!useFundUtilization && tradeType === 'FLAP') {
345
346
  if (buyerBalance < buyAmountAfterProfit) {
346
- throw new Error(`FLAP 内盘模式需要买家钱包有足够的 OKB,需要 ${ethers.formatEther(buyAmountAfterProfit)},当前 ${ethers.formatEther(buyerBalance)}`);
347
+ throw new Error(`普通模式需要买家钱包有足够的 OKB,需要 ${ethers.formatEther(buyAmountAfterProfit)},当前 ${ethers.formatEther(buyerBalance)}`);
347
348
  }
348
349
  }
349
350
  // ========================================
350
- // 同步签署授权(只需要卖家和买家,不需要 hop wallets)
351
+ // 签署授权
351
352
  // ========================================
352
- const authorizations = [];
353
+ const authPromises = [];
353
354
  // 卖家授权(交易发起者,nonce +1)
354
- authorizations.push(signAuthorization(sellerWallet, delegateAddress, BigInt(sellerNonce + 1)));
355
+ authPromises.push(signAuthorization(sellerWallet, delegateAddress, BigInt(sellerNonce + 1)));
355
356
  // 买家授权
356
- authorizations.push(signAuthorization(buyerWallet, delegateAddress, BigInt(buyerNonce)));
357
- // 等待所有授权签名完成
358
- const resolvedAuthorizations = await Promise.all(authorizations);
359
- const calls = [];
357
+ authPromises.push(signAuthorization(buyerWallet, delegateAddress, BigInt(buyerNonce)));
358
+ // 中间钱包授权(资金利用率模式)
359
+ for (const hopWallet of hopWallets) {
360
+ authPromises.push(signAuthorization(hopWallet, delegateAddress, 0n));
361
+ }
362
+ const authorizations = await Promise.all(authPromises);
360
363
  // ========================================
361
- // ✅ 普通换手模式逻辑
362
- // 1. 卖家卖出代币 → OKB 留在卖家账户
363
- // 2. 买家用自己预存的 OKB 买入代币(金额 = 卖家卖出所得,不是全部余额)
364
- // 3. 利润从买家的 OKB 中扣除
364
+ // 构建调用
365
365
  // ========================================
366
- // 1. 卖家卖出(OKB 留在卖家账户,不转给买家)
367
- const sellCall = buildSellCallWithAmountInternal(sellerWallet, sellAmountWei, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
368
- calls.push(sellCall);
369
- // 2. 利润刮取(从买家余额扣除,在买入之前)
370
- if (profitAmount > 0n) {
366
+ const calls = [];
367
+ if (useFundUtilization) {
368
+ // ========================================
369
+ // 资金利用率模式
370
+ // 1. 卖家卖出代币 获得 OKB
371
+ // 2. OKB 多跳转账 → 中间钱包1 → 中间钱包2 → ... → 买家
372
+ // 3. 利润从卖家 OKB 中扣除
373
+ // 4. 买家用收到的 OKB 买入
374
+ // ========================================
375
+ console.log(`[Bundle Swap] 资金利用率模式,hopCount=${actualHopCount}`);
376
+ // 1. 卖家卖出
377
+ const sellCall = buildSellCallWithAmountInternal(sellerWallet, sellAmountWei, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
378
+ calls.push(sellCall);
379
+ // 2. 利润刮取(从卖家余额扣除)
380
+ if (profitAmount > 0n) {
381
+ calls.push({
382
+ target: sellerWallet.address,
383
+ allowFailure: false,
384
+ value: 0n,
385
+ callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmount]),
386
+ });
387
+ }
388
+ // 3. OKB 多跳转账(卖家 → hop1 → hop2 → ... → 买家)
389
+ const firstRecipient = hopWallets.length > 0 ? hopWallets[0].address : buyerWallet.address;
390
+ // 卖家 → 第一个接收者
371
391
  calls.push({
372
- target: buyerWallet.address,
392
+ target: sellerWallet.address,
373
393
  allowFailure: false,
374
394
  value: 0n,
375
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmount]),
395
+ callData: delegateInterface.encodeFunctionData('transferTo', [firstRecipient]),
376
396
  });
397
+ // 中间钱包之间转账
398
+ for (let i = 0; i < hopWallets.length; i++) {
399
+ const nextRecipient = i < hopWallets.length - 1 ? hopWallets[i + 1].address : buyerWallet.address;
400
+ calls.push({
401
+ target: hopWallets[i].address,
402
+ allowFailure: false,
403
+ value: 0n,
404
+ callData: delegateInterface.encodeFunctionData('transferTo', [nextRecipient]),
405
+ });
406
+ }
407
+ // 4. 买家买入(使用收到的全部 OKB)
408
+ const buyCall = buildBuyCallInternal(buyerWallet, tradeType === 'FLAP' ? buyAmountAfterProfit : 0n, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
409
+ calls.push(buyCall);
410
+ }
411
+ else {
412
+ // ========================================
413
+ // ✅ 普通模式
414
+ // 1. 卖家卖出代币 → OKB 留在卖家账户
415
+ // 2. 买家用自己预存的 OKB 买入代币
416
+ // 3. 利润从买家的 OKB 中扣除
417
+ // ========================================
418
+ console.log(`[Bundle Swap] 普通模式`);
419
+ // 1. 卖家卖出(OKB 留在卖家账户)
420
+ const sellCall = buildSellCallWithAmountInternal(sellerWallet, sellAmountWei, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
421
+ calls.push(sellCall);
422
+ // 2. 利润刮取(从买家余额扣除)
423
+ if (profitAmount > 0n) {
424
+ calls.push({
425
+ target: buyerWallet.address,
426
+ allowFailure: false,
427
+ value: 0n,
428
+ callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmount]),
429
+ });
430
+ }
431
+ // 3. 买家用自己的 OKB 买入
432
+ const buyAmountForCall = tradeType === 'FLAP' ? buyAmountAfterProfit : 0n;
433
+ const buyCall = buildBuyCallInternal(buyerWallet, buyAmountForCall, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
434
+ calls.push(buyCall);
377
435
  }
378
- // 3. 买家用自己预存的 OKB 买入
379
- // ✅ 关键修复:买入金额 = 卖家卖出所得(扣除利润),而不是买家全部余额
380
- // FLAP 模式必须指定精确金额,V2/V3 使用 0n(合约自动使用全部余额)
381
- const buyAmountForCall = tradeType === 'FLAP' ? buyAmountAfterProfit : 0n;
382
- console.log(`[Bundle Swap] 实际买入调用金额: ${ethers.formatEther(buyAmountForCall)} OKB`);
383
- const buyCall = buildBuyCallInternal(buyerWallet, buyAmountForCall, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
384
- calls.push(buyCall);
385
436
  // ========================================
386
- // 同步构建交易
437
+ // 构建交易
387
438
  // ========================================
388
- const signedTransaction = buildEIP7702TransactionSync(sellerWallet, resolvedAuthorizations, calls, 0n, // 修复:利润使用 transferAmount 从卖家余额转账,不需要通过 msg.value 传递
389
- sellerNonce, feeData, config);
439
+ const signedTransaction = buildEIP7702TransactionSync(sellerWallet, authorizations, calls, 0n, sellerNonce, feeData, config);
390
440
  return {
391
441
  signedTransaction,
392
442
  hopWallets: hopWalletInfos,
@@ -394,11 +444,12 @@ export async function bundleSwap(params) {
394
444
  sellerAddress: sellerWallet.address,
395
445
  buyerAddresses: [buyerWallet.address],
396
446
  sellAmount: ethers.formatUnits(sellAmountWei, tokenDecimals),
397
- estimatedOkbOut: ethers.formatEther(estimatedOkbOut), // ✅ 预估卖出所得 OKB
398
- estimatedBuyAmount: '0',
399
- profitAmount: ethers.formatEther(profitAmount), // ✅ 利润是 OKB
447
+ estimatedOkbOut: ethers.formatEther(estimatedOkbOut),
448
+ estimatedBuyAmount: ethers.formatEther(buyAmountAfterProfit),
449
+ profitAmount: ethers.formatEther(profitAmount),
400
450
  profitRecipient,
401
451
  userType,
452
+ useFundUtilization,
402
453
  },
403
454
  };
404
455
  }
@@ -419,141 +470,189 @@ export async function bundleSwap(params) {
419
470
  * });
420
471
  */
421
472
  export async function bundleBatchSwap(params) {
422
- const { sellerPrivateKey, buyerPrivateKeys, buyerRatios, // ✅ 添加:前端传入的分配比例
423
- tokenAddress, tokenDecimals = 18, sellAmount, hopCount = 2, // ✅ 设为 0 则不多跳
424
- tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', // ✅ 用户类型(影响利润率)
473
+ const { sellerPrivateKey, buyerPrivateKeys, buyerRatios, tokenAddress, tokenDecimals = 18, sellAmount, hopCount = 0, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', useFundUtilization = false, // ✅ 默认普通模式
425
474
  config, } = params;
426
475
  const provider = getCachedProvider(config?.rpcUrl);
427
476
  const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
428
477
  const actualRouter = routerAddress ?? getDefaultRouter(tradeType);
478
+ const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
479
+ const portalInterface = new ethers.Interface(FLAP_PORTAL_ABI);
429
480
  // ========================================
430
- // 同步操作 - 创建钱包
481
+ // 创建钱包
431
482
  // ========================================
432
483
  const sellerWallet = createWallet(sellerPrivateKey, provider);
433
484
  const buyerWallets = buyerPrivateKeys.map(pk => createWallet(pk, provider));
434
- const hopWalletInfos = hopCount > 0 ? generateRandomWallets(hopCount) : [];
485
+ // 资金利用率模式才需要中间钱包
486
+ const actualHopCount = useFundUtilization ? hopCount : 0;
487
+ const hopWalletInfos = actualHopCount > 0 ? generateRandomWallets(actualHopCount) : [];
435
488
  const hopWallets = hopWalletInfos.map(info => createWallet(info.privateKey, provider));
436
489
  const sellAmountWei = ethers.parseUnits(truncateDecimals(sellAmount, tokenDecimals), tokenDecimals);
437
- // ✅ 修复:获取卖出报价,基于预估的 OKB 输出计算利润
490
+ // 获取卖出报价
438
491
  const estimatedOkbOut = await quoteSellOutput(sellAmountWei, tokenAddress, tradeType, fee, config?.rpcUrl);
439
- // 使用双边费率计算利润(换手 = 卖 + 买)
492
+ // 计算利润和买入金额
440
493
  const profitAmount = estimatedOkbOut > 0n
441
- ? calculateProfitAmountByUserType(estimatedOkbOut, userType, true) // isDoubleMode = true
494
+ ? calculateProfitAmountByUserType(estimatedOkbOut, userType, true)
442
495
  : 0n;
443
496
  const profitRecipient = getProfitRecipient(config);
444
- // ✅ 计算总买入金额:基于卖家卖出得到的 OKB(不是买家全部余额)
445
497
  const totalBuyAmountAfterProfit = estimatedOkbOut > profitAmount
446
498
  ? estimatedOkbOut - profitAmount
447
499
  : 0n;
500
+ const modeLabel = useFundUtilization ? '资金利用率' : '普通';
501
+ console.log(`[Bundle Batch Swap] 模式: ${modeLabel}`);
448
502
  console.log(`[Bundle Batch Swap] 卖出数量: ${sellAmount} Token`);
449
503
  console.log(`[Bundle Batch Swap] 预估获得: ${ethers.formatEther(estimatedOkbOut)} OKB`);
450
504
  console.log(`[Bundle Batch Swap] 利润: ${ethers.formatEther(profitAmount)} OKB (userType=${userType})`);
451
- console.log(`[Bundle Batch Swap] 买家总应买入: ${ethers.formatEther(totalBuyAmountAfterProfit)} OKB(基于卖出所得)`);
452
- // ✅ FLAP 模式需要有效的报价(不能使用 0n 作为买入金额)
505
+ console.log(`[Bundle Batch Swap] 买入金额: ${ethers.formatEther(totalBuyAmountAfterProfit)} OKB`);
506
+ // 验证报价
453
507
  if (tradeType === 'FLAP' && totalBuyAmountAfterProfit <= 0n) {
454
508
  throw new Error('FLAP 内盘模式需要有效的报价,请检查代币地址或稍后重试');
455
509
  }
456
510
  // ========================================
457
- // 并行获取所有异步数据
511
+ // 并行获取数据
458
512
  // ========================================
459
513
  const addressesToQuery = [sellerWallet.address, ...buyerWallets.map(w => w.address)];
460
514
  const [nonces, feeData, ...buyerBalances] = await Promise.all([
461
515
  batchGetNonces(addressesToQuery, provider),
462
516
  provider.getFeeData(),
463
- // 获取所有买家的 OKB 余额(验证是否足够)
464
517
  ...buyerWallets.map(w => provider.getBalance(w.address)),
465
518
  ]);
466
519
  const sellerNonce = nonces[0];
467
520
  const buyerNonces = nonces.slice(1);
468
- console.log(`[Bundle Batch Swap] 买家余额:`, buyerBalances.map(b => ethers.formatEther(b)));
469
- // FLAP 模式验证:买家总余额必须足够
470
- if (tradeType === 'FLAP') {
521
+ // 普通模式验证:买家需要预存足够的 OKB
522
+ if (!useFundUtilization && tradeType === 'FLAP') {
471
523
  const totalBuyerBalance = buyerBalances.reduce((sum, b) => sum + BigInt(b.toString()), 0n);
472
524
  if (totalBuyerBalance < totalBuyAmountAfterProfit) {
473
- throw new Error(`FLAP 内盘模式需要买家钱包总余额足够,需要 ${ethers.formatEther(totalBuyAmountAfterProfit)},当前总计 ${ethers.formatEther(totalBuyerBalance)}`);
525
+ throw new Error(`普通模式需要买家钱包总余额足够,需要 ${ethers.formatEther(totalBuyAmountAfterProfit)},当前总计 ${ethers.formatEther(totalBuyerBalance)}`);
474
526
  }
475
527
  }
476
528
  // ========================================
477
- // 同步构建调用
529
+ // 签署授权
478
530
  // ========================================
479
- const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
480
- const portalInterface = new ethers.Interface(FLAP_PORTAL_ABI);
481
- const calls = [];
531
+ const authPromises = [];
532
+ authPromises.push(signAuthorization(sellerWallet, delegateAddress, BigInt(sellerNonce + 1)));
533
+ for (let i = 0; i < buyerWallets.length; i++) {
534
+ authPromises.push(signAuthorization(buyerWallets[i], delegateAddress, BigInt(buyerNonces[i])));
535
+ }
536
+ // 中间钱包授权(资金利用率模式)
537
+ for (const hopWallet of hopWallets) {
538
+ authPromises.push(signAuthorization(hopWallet, delegateAddress, 0n));
539
+ }
540
+ const authorizations = await Promise.all(authPromises);
482
541
  // ========================================
483
- // ✅ 修复:普通换手模式逻辑(一卖多买)
484
- // 1. 卖家卖出代币 → OKB 留在卖家账户
485
- // 2. 所有买家用自己预存的 OKB 买入代币
486
- // 3. 利润从第一个买家的 OKB 中扣除
542
+ // 构建调用
487
543
  // ========================================
488
- // 1. 卖家卖出(OKB 留在卖家账户,不转给买家)
489
- const sellCall = buildSellCallWithAmountInternal(sellerWallet, sellAmountWei, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
490
- calls.push(sellCall);
491
- // 2. 利润刮取(从第一个买家扣除,在买入之前)
492
- if (profitAmount > 0n) {
493
- calls.push({
494
- target: buyerWallets[0].address,
495
- allowFailure: false,
496
- value: 0n,
497
- callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmount]),
498
- });
499
- }
500
- // ✅ 3. 计算每个买家的买入金额
501
- // 关键修复:买入金额 = 卖家卖出所得(按比例分配),而不是买家全部余额
544
+ const calls = [];
545
+ // 计算每个买家的买入金额
502
546
  let buyAmountsPerBuyer;
503
547
  if (tradeType === 'FLAP') {
504
- // FLAP 模式:按比例分配卖家卖出所得的 OKB
505
548
  if (buyerWallets.length === 1) {
506
- // 单买家:使用全部卖出所得
507
549
  buyAmountsPerBuyer = [totalBuyAmountAfterProfit];
508
550
  }
509
551
  else if (buyerRatios && buyerRatios.length === buyerWallets.length) {
510
- // 多买家 + 有比例:按前端传入的比例分配
511
552
  let allocated = 0n;
512
553
  buyAmountsPerBuyer = buyerRatios.map((ratio, i) => {
513
554
  const amount = (totalBuyAmountAfterProfit * BigInt(Math.round(ratio * 10000))) / 10000n;
514
555
  if (i === buyerRatios.length - 1) {
515
- return totalBuyAmountAfterProfit - allocated; // 最后一个分配剩余,避免精度问题
556
+ return totalBuyAmountAfterProfit - allocated;
516
557
  }
517
558
  allocated += amount;
518
559
  return amount;
519
560
  });
520
561
  }
521
562
  else {
522
- // 多买家无比例:均分
523
563
  const avgAmount = totalBuyAmountAfterProfit / BigInt(buyerWallets.length);
524
564
  const remainder = totalBuyAmountAfterProfit % BigInt(buyerWallets.length);
525
- buyAmountsPerBuyer = buyerWallets.map((_, i) => {
526
- // 最后一个买家分配剩余
527
- return i === buyerWallets.length - 1 ? avgAmount + remainder : avgAmount;
528
- });
565
+ buyAmountsPerBuyer = buyerWallets.map((_, i) => i === buyerWallets.length - 1 ? avgAmount + remainder : avgAmount);
529
566
  }
530
- console.log(`[bundleBatchSwap] FLAP 模式,买家买入金额(基于卖出所得):`, buyAmountsPerBuyer.map(a => ethers.formatEther(a)));
531
567
  }
532
568
  else {
533
- // V2/V3 模式:使用 0n,合约自动使用全部余额
534
569
  buyAmountsPerBuyer = buyerWallets.map(() => 0n);
535
570
  }
536
- // 4. 所有买家买入(使用自己预存的 OKB)
537
- for (let i = 0; i < buyerWallets.length; i++) {
538
- const buyCall = buildBuyCallInternal(buyerWallets[i], buyAmountsPerBuyer[i], tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
539
- calls.push(buyCall);
571
+ if (useFundUtilization) {
572
+ // ========================================
573
+ // 资金利用率模式(一卖多买)
574
+ // 1. 卖家卖出代币 → 获得 OKB
575
+ // 2. 利润从卖家 OKB 中扣除
576
+ // 3. OKB 多跳转账 → 分配给各买家
577
+ // 4. 各买家用收到的 OKB 买入
578
+ // ========================================
579
+ console.log(`[Bundle Batch Swap] 资金利用率模式,hopCount=${actualHopCount}`);
580
+ // 1. 卖家卖出
581
+ const sellCall = buildSellCallWithAmountInternal(sellerWallet, sellAmountWei, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
582
+ calls.push(sellCall);
583
+ // 2. 利润刮取(从卖家余额扣除)
584
+ if (profitAmount > 0n) {
585
+ calls.push({
586
+ target: sellerWallet.address,
587
+ allowFailure: false,
588
+ value: 0n,
589
+ callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmount]),
590
+ });
591
+ }
592
+ // 3. OKB 多跳转账给第一个买家
593
+ const firstRecipient = hopWallets.length > 0 ? hopWallets[0].address : buyerWallets[0].address;
594
+ // 卖家 → 第一个接收者(转全部余额)
595
+ calls.push({
596
+ target: sellerWallet.address,
597
+ allowFailure: false,
598
+ value: 0n,
599
+ callData: delegateInterface.encodeFunctionData('transferTo', [firstRecipient]),
600
+ });
601
+ // 中间钱包之间转账
602
+ for (let i = 0; i < hopWallets.length; i++) {
603
+ const nextRecipient = i < hopWallets.length - 1 ? hopWallets[i + 1].address : buyerWallets[0].address;
604
+ calls.push({
605
+ target: hopWallets[i].address,
606
+ allowFailure: false,
607
+ value: 0n,
608
+ callData: delegateInterface.encodeFunctionData('transferTo', [nextRecipient]),
609
+ });
610
+ }
611
+ // 第一个买家分配给其他买家
612
+ for (let i = 1; i < buyerWallets.length; i++) {
613
+ calls.push({
614
+ target: buyerWallets[0].address,
615
+ allowFailure: false,
616
+ value: 0n,
617
+ callData: delegateInterface.encodeFunctionData('transferAmount', [buyerWallets[i].address, buyAmountsPerBuyer[i]]),
618
+ });
619
+ }
620
+ // 4. 所有买家买入
621
+ for (let i = 0; i < buyerWallets.length; i++) {
622
+ const buyCall = buildBuyCallInternal(buyerWallets[i], buyAmountsPerBuyer[i], tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
623
+ calls.push(buyCall);
624
+ }
540
625
  }
541
- // ========================================
542
- // 同步签署授权(只需要卖家和买家,不需要 hop wallets)
543
- // ========================================
544
- const authPromises = [];
545
- // 卖家授权(交易发起者,nonce +1)
546
- authPromises.push(signAuthorization(sellerWallet, delegateAddress, BigInt(sellerNonce + 1)));
547
- // 买家授权
548
- for (let i = 0; i < buyerWallets.length; i++) {
549
- authPromises.push(signAuthorization(buyerWallets[i], delegateAddress, BigInt(buyerNonces[i])));
626
+ else {
627
+ // ========================================
628
+ // ✅ 普通模式(一卖多买)
629
+ // 1. 卖家卖出代币 → OKB 留在卖家账户
630
+ // 2. 利润从第一个买家 OKB 中扣除
631
+ // 3. 各买家用自己预存的 OKB 买入
632
+ // ========================================
633
+ console.log(`[Bundle Batch Swap] 普通模式`);
634
+ // 1. 卖家卖出(OKB 留在卖家账户)
635
+ const sellCall = buildSellCallWithAmountInternal(sellerWallet, sellAmountWei, tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
636
+ calls.push(sellCall);
637
+ // 2. 利润刮取(从第一个买家余额扣除)
638
+ if (profitAmount > 0n) {
639
+ calls.push({
640
+ target: buyerWallets[0].address,
641
+ allowFailure: false,
642
+ value: 0n,
643
+ callData: delegateInterface.encodeFunctionData('transferAmount', [profitRecipient, profitAmount]),
644
+ });
645
+ }
646
+ // 3. 所有买家买入(使用自己预存的 OKB)
647
+ for (let i = 0; i < buyerWallets.length; i++) {
648
+ const buyCall = buildBuyCallInternal(buyerWallets[i], buyAmountsPerBuyer[i], tokenAddress, tradeType, actualRouter, fee, delegateInterface, portalInterface);
649
+ calls.push(buyCall);
650
+ }
550
651
  }
551
- const authorizations = await Promise.all(authPromises);
552
652
  // ========================================
553
- // 同步构建交易
653
+ // 构建交易
554
654
  // ========================================
555
- const signedTransaction = buildEIP7702TransactionSync(sellerWallet, authorizations, calls, 0n, // 利润使用 transferAmount 从卖家余额转账,不需要通过 msg.value 传递
556
- sellerNonce, feeData, config);
655
+ const signedTransaction = buildEIP7702TransactionSync(sellerWallet, authorizations, calls, 0n, sellerNonce, feeData, config);
557
656
  return {
558
657
  signedTransaction,
559
658
  hopWallets: hopWalletInfos,
@@ -561,11 +660,12 @@ export async function bundleBatchSwap(params) {
561
660
  sellerAddress: sellerWallet.address,
562
661
  buyerAddresses: buyerWallets.map(w => w.address),
563
662
  sellAmount: ethers.formatUnits(sellAmountWei, tokenDecimals),
564
- estimatedOkbOut: ethers.formatEther(estimatedOkbOut), // ✅ 预估卖出所得 OKB
565
- estimatedBuyAmount: '0',
566
- profitAmount: ethers.formatEther(profitAmount), // ✅ 利润是 OKB
663
+ estimatedOkbOut: ethers.formatEther(estimatedOkbOut),
664
+ estimatedBuyAmount: ethers.formatEther(totalBuyAmountAfterProfit),
665
+ profitAmount: ethers.formatEther(profitAmount),
567
666
  profitRecipient,
568
667
  userType,
668
+ useFundUtilization,
569
669
  },
570
670
  };
571
671
  }
@@ -204,6 +204,8 @@ export interface BundleSwapResult {
204
204
  profitRecipient?: string;
205
205
  /** 用户类型 */
206
206
  userType?: string;
207
+ /** 是否使用资金利用率模式 */
208
+ useFundUtilization?: boolean;
207
209
  };
208
210
  }
209
211
  export interface MultiHopTransferParams {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.7.62",
3
+ "version": "1.7.63",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",