four-flap-meme-sdk 4.4.0 → 4.4.2

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.
@@ -90,12 +90,26 @@ async function executeSellFlow(options) {
90
90
  amountsWei,
91
91
  minOuts: sellOutputs.minOuts,
92
92
  });
93
+ let sellGasLimit = finalGasLimit;
94
+ if (unsignedSells[0] && wallets[0]) {
95
+ try {
96
+ const estimated = await provider.estimateGas({
97
+ ...unsignedSells[0],
98
+ from: wallets[0].address,
99
+ });
100
+ if (estimated > 0n)
101
+ sellGasLimit = estimated;
102
+ }
103
+ catch {
104
+ /* 估算失败继续用配置上限 */
105
+ }
106
+ }
93
107
  // ✅ 并行签名所有卖出交易
94
108
  const signedSells = await Promise.all(unsignedSells.map((unsigned, index) => wallets[index].signTransaction({
95
109
  ...unsigned,
96
110
  from: wallets[index].address,
97
111
  nonce: adjustedNonces[index],
98
- gasLimit: finalGasLimit,
112
+ gasLimit: sellGasLimit,
99
113
  gasPrice,
100
114
  chainId,
101
115
  type: txType,
@@ -74,6 +74,21 @@ export async function fourBundleSwapMerkle(params) {
74
74
  ]);
75
75
  const { sellerNonces, buyerNonce } = noncesResult;
76
76
  const noncePlan = planSellerNonces(sellerNonces, needBribeTx, needApproval, extractProfit);
77
+ let sellGasLimit = finalGasLimit;
78
+ let buyGasLimit = finalGasLimit;
79
+ try {
80
+ const [sellGas, buyGas] = await Promise.all([
81
+ provider.estimateGas({ ...sellUnsigned, from: seller.address }),
82
+ provider.estimateGas({ ...buyUnsigned, from: buyer.address, value: buyerFunds }),
83
+ ]);
84
+ if (sellGas > 0n)
85
+ sellGasLimit = sellGas;
86
+ if (buyGas > 0n)
87
+ buyGasLimit = buyGas;
88
+ }
89
+ catch {
90
+ /* 估算失败继续用配置上限 */
91
+ }
77
92
  const signPromises = [];
78
93
  if (needBribeTx && noncePlan.bribeNonce !== undefined) {
79
94
  signPromises.push(signBribeTransaction(seller, bribeAmount, noncePlan.bribeNonce, gasPrice, chainIdNum, txType));
@@ -85,7 +100,7 @@ export async function fourBundleSwapMerkle(params) {
85
100
  ...sellUnsigned,
86
101
  from: seller.address,
87
102
  nonce: noncePlan.sellerNonce,
88
- gasLimit: finalGasLimit,
103
+ gasLimit: sellGasLimit,
89
104
  gasPrice,
90
105
  chainId: chainIdNum,
91
106
  type: txType,
@@ -93,7 +108,7 @@ export async function fourBundleSwapMerkle(params) {
93
108
  ...buyUnsigned,
94
109
  from: buyer.address,
95
110
  nonce: buyerNonce,
96
- gasLimit: finalGasLimit,
111
+ gasLimit: buyGasLimit,
97
112
  gasPrice,
98
113
  chainId: chainIdNum,
99
114
  type: txType,
@@ -2,7 +2,7 @@ import { ethers, Wallet } from 'ethers';
2
2
  import { getOptimizedGasPrice, NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../utils/bundle-helpers.js';
3
3
  import { calculateTransferFee, floorErc20TransferGasLimit, GAS_LIMITS, isBscChain } from '../../core/constants/index.js';
4
4
  import { getGasPriceConfig, shouldExtractProfit, getProfitRecipient, getBribeAmount } from '../config-helpers.js';
5
- import { getErc20Decimals as _getErc20Decimals, generateHopWallets as _generateHopWallets, normalizeAmounts as _normalizeAmounts, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress, } from '../internal.js';
5
+ import { getErc20Decimals as _getErc20Decimals, generateHopWallets as _generateHopWallets, normalizeAmounts as _normalizeAmounts, calculateGasLimit as _calculateGasLimit, estimateSweepLimits, isNativeTokenAddress as _isNativeTokenAddress, } from '../internal.js';
6
6
  import { normalizeItemsOrRecipientsAmounts, resolveHopCountInput, resolveProvidedHops, resolveSignContext, signBribeTransaction, } from '../../core/sign-context-helpers.js';
7
7
  // ==================== 钱包转账按地址收费 ====================
8
8
  /**
@@ -29,8 +29,24 @@ export async function disperseWithBundleMerkle(params) {
29
29
  const preparedHops = providedHops ?? _generateHopWallets(recipients.length, hopCountInput);
30
30
  const hasHops = preparedHops !== null;
31
31
  const maxHopCount = hasHops ? Math.max(...preparedHops.map((h) => h.length)) : 0;
32
- const finalGasLimit = _calculateGasLimit(config, isNative, hasHops, maxHopCount);
33
- const nativeGasLimit = (config.prefer21000ForNative ?? false) ? 21000n : finalGasLimit;
32
+ let finalGasLimit = _calculateGasLimit(config, isNative, hasHops, maxHopCount);
33
+ let nativeGasLimit = (config.prefer21000ForNative ?? false) ? 21000n : finalGasLimit;
34
+ let gasEstimated = false;
35
+ if (recipients[0]) {
36
+ const limits = await estimateSweepLimits({
37
+ provider,
38
+ from: mainWallet.address,
39
+ to: recipients[0],
40
+ tokenAddress: isNative ? undefined : tokenAddress,
41
+ nativeFallback: nativeGasLimit,
42
+ tokenFallback: finalGasLimit,
43
+ });
44
+ if (limits.estimated) {
45
+ gasEstimated = true;
46
+ nativeGasLimit = limits.nativeGasLimit;
47
+ finalGasLimit = isNative ? limits.nativeGasLimit : limits.tokenGasLimit;
48
+ }
49
+ }
34
50
  const signedTxs = [];
35
51
  const extractProfit = shouldExtractProfit();
36
52
  const profitAddr = getProfitRecipient();
@@ -137,8 +153,8 @@ export async function disperseWithBundleMerkle(params) {
137
153
  // ✅ Gas limit 设置
138
154
  // - 原生代币转账:贿赂档
139
155
  // - ERC20 转账:走 GAS_LIMITS(含股票币代理)
140
- const nativeTransferGasLimit = GAS_LIMITS.BRIBE;
141
- const erc20TransferGasLimit = floorErc20TransferGasLimit(finalGasLimit);
156
+ const nativeTransferGasLimit = gasEstimated ? nativeGasLimit : GAS_LIMITS.BRIBE;
157
+ const erc20TransferGasLimit = gasEstimated ? finalGasLimit : floorErc20TransferGasLimit(finalGasLimit);
142
158
  // ✅ 原生代币多跳的 gas 费(每跳只需要 21000)
143
159
  const nativeHopGasFee = nativeTransferGasLimit * gasPrice;
144
160
  // ✅ ERC20 多跳时,中转钱包需要执行 2 笔交易(转 gas + 转 ERC20)
@@ -28,6 +28,8 @@ export interface SweepBranchContext {
28
28
  amount: SweepSignParams['amount'];
29
29
  finalGasLimit: bigint;
30
30
  nativeGasLimit: bigint;
31
+ /** 节点估算成功时不再把 ERC20 gas 抬到 12 万 */
32
+ gasEstimated?: boolean;
31
33
  /** clampRatio(ratioPct) 的结果 */
32
34
  ratio: number | undefined;
33
35
  /** 共享 NonceManager(用于统一协调 贿赂/利润提取 等 targetWallet 交易的 nonce,避免 nonce 冲突) */
@@ -8,7 +8,7 @@ import { calculateTransferFee, floorErc20TransferGasLimit } from '../../../core/
8
8
  import { batchGetBalances as _batchGetBalances, batchGetTokenAndNativeBalances, getErc20Decimals as _getErc20Decimals, } from '../../internal.js';
9
9
  import { clampRatio } from './context.js';
10
10
  export async function sweepErc20NoHop(ctx) {
11
- const { provider, chainIdNum, txType, config, target, targetWallet, tokenAddress, tokenDecimals, skipIfInsufficient, extractProfit, profitAddr, actualKeys, sources, ratios, amounts, amount, finalGasLimit, ratio, } = ctx;
11
+ const { provider, chainIdNum, txType, config, target, targetWallet, tokenAddress, tokenDecimals, skipIfInsufficient, extractProfit, profitAddr, actualKeys, sources, ratios, amounts, amount, finalGasLimit, nativeGasLimit, gasEstimated, ratio, } = ctx;
12
12
  const signedTxs = [];
13
13
  let totalProfit = 0n;
14
14
  let totalAmountBeforeProfit = 0n;
@@ -37,9 +37,8 @@ export async function sweepErc20NoHop(ctx) {
37
37
  ? (paired.native[targetIndexInSources] ?? 0n)
38
38
  : (paired.native[addresses.length] ?? 0n);
39
39
  const iface = new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
40
- // ✅ 修复:利润多跳需要 PROFIT_HOP_COUNT + 1 笔交易的 gas
41
- // ✅ 统一使用 21055n 作为利润多跳的 gas limit
42
- const PROFIT_HOP_GAS_LIMIT_ERC20 = 21055n;
40
+ const transferGasLimit = gasEstimated ? finalGasLimit : floorErc20TransferGasLimit(finalGasLimit);
41
+ const PROFIT_HOP_GAS_LIMIT_ERC20 = nativeGasLimit;
43
42
  const profitTxGas = PROFIT_HOP_GAS_LIMIT_ERC20 * gasPrice * BigInt(PROFIT_HOP_COUNT + 1);
44
43
  // ✅ 第一步:计算所有钱包的归集金额和利润,找出归集金额最大的钱包
45
44
  const sweepAmounts = [];
@@ -73,7 +72,7 @@ export async function sweepErc20NoHop(ctx) {
73
72
  continue;
74
73
  }
75
74
  // ✅ 检查 BNB 余额(只需主转账的 gas,支付者后面单独检查)
76
- const totalGasNeeded = finalGasLimit * gasPrice;
75
+ const totalGasNeeded = transferGasLimit * gasPrice;
77
76
  if (config.checkBnbForErc20NoHop) {
78
77
  const bnb = bnbBalances[i] ?? 0n;
79
78
  if (skipIfInsufficient && bnb < totalGasNeeded) {
@@ -106,7 +105,7 @@ export async function sweepErc20NoHop(ctx) {
106
105
  // ✅ 如果需要提取费用,检查支付者是否有足够原生代币支付
107
106
  if (extractProfit && nativeProfitAmount > 0n && profitPayerWalletErc20 && config.checkBnbForErc20NoHop) {
108
107
  const payerBnbBalance = useTargetAsPayerErc20 ? targetNativeBalance : (bnbBalances[maxSweepIndex] ?? 0n);
109
- const payerNeedGas = (useTargetAsPayerErc20 ? 0n : finalGasLimit * gasPrice) + profitTxGas + nativeProfitAmount;
108
+ const payerNeedGas = (useTargetAsPayerErc20 ? 0n : transferGasLimit * gasPrice) + profitTxGas + nativeProfitAmount;
110
109
  // 如果支付者原生代币余额不足,跳过费用提取
111
110
  if (payerBnbBalance < payerNeedGas) {
112
111
  nativeProfitAmount = 0n;
@@ -145,7 +144,7 @@ export async function sweepErc20NoHop(ctx) {
145
144
  value: 0n,
146
145
  nonce,
147
146
  gasPrice,
148
- gasLimit: floorErc20TransferGasLimit(finalGasLimit),
147
+ gasLimit: transferGasLimit,
149
148
  chainId: BigInt(chainIdNum),
150
149
  type: txType,
151
150
  });
@@ -8,7 +8,7 @@ import { ethers, Wallet } from 'ethers';
8
8
  import { getOptimizedGasPrice } from '../../../utils/bundle-helpers.js';
9
9
  import { CHAINS, isBscChain } from '../../../core/constants/index.js';
10
10
  import { getTxType, getGasPriceConfig, shouldExtractProfit, getProfitRecipient, getBribeAmount } from '../../config-helpers.js';
11
- import { generateHopWallets as _generateHopWallets, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress, } from '../../internal.js';
11
+ import { generateHopWallets as _generateHopWallets, calculateGasLimit as _calculateGasLimit, estimateSweepLimits, isNativeTokenAddress as _isNativeTokenAddress, } from '../../internal.js';
12
12
  import { createSignProvider, resolveHopCountInput, resolveProvidedHops, signBribeTransaction } from '../../../core/sign-context-helpers.js';
13
13
  import { NonceManager } from '../../../core/nonce/nonce-manager.js';
14
14
  import { clampRatio } from './context.js';
@@ -46,9 +46,25 @@ export async function sweepWithBundleMerkle(params) {
46
46
  const preparedHops = providedHops ?? _generateHopWallets(actualKeys.length, hopCountInput);
47
47
  const hasHops = preparedHops !== null;
48
48
  const maxHopCount = hasHops ? Math.max(...preparedHops.map((h) => h.length)) : 0;
49
- // 智能计算 Gas Limit
50
- const finalGasLimit = _calculateGasLimit(config, isNative, hasHops, maxHopCount);
51
- const nativeGasLimit = (config.prefer21000ForNative ?? false) ? 21000n : finalGasLimit;
49
+ // 先按配置算上限,再向节点估算。估算成功就用估算值,归集才不会把没用完的 gas 退回钱包。
50
+ let finalGasLimit = _calculateGasLimit(config, isNative, hasHops, maxHopCount);
51
+ let nativeGasLimit = (config.prefer21000ForNative ?? false) ? 21000n : finalGasLimit;
52
+ let gasEstimated = false;
53
+ if (actualKeys[0]) {
54
+ const limits = await estimateSweepLimits({
55
+ provider,
56
+ from: new Wallet(actualKeys[0]).address,
57
+ to: target,
58
+ tokenAddress: isNative ? undefined : tokenAddress,
59
+ nativeFallback: nativeGasLimit,
60
+ tokenFallback: finalGasLimit,
61
+ });
62
+ if (limits.estimated) {
63
+ gasEstimated = true;
64
+ nativeGasLimit = limits.nativeGasLimit;
65
+ finalGasLimit = isNative ? limits.nativeGasLimit : limits.tokenGasLimit;
66
+ }
67
+ }
52
68
  // ✅ 利润提取配置
53
69
  const extractProfit = shouldExtractProfit();
54
70
  const profitAddr = getProfitRecipient();
@@ -86,6 +102,7 @@ export async function sweepWithBundleMerkle(params) {
86
102
  amount,
87
103
  finalGasLimit,
88
104
  nativeGasLimit,
105
+ gasEstimated,
89
106
  ratio,
90
107
  nonceManager,
91
108
  };
@@ -23,9 +23,8 @@ export async function sweepNativeNoHop(ctx) {
23
23
  _batchGetBalances(provider, addresses),
24
24
  ]);
25
25
  const gasCostBase = nativeGasLimit * gasPrice;
26
- // ✅ 修复:利润多跳需要 PROFIT_HOP_COUNT + 1 笔交易的 gas(payer → hop1 → hop2 → 利润地址)
27
- // ✅ 统一使用 21055n 作为利润多跳的 gas limit
28
- const PROFIT_HOP_GAS_LIMIT = 21055n;
26
+ // 利润多跳也是原生转账,跟归集用同一个估算值
27
+ const PROFIT_HOP_GAS_LIMIT = nativeGasLimit;
29
28
  const profitTxGas = PROFIT_HOP_GAS_LIMIT * gasPrice * BigInt(PROFIT_HOP_COUNT + 1);
30
29
  // ✅ 第一步:计算所有钱包的归集金额和利润,找出归集金额最大的钱包
31
30
  const sweepAmounts = [];
@@ -8,7 +8,7 @@ import { calculateTransferFee, floorErc20TransferGasLimit, GAS_LIMITS } from '..
8
8
  import { batchGetBalances as _batchGetBalances, batchGetTokenAndNativeBalances, getErc20Decimals as _getErc20Decimals, } from '../../internal.js';
9
9
  import { clampRatio } from './context.js';
10
10
  export async function sweepWithHops(ctx, preparedHops) {
11
- const { provider, chainIdNum, txType, config, target, targetWallet, tokenAddress, tokenDecimals, skipIfInsufficient, isNative, extractProfit, profitAddr, actualKeys, sources, ratios, amounts, amount, finalGasLimit, nativeGasLimit, ratio, } = ctx;
11
+ const { provider, chainIdNum, txType, config, target, targetWallet, tokenAddress, tokenDecimals, skipIfInsufficient, isNative, extractProfit, profitAddr, actualKeys, sources, ratios, amounts, amount, finalGasLimit, nativeGasLimit, gasEstimated, ratio, } = ctx;
12
12
  const signedTxs = [];
13
13
  let totalProfit = 0n;
14
14
  let totalAmountBeforeProfit = 0n;
@@ -43,8 +43,8 @@ export async function sweepWithHops(ctx, preparedHops) {
43
43
  const bnbBalances = paired.native;
44
44
  const iface = isNative ? null : new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
45
45
  // ✅ Gas limit 设置(与分散函数保持一致)
46
- const nativeTransferGasLimit = GAS_LIMITS.BRIBE;
47
- const erc20TransferGasLimit = floorErc20TransferGasLimit(finalGasLimit);
46
+ const nativeTransferGasLimit = gasEstimated ? nativeGasLimit : GAS_LIMITS.BRIBE;
47
+ const erc20TransferGasLimit = gasEstimated ? finalGasLimit : floorErc20TransferGasLimit(finalGasLimit);
48
48
  // ✅ 原生代币多跳的 gas 费(每跳只需要 21000)
49
49
  const nativeHopGasFee = nativeTransferGasLimit * gasPrice;
50
50
  // ✅ ERC20 多跳时,中转钱包需要执行 2 笔交易(转 gas + 转 ERC20)
@@ -14,6 +14,19 @@ export declare function batchGetTokenAndNativeBalances(provider: JsonRpcProvider
14
14
  token: bigint[];
15
15
  native: bigint[];
16
16
  }>;
17
+ /** 归集/分发:按节点估算这笔转账的 gas。失败返回 null,调用方再用固定上限。 */
18
+ export declare function estimateSweepLimits(params: {
19
+ provider: JsonRpcProvider;
20
+ from: string;
21
+ to: string;
22
+ tokenAddress?: string;
23
+ nativeFallback: bigint;
24
+ tokenFallback: bigint;
25
+ }): Promise<{
26
+ nativeGasLimit: bigint;
27
+ tokenGasLimit: bigint;
28
+ estimated: boolean;
29
+ }>;
17
30
  export declare function estimateErc20TransferGas(provider: JsonRpcProvider, tokenAddress: string, from: string, to: string, amount: bigint, bufferPercent?: number): Promise<bigint>;
18
31
  export declare function estimateMaxErc20TransferGas(provider: JsonRpcProvider, tokenAddress: string, from: string, recipients: string[], amounts: bigint[], bufferPercent?: number): Promise<bigint>;
19
32
  export declare function calculateGasLimit(config: BundleGasConfig, isNative: boolean, _hasHops: boolean, _hopCount?: number): bigint;
@@ -129,6 +129,48 @@ export async function batchGetTokenAndNativeBalances(provider, addresses, tokenA
129
129
  return { token, native };
130
130
  }
131
131
  }
132
+ /** 归集/分发:按节点估算这笔转账的 gas。失败返回 null,调用方再用固定上限。 */
133
+ export async function estimateSweepLimits(params) {
134
+ try {
135
+ if (!params.tokenAddress) {
136
+ const gas = await params.provider.estimateGas({
137
+ from: params.from,
138
+ to: params.to,
139
+ value: 0n,
140
+ });
141
+ if (gas > 0n)
142
+ return { nativeGasLimit: gas, tokenGasLimit: gas, estimated: true };
143
+ }
144
+ else {
145
+ const iface = new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
146
+ const data = iface.encodeFunctionData('transfer', [params.to, 1n]);
147
+ const [tokenGas, nativeGas] = await Promise.all([
148
+ params.provider.estimateGas({
149
+ from: params.from,
150
+ to: params.tokenAddress,
151
+ data,
152
+ value: 0n,
153
+ }),
154
+ params.provider.estimateGas({ from: params.from, to: params.to, value: 0n }).catch(() => 0n),
155
+ ]);
156
+ if (tokenGas > 0n) {
157
+ return {
158
+ nativeGasLimit: nativeGas > 0n ? nativeGas : params.nativeFallback,
159
+ tokenGasLimit: tokenGas,
160
+ estimated: true,
161
+ };
162
+ }
163
+ }
164
+ }
165
+ catch {
166
+ /* 估算失败就用原来的固定上限 */
167
+ }
168
+ return {
169
+ nativeGasLimit: params.nativeFallback,
170
+ tokenGasLimit: params.tokenFallback,
171
+ estimated: false,
172
+ };
173
+ }
132
174
  export async function estimateErc20TransferGas(provider, tokenAddress, from, to, amount, bufferPercent = 5) {
133
175
  try {
134
176
  const iface = new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
@@ -47,7 +47,6 @@ export async function batchSweepEgas(params) {
47
47
  const provider = createEniProvider(rpcUrl, ENI_CHAIN_ID);
48
48
  const feeData = await provider.getFeeData();
49
49
  const maxFeePerGas = gasPrice ?? feeData.maxFeePerGas ?? feeData.gasPrice ?? 1000000000n;
50
- const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? 0n;
51
50
  const transactions = await Promise.all(privateKeys.map(async (key, i) => {
52
51
  const wallet = new Wallet(key, provider);
53
52
  const nonce = await wallet.getNonce();
@@ -58,7 +57,7 @@ export async function batchSweepEgas(params) {
58
57
  chainId: ENI_CHAIN_ID,
59
58
  type: 2,
60
59
  maxFeePerGas,
61
- maxPriorityFeePerGas,
60
+ maxPriorityFeePerGas: maxFeePerGas,
62
61
  gasLimit: GAS_NATIVE_TRANSFER,
63
62
  });
64
63
  return { signedTx, from: wallet.address, nonce };
@@ -69,8 +68,20 @@ export async function eniSweepForSubmit(params) {
69
68
  const { rpcUrl = ENI_RPC_URL, sourcePrivateKeys, target, targetPrivateKey, tokenAddress, hopCount = 0 } = params;
70
69
  const isNative = !tokenAddress || tokenAddress === ethers.ZeroAddress;
71
70
  const ratioPct = params.ratioPct ?? 100;
72
- const erc20GasLimit = params.gasLimit ? BigInt(params.gasLimit) : DEFAULT_GAS_PER_SWEEP;
73
71
  const provider = createEniProvider(rpcUrl, ENI_CHAIN_ID);
72
+ let erc20GasLimit = params.gasLimit ? BigInt(params.gasLimit) : DEFAULT_GAS_PER_SWEEP;
73
+ if (!isNative && tokenAddress && sourcePrivateKeys[0]) {
74
+ try {
75
+ const from = new Wallet(sourcePrivateKeys[0]).address;
76
+ const data = erc20Iface.encodeFunctionData('transfer', [target, 1n]);
77
+ const estimated = await provider.estimateGas({ from, to: tokenAddress, data });
78
+ if (estimated > 0n)
79
+ erc20GasLimit = estimated;
80
+ }
81
+ catch {
82
+ /* 估算失败再用表单或 20 万上限 */
83
+ }
84
+ }
74
85
  const feeData = await provider.getFeeData();
75
86
  const maxFeePerGas = feeData.maxFeePerGas ?? feeData.gasPrice ?? 1000000000n;
76
87
  const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? 0n;
@@ -1,4 +1,5 @@
1
- import { Wallet, Interface, JsonRpcProvider, formatEther, formatUnits, isHexString } from 'ethers';
1
+ import { Wallet, Interface, formatEther, formatUnits, isHexString } from 'ethers';
2
+ import { createProvider } from './provider-factory.js';
2
3
  import { CHAIN_ID_MAP, ADDRESSES } from '../core/constants/index.js';
3
4
  import { ERC20_ABI, MULTICALL3_ABI } from '../abis/common.js';
4
5
  import { getErrorMessageFromUnknown } from '../core/index.js';
@@ -247,7 +248,14 @@ async function getMulticallAddress(provider, chainId) {
247
248
  * ✅ 统一实现(精简版,复用内部函数)
248
249
  */
249
250
  export async function getTokenBalancesWithMulticall(rpcUrl, a, b, c) {
250
- const provider = new JsonRpcProvider(rpcUrl);
251
+ let chainId;
252
+ if (Array.isArray(b) && Array.isArray(c)) {
253
+ if (typeof a === 'number')
254
+ chainId = a;
255
+ else if (typeof a === 'string')
256
+ chainId = CHAIN_ID_MAP[a];
257
+ }
258
+ const provider = chainId != null ? createProvider(rpcUrl, chainId) : createProvider(rpcUrl);
251
259
  // ✅ 分支 1:rpcUrl, tokenAddresses[], holders[]
252
260
  if (Array.isArray(a) && Array.isArray(b) && typeof c === 'undefined') {
253
261
  const multicallAddress = await getMulticallAddress(provider);
@@ -255,13 +263,6 @@ export async function getTokenBalancesWithMulticall(rpcUrl, a, b, c) {
255
263
  }
256
264
  // ✅ 分支 2:rpcUrl, chain/chainId, tokenAddresses[], holders[]
257
265
  if (Array.isArray(b) && Array.isArray(c)) {
258
- let chainId;
259
- if (typeof a === 'number') {
260
- chainId = a;
261
- }
262
- else if (typeof a === 'string') {
263
- chainId = CHAIN_ID_MAP[a];
264
- }
265
266
  const multicallAddress = await getMulticallAddress(provider, chainId);
266
267
  return _queryMultiTokenBalances(provider, multicallAddress, b, c);
267
268
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "4.4.0",
3
+ "version": "4.4.2",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",