four-flap-meme-sdk 1.6.27 → 1.6.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.
@@ -147,6 +147,26 @@ export async function buildDisperseFromSingleOwnerOpsWithProfit(params) {
147
147
  const fnFixed = aaManager.buildUserOpWithFixedGas;
148
148
  if (typeof fnFixed !== 'function')
149
149
  throw new Error('AA disperse:SDK 不支持 buildUserOpWithFixedGas');
150
+ // ✅ 关键修复:如果有多个 UserOps,需要确保 sender 有足够余额支付所有 prefund
151
+ // 多个 UserOps 在同一个 handleOps 中提交时,prefund 在 validation 阶段同时扣除
152
+ if (chunks.length > 1 && params.kind === 'native') {
153
+ const feeData = await provider.getFeeData();
154
+ const gasPrice = feeData.gasPrice ?? 5000000000n;
155
+ const estimatePrefundPerOp = (listLength, deployed) => {
156
+ const base = 180000n;
157
+ const per = 45000n;
158
+ const callGas = base + per * BigInt(listLength);
159
+ const verifyGas = deployed ? 250000n : 800000n;
160
+ const preVerifyGas = 60000n;
161
+ return (callGas + verifyGas + preVerifyGas) * gasPrice * 120n / 100n;
162
+ };
163
+ let totalPrefundNeeded = 0n;
164
+ for (let i = 0; i < chunks.length; i++) {
165
+ const deployed = i === 0 ? deployed0 : true;
166
+ totalPrefundNeeded += estimatePrefundPerOp(chunks[i].length, deployed);
167
+ }
168
+ console.log(`[AA 分发] 多批次分发:${chunks.length} 批,总 prefund 预估: ${ethers.formatEther(totalPrefundNeeded)} OKB`);
169
+ }
150
170
  const ops = [];
151
171
  for (let i = 0; i < chunks.length; i++) {
152
172
  const list = chunks[i];
@@ -268,6 +288,19 @@ export async function buildTransfersWithProfit(params) {
268
288
  initCodeUsed.add(k);
269
289
  return aaManager.generateInitCode(ownerAddress);
270
290
  };
291
+ // ✅ 关键修复:计算每个 sender 执行 UserOp 需要的 prefund(gas 费用)
292
+ // 在 Native 模式下,需要确保留足够的金额支付 prefund
293
+ const feeData = await provider.getFeeData();
294
+ const gasPrice = feeData.gasPrice ?? feeData.maxFeePerGas ?? 5000000000n;
295
+ const estimateTransferPrefund = (deployed) => {
296
+ // 归集操作的 gas:callGasLimit + verificationGasLimit + preVerificationGas
297
+ const callGas = 120000n; // Native 转账
298
+ const verifyGas = deployed ? 250000n : 800000n;
299
+ const preVerifyGas = 60000n;
300
+ const totalGas = callGas + verifyGas + preVerifyGas;
301
+ // 加 30% buffer 以确保足够(归集操作需要更保守)
302
+ return (totalGas * gasPrice * 130n) / 100n;
303
+ };
271
304
  // ✅ 第一步:计算每个钱包的归集金额和总利润
272
305
  // 利润从每个钱包的归集金额中扣除,但只由第一个有效钱包统一转账给利润地址
273
306
  const transferInfos = [];
@@ -292,10 +325,18 @@ export async function buildTransfersWithProfit(params) {
292
325
  if (amountWei <= 0n)
293
326
  continue;
294
327
  const profitWei = calcProfitWei(amountWei, PROFIT_CONFIG.RATE_BPS);
295
- const toWei = amountWei - profitWei;
328
+ const deployed = accountInfos[i]?.deployed ?? false;
329
+ const prefundWei = params.kind === 'native' ? estimateTransferPrefund(deployed) : 0n;
330
+ // ✅ 关键修复:toWei 需要扣除 max(profitWei, prefundWei),确保留足够的 gas
331
+ // 在 Native 模式下,如果 profitWei < prefundWei,需要留更多余额
332
+ const reserveWei = params.kind === 'native'
333
+ ? (profitWei > prefundWei ? profitWei : prefundWei)
334
+ : profitWei;
335
+ const toWei = amountWei > reserveWei ? (amountWei - reserveWei) : 0n;
296
336
  totalProfitWei += profitWei;
297
- transferInfos.push({ walletIndex: i, sender, to, amountWei, profitWei, toWei });
337
+ transferInfos.push({ walletIndex: i, sender, to, amountWei, profitWei, toWei, prefundWei });
298
338
  }
339
+ console.log(`[AA 归集] 钱包数量: ${transferInfos.length}, 总利润: ${ethers.formatEther(totalProfitWei)} OKB`);
299
340
  const unsigned = [];
300
341
  const opOwnerIndex = [];
301
342
  // ✅ 第二步:构建 UserOps
@@ -581,8 +581,29 @@ export class AADexSwapExecutor {
581
581
  if (capitalMode && buyerSenders.length > 0 && totalBuyWei > 0n) {
582
582
  if (hopCount <= 0) {
583
583
  console.log('[AA DEX 批量换手] 进入直接分发模式 (hopCount <= 0)');
584
- // ✅ 直接分发模式:将利润接收者加入分发列表(AA 内部刮取)
585
- const items = buyerSenders.map((to, i) => ({ to, value: buyAmountsWei[i] ?? 0n })).filter(x => x.value > 0n);
584
+ // ✅ 关键修复:计算每个买方执行买入 UserOp 需要的 prefund(gas 费用)
585
+ // EntryPoint validation 阶段会扣除 prefund,此时分发还没执行
586
+ // 因此需要为每个买方额外预留 prefund
587
+ const feeData = await this.aaManager.getFeeData();
588
+ const gasPrice = feeData.gasPrice ?? feeData.maxFeePerGas ?? 5000000000n; // 5 gwei fallback
589
+ const estimateBuyerPrefund = (deployed) => {
590
+ // 买入操作的 gas:V3 swap 约 650,000,部署需要额外 verificationGas
591
+ const callGas = 650000n;
592
+ const verifyGas = deployed ? 250000n : 800000n;
593
+ const preVerifyGas = 60000n;
594
+ const totalGas = callGas + verifyGas + preVerifyGas;
595
+ // 加 20% buffer 以确保足够
596
+ return (totalGas * gasPrice * 120n) / 100n;
597
+ };
598
+ // 计算每个买方需要的 prefund
599
+ const buyerPrefunds = buyerAis.map(ai => estimateBuyerPrefund(ai.deployed));
600
+ const totalBuyerPrefund = buyerPrefunds.reduce((a, b) => a + b, 0n);
601
+ console.log(`[AA DEX 直接分发] 买方数量: ${buyerSenders.length}, 总 prefund 预估: ${ethers.formatEther(totalBuyerPrefund)} OKB`);
602
+ // ✅ 直接分发模式:分发金额 = 买入金额 + 买方 prefund
603
+ const items = buyerSenders.map((to, i) => ({
604
+ to,
605
+ value: (buyAmountsWei[i] ?? 0n) + (buyerPrefunds[i] ?? 0n) // ✅ 包含 prefund
606
+ })).filter(x => x.value > 0n);
586
607
  // 添加利润接收者到分发列表
587
608
  if (extractProfit && profitWei > 0n) {
588
609
  items.push({ to: profitRecipient, value: profitWei });
@@ -390,8 +390,29 @@ export class AAPortalSwapExecutor {
390
390
  if (capitalMode && buyerSenders.length > 0 && totalBuyWei > 0n) {
391
391
  if (hopCount <= 0) {
392
392
  console.log('[AA Portal 批量换手] 进入直接分发模式 (hopCount <= 0)');
393
- // ✅ 直接分发模式:将利润接收者加入分发列表(AA 内部刮取)
394
- const items = buyerSenders.map((to, i) => ({ to, value: buyAmountsWei[i] ?? 0n })).filter(x => x.value > 0n);
393
+ // ✅ 关键修复:计算每个买方执行买入 UserOp 需要的 prefund(gas 费用)
394
+ // EntryPoint validation 阶段会扣除 prefund,此时分发还没执行
395
+ // 因此需要为每个买方额外预留 prefund
396
+ const feeData = await this.aaManager.getFeeData();
397
+ const gasPrice = feeData.gasPrice ?? feeData.maxFeePerGas ?? 5000000000n; // 5 gwei fallback
398
+ const estimateBuyerPrefund = (deployed) => {
399
+ // 买入操作的 gas:Portal 买入约 450,000,部署需要额外 verificationGas
400
+ const callGas = 450000n;
401
+ const verifyGas = deployed ? 250000n : 800000n;
402
+ const preVerifyGas = 60000n;
403
+ const totalGas = callGas + verifyGas + preVerifyGas;
404
+ // 加 20% buffer 以确保足够
405
+ return (totalGas * gasPrice * 120n) / 100n;
406
+ };
407
+ // 计算每个买方需要的 prefund
408
+ const buyerPrefunds = buyerAis.map(ai => estimateBuyerPrefund(ai.deployed));
409
+ const totalBuyerPrefund = buyerPrefunds.reduce((a, b) => a + b, 0n);
410
+ console.log(`[AA Portal 直接分发] 买方数量: ${buyerSenders.length}, 总 prefund 预估: ${ethers.formatEther(totalBuyerPrefund)} OKB`);
411
+ // ✅ 直接分发模式:分发金额 = 买入金额 + 买方 prefund
412
+ const items = buyerSenders.map((to, i) => ({
413
+ to,
414
+ value: (buyAmountsWei[i] ?? 0n) + (buyerPrefunds[i] ?? 0n) // ✅ 包含 prefund
415
+ })).filter(x => x.value > 0n);
395
416
  if (extractProfit && profitWei > 0n) {
396
417
  items.push({ to: profitRecipient, value: profitWei });
397
418
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.6.27",
3
+ "version": "1.6.28",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",