four-flap-meme-sdk 1.6.85 → 1.6.87

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.
@@ -331,101 +331,101 @@ export async function buildWashOps(params) {
331
331
  // 批量预测买入后获得的代币数量(用于卖出,避免 maxUint256 问题)
332
332
  let expectedTokenAmounts = [];
333
333
  if (poolType === 'flap') {
334
- // ✅ Flap 报价:使用【总金额报价 + 按比例分配】(和 BSC 一样)
334
+ // ✅ Flap 报价:使用【累积差值法】精确计算每个钱包能买到的代币数量
335
335
  const portalQuery = new PortalQuery({ rpcUrl: config.rpcUrl, chainId: config.chainId });
336
- const totalBuyWei = buyWeiList.reduce((a, b) => a + b, 0n);
337
- console.log(`[buildWashOps] Flap 总金额报价: ${buyWeiList.length} 个钱包, 总金额=${totalBuyWei}`);
338
- // 1. 用总金额获取总代币数量
339
- let totalTokenAmount = 0n;
340
- try {
341
- totalTokenAmount = await portalQuery.previewBuy(params.tokenAddress, totalBuyWei);
336
+ console.log(`[buildWashOps] Flap 累积差值报价: ${buyWeiList.length} 个钱包`);
337
+ // 1. 构建累积金额数组
338
+ const cumulativeAmounts = [];
339
+ let cumulative = 0n;
340
+ for (const buyWei of buyWeiList) {
341
+ cumulative += buyWei;
342
+ cumulativeAmounts.push(cumulative);
342
343
  }
343
- catch {
344
+ // 2. 串行查询所有累积金额点的报价
345
+ const cumulativeQuotes = [];
346
+ for (const amt of cumulativeAmounts) {
344
347
  try {
345
- totalTokenAmount = await portalQuery.quoteExactInput('0x0000000000000000000000000000000000000000', params.tokenAddress, totalBuyWei);
348
+ const quote = await portalQuery.previewBuy(params.tokenAddress, amt);
349
+ cumulativeQuotes.push(quote);
346
350
  }
347
351
  catch {
348
- totalTokenAmount = 0n;
349
- }
350
- }
351
- // 2. 按每个钱包的买入金额比例分配代币数量
352
- if (totalBuyWei > 0n && totalTokenAmount > 0n) {
353
- let allocated = 0n;
354
- expectedTokenAmounts = buyWeiList.map((buyWei, i) => {
355
- if (i === buyWeiList.length - 1) {
356
- return totalTokenAmount - allocated;
352
+ try {
353
+ const quote = await portalQuery.quoteExactInput('0x0000000000000000000000000000000000000000', params.tokenAddress, amt);
354
+ cumulativeQuotes.push(quote);
357
355
  }
358
- const share = (totalTokenAmount * buyWei) / totalBuyWei;
359
- allocated += share;
360
- return share;
361
- });
362
- }
363
- else {
364
- expectedTokenAmounts = buyWeiList.map(() => 0n);
356
+ catch {
357
+ cumulativeQuotes.push(0n);
358
+ }
359
+ }
365
360
  }
366
- console.log(`[buildWashOps] Flap 总代币=${totalTokenAmount}, 分配:`, expectedTokenAmounts.map(a => a.toString()));
361
+ // 3. 计算每个钱包的预期代币数量(累积差值)
362
+ expectedTokenAmounts = cumulativeQuotes.map((quote, i) => {
363
+ if (i === 0)
364
+ return quote;
365
+ return quote - cumulativeQuotes[i - 1];
366
+ });
367
+ console.log(`[buildWashOps] Flap 累积报价:`, cumulativeQuotes.map(a => a.toString()));
368
+ console.log(`[buildWashOps] Flap 每钱包代币:`, expectedTokenAmounts.map(a => a.toString()));
367
369
  }
368
370
  else if (poolType === 'v2') {
369
- // ✅ V2 报价:使用【总金额报价 + 按比例分配】(和 BSC 一样)
371
+ // ✅ V2 报价:使用【累积差值法】精确计算每个钱包能买到的代币数量
370
372
  const dexQuery = new DexQuery({ rpcUrl: config.rpcUrl, routerAddress, wokbAddress: wokb });
371
- const totalBuyWei = buyWeiList.reduce((a, b) => a + b, 0n);
372
- console.log(`[buildWashOps] V2 总金额报价: ${buyWeiList.length} 个钱包, 总金额=${totalBuyWei}`);
373
- // 1. 用总金额获取总代币数量
374
- let totalTokenAmount = 0n;
375
- try {
376
- totalTokenAmount = await dexQuery.quoteOkbToToken(totalBuyWei, params.tokenAddress);
377
- }
378
- catch {
379
- totalTokenAmount = 0n;
380
- }
381
- // 2. 按每个钱包的买入金额比例分配代币数量
382
- if (totalBuyWei > 0n && totalTokenAmount > 0n) {
383
- let allocated = 0n;
384
- expectedTokenAmounts = buyWeiList.map((buyWei, i) => {
385
- if (i === buyWeiList.length - 1) {
386
- return totalTokenAmount - allocated;
387
- }
388
- const share = (totalTokenAmount * buyWei) / totalBuyWei;
389
- allocated += share;
390
- return share;
391
- });
373
+ console.log(`[buildWashOps] V2 累积差值报价: ${buyWeiList.length} 个钱包`);
374
+ // 1. 构建累积金额数组
375
+ const cumulativeAmounts = [];
376
+ let cumulative = 0n;
377
+ for (const buyWei of buyWeiList) {
378
+ cumulative += buyWei;
379
+ cumulativeAmounts.push(cumulative);
392
380
  }
393
- else {
394
- expectedTokenAmounts = buyWeiList.map(() => 0n);
381
+ // 2. 串行查询所有累积金额点的报价(V2 Router 不支持 Multicall)
382
+ const cumulativeQuotes = [];
383
+ for (const amt of cumulativeAmounts) {
384
+ try {
385
+ const quote = await dexQuery.quoteOkbToToken(amt, params.tokenAddress);
386
+ cumulativeQuotes.push(quote);
387
+ }
388
+ catch {
389
+ cumulativeQuotes.push(0n);
390
+ }
395
391
  }
396
- console.log(`[buildWashOps] V2 总代币=${totalTokenAmount}, 分配:`, expectedTokenAmounts.map(a => a.toString()));
392
+ // 3. 计算每个钱包的预期代币数量(累积差值)
393
+ expectedTokenAmounts = cumulativeQuotes.map((quote, i) => {
394
+ if (i === 0)
395
+ return quote;
396
+ return quote - cumulativeQuotes[i - 1];
397
+ });
398
+ console.log(`[buildWashOps] V2 累积报价:`, cumulativeQuotes.map(a => a.toString()));
399
+ console.log(`[buildWashOps] V2 每钱包代币:`, expectedTokenAmounts.map(a => a.toString()));
397
400
  }
398
401
  else if (poolType === 'v3') {
399
- // ✅ V3 报价:使用【总金额报价 + 按比例分配】(和 BSC 一样)
400
- // 这样可以正确考虑多钱包累积价格影响,确保卖干净
401
- const totalBuyWei = buyWeiList.reduce((a, b) => a + b, 0n);
402
- console.log(`[buildWashOps] V3 总金额报价: ${buyWeiList.length} 个钱包, 总金额=${totalBuyWei}, fee=${v3Fee}`);
403
- // 1. 用总金额获取总代币数量
404
- const totalQuoteResult = await batchQuoteV3WithMulticall({
402
+ // ✅ V3 报价:使用【累积差值法】精确计算每个钱包能买到的代币数量
403
+ // 查询每个累积金额点的报价,然后取差值
404
+ // 例如:[100, 200] 查询 100, 300 钱包1=T(100), 钱包2=T(300)-T(100)
405
+ console.log(`[buildWashOps] V3 累积差值报价: ${buyWeiList.length} 个钱包, fee=${v3Fee}`);
406
+ // 1. 构建累积金额数组
407
+ const cumulativeAmounts = [];
408
+ let cumulative = 0n;
409
+ for (const buyWei of buyWeiList) {
410
+ cumulative += buyWei;
411
+ cumulativeAmounts.push(cumulative);
412
+ }
413
+ // 2. 批量查询所有累积金额点的报价
414
+ const cumulativeQuotes = await batchQuoteV3WithMulticall({
405
415
  rpcUrl: config.rpcUrl,
406
416
  tokenIn: wokb,
407
417
  tokenOut: params.tokenAddress,
408
- amountsIn: [totalBuyWei],
418
+ amountsIn: cumulativeAmounts,
409
419
  fee: v3Fee,
410
420
  });
411
- const totalTokenAmount = totalQuoteResult[0] || 0n;
412
- // 2. 按每个钱包的买入金额比例分配代币数量
413
- if (totalBuyWei > 0n && totalTokenAmount > 0n) {
414
- let allocated = 0n;
415
- expectedTokenAmounts = buyWeiList.map((buyWei, i) => {
416
- if (i === buyWeiList.length - 1) {
417
- // 最后一个钱包分配剩余的全部(避免精度损失)
418
- return totalTokenAmount - allocated;
419
- }
420
- const share = (totalTokenAmount * buyWei) / totalBuyWei;
421
- allocated += share;
422
- return share;
423
- });
424
- }
425
- else {
426
- expectedTokenAmounts = buyWeiList.map(() => 0n);
427
- }
428
- console.log(`[buildWashOps] V3 总代币=${totalTokenAmount}, 分配:`, expectedTokenAmounts.map(a => a.toString()));
421
+ // 3. 计算每个钱包的预期代币数量(累积差值)
422
+ expectedTokenAmounts = cumulativeQuotes.map((quote, i) => {
423
+ if (i === 0)
424
+ return quote;
425
+ return quote - cumulativeQuotes[i - 1];
426
+ });
427
+ console.log(`[buildWashOps] V3 累积报价:`, cumulativeQuotes.map(a => a.toString()));
428
+ console.log(`[buildWashOps] V3 每钱包代币:`, expectedTokenAmounts.map(a => a.toString()));
429
429
  }
430
430
  console.log(`[buildWashOps] 预测买入代币数量 (${poolType}):`, expectedTokenAmounts.map(a => a.toString()));
431
431
  // 构建所有 UserOps 的骨架
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.6.85",
3
+ "version": "1.6.87",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",