four-flap-meme-sdk 1.5.8 → 1.5.9

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.
@@ -250,6 +250,30 @@ export async function submitMultipleBundlesToBlockRazorParallel(bundles, config)
250
250
  const promises = bundles.map(signedTransactions => submitBundleToBlockRazor(signedTransactions, config));
251
251
  return await Promise.all(promises);
252
252
  }
253
+ function shouldTreatBroadcastErrorAsMaybeSent(msg) {
254
+ const m = String(msg || '').toLowerCase();
255
+ // 常见:交易已被节点接收/已在 mempool/已上链,但节点返回报错
256
+ return (m.includes('already known') ||
257
+ m.includes('known transaction') ||
258
+ m.includes('nonce too low') ||
259
+ m.includes('nonce has already been used') ||
260
+ m.includes('nonce expired') ||
261
+ m.includes('replacement transaction underpriced'));
262
+ }
263
+ async function recoverTxHashIfAlreadySeen(provider, signedTx, errorMessage) {
264
+ if (!shouldTreatBroadcastErrorAsMaybeSent(errorMessage))
265
+ return undefined;
266
+ try {
267
+ const hash = ethers.keccak256(signedTx);
268
+ if (!hash)
269
+ return undefined;
270
+ const tx = await provider.getTransaction(hash);
271
+ return tx ? hash : undefined;
272
+ }
273
+ catch {
274
+ return undefined;
275
+ }
276
+ }
253
277
  /**
254
278
  * 并行广播到 RPC(用于不支持 Bundle 的链,如 Monad)
255
279
  *
@@ -333,6 +357,17 @@ export async function submitDirectToRpc(signedTransactions, config) {
333
357
  catch (error) {
334
358
  const errorMessage = error?.message || String(error);
335
359
  console.error(`❌ [${chainName}] 交易 ${i + 1}/${totalTransactions} 广播失败:`, errorMessage);
360
+ // ✅ 兼容:nonce too low / already known 等情况下,交易可能已经被接收
361
+ const recovered = await recoverTxHashIfAlreadySeen(provider, signedTx, errorMessage);
362
+ if (recovered) {
363
+ if (config.waitForConfirmation) {
364
+ try {
365
+ await provider.waitForTransaction(recovered, 1, config.confirmationTimeout ?? 30000);
366
+ }
367
+ catch { }
368
+ }
369
+ return { index: i, success: true, txHash: recovered, error: errorMessage };
370
+ }
336
371
  return {
337
372
  index: i,
338
373
  success: false,
@@ -431,6 +466,29 @@ export async function submitDirectToRpcSequential(signedTransactions, config) {
431
466
  }
432
467
  catch (error) {
433
468
  const errorMessage = error?.message || String(error);
469
+ // ✅ 兼容:nonce too low / already known 等情况下,交易可能已经被接收
470
+ const recovered = await recoverTxHashIfAlreadySeen(provider, signedTx, errorMessage);
471
+ if (recovered) {
472
+ // 顺序模式依赖确认:尽量等待一下
473
+ try {
474
+ const receipt = await provider.waitForTransaction(recovered, 1, confirmationTimeout);
475
+ if (receipt && receipt.status === 1) {
476
+ results.push({ index: i, success: true, txHash: recovered, error: errorMessage });
477
+ txHashes.push(recovered);
478
+ continue;
479
+ }
480
+ const errorMsg = `交易执行失败(status=${receipt?.status})`;
481
+ results.push({ index: i, success: false, txHash: recovered, error: `${errorMessage} | ${errorMsg}` });
482
+ errors.push(`交易 ${i + 1}: ${errorMessage} | ${errorMsg}`);
483
+ continue;
484
+ }
485
+ catch {
486
+ // 等待超时也先认为“已广播”,交给上层自行确认
487
+ results.push({ index: i, success: true, txHash: recovered, error: errorMessage });
488
+ txHashes.push(recovered);
489
+ continue;
490
+ }
491
+ }
434
492
  results.push({
435
493
  index: i,
436
494
  success: false,
@@ -22,7 +22,8 @@ export async function flapPrivateBuyMerkle(params) {
22
22
  // ✅ 并行获取 gasPrice、nonce 和构建未签名交易
23
23
  const [gasPrice, currentNonce, unsigned] = await Promise.all([
24
24
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
25
- wallet.getNonce(),
25
+ // ✅ 使用 pending nonce,避免 xLayer 等链上“已有 pending 交易”导致 nonce too low
26
+ provider.getTransactionCount(wallet.address, 'pending'),
26
27
  portal.swapExactInput.populateTransaction({
27
28
  inputToken: ZERO_ADDRESS,
28
29
  outputToken: tokenAddress,
@@ -101,7 +102,8 @@ export async function flapPrivateSellMerkle(params) {
101
102
  // ✅ 并行获取 gasPrice、nonce、报价和构建未签名交易
102
103
  const [gasPrice, currentNonce, { quotedOutput }, unsigned] = await Promise.all([
103
104
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
104
- wallet.getNonce(),
105
+ // ✅ 使用 pending nonce,避免 xLayer 等链上“已有 pending 交易”导致 nonce too low
106
+ provider.getTransactionCount(wallet.address, 'pending'),
105
107
  resolveSingleSellOutputs(portal, tokenAddress, amountWei, minOutputAmount),
106
108
  portal.swapExactInput.populateTransaction({
107
109
  inputToken: tokenAddress,
@@ -198,7 +200,8 @@ export async function flapBatchPrivateBuyMerkle(params) {
198
200
  // ✅ 并行获取 gasPrice、所有 nonces 和构建未签名交易
199
201
  const [gasPrice, initialNonces, unsignedList] = await Promise.all([
200
202
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
201
- Promise.all(wallets.map(w => w.getNonce())),
203
+ // 使用 pending nonce,避免 xLayer 等链上“已有 pending 交易”导致 nonce too low
204
+ Promise.all(wallets.map(w => provider.getTransactionCount(w.address, 'pending'))),
202
205
  Promise.all(portals.map((portal, i) => portal.swapExactInput.populateTransaction({
203
206
  inputToken: ZERO_ADDRESS,
204
207
  outputToken: tokenAddress,
@@ -287,7 +290,8 @@ export async function flapBatchPrivateSellMerkle(params) {
287
290
  // ✅ 并行获取 gasPrice、所有 nonces、所有报价和构建未签名交易
288
291
  const [gasPrice, initialNonces, quotedOutputs, unsignedList] = await Promise.all([
289
292
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
290
- Promise.all(wallets.map(w => w.getNonce())),
293
+ // 使用 pending nonce,避免 xLayer 等链上“已有 pending 交易”导致 nonce too low
294
+ Promise.all(wallets.map(w => provider.getTransactionCount(w.address, 'pending'))),
291
295
  Promise.all(amountsWei.map(amount => portal.quoteExactInput.staticCall({
292
296
  inputToken: tokenAddress,
293
297
  outputToken: ZERO_ADDRESS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.8",
3
+ "version": "1.5.9",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",