four-flap-meme-sdk 4.4.2 → 4.4.3

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.
@@ -50,8 +50,8 @@ function resolveApprovalGasLimit(config) {
50
50
  if (config.gasLimit)
51
51
  return BigInt(config.gasLimit);
52
52
  if (config.gasLimitMultiplier)
53
- return BigInt(Math.ceil(60000 * config.gasLimitMultiplier));
54
- return 60000n;
53
+ return BigInt(Math.ceil(150000 * config.gasLimitMultiplier));
54
+ return 150000n;
55
55
  }
56
56
  /**
57
57
  * 批量授权代币给 TokenManager(用于 Private Buy/Sell)
@@ -63,11 +63,20 @@ export async function signQuoteApproveIfNeeded(params) {
63
63
  if (allowance >= amount)
64
64
  return undefined;
65
65
  const unsigned = await token.approve.populateTransaction(params.spender, amount);
66
+ let gasLimit = 150000n;
67
+ try {
68
+ const estimated = await provider.estimateGas({ ...unsigned, from: params.wallet.address });
69
+ if (estimated > 0n)
70
+ gasLimit = estimated;
71
+ }
72
+ catch {
73
+ /* 估算失败用 15 万,避免代理报价币 8 万不够 */
74
+ }
66
75
  return params.wallet.signTransaction({
67
76
  ...unsigned,
68
77
  from: params.wallet.address,
69
78
  nonce: await params.getNonce(),
70
- gasLimit: 80000n,
79
+ gasLimit,
71
80
  gasPrice: params.gasPrice,
72
81
  chainId: params.chainId,
73
82
  type: params.txType,
@@ -56,11 +56,20 @@ export async function signQuoteApproveTxs(params) {
56
56
  continue;
57
57
  const token = new Contract(quoteAddress, ERC20_ABI, wallets[i]);
58
58
  const unsigned = await token.approve.populateTransaction(spender, amounts[i]);
59
+ let gasLimit = 150000n;
60
+ try {
61
+ const estimated = await provider.estimateGas({ ...unsigned, from: wallets[i].address });
62
+ if (estimated > 0n)
63
+ gasLimit = estimated;
64
+ }
65
+ catch {
66
+ /* 估算失败用 15 万 */
67
+ }
59
68
  signed.push(await wallets[i].signTransaction({
60
69
  ...unsigned,
61
70
  from: wallets[i].address,
62
71
  nonce: await nonceManager.getNextNonce(wallets[i]),
63
- gasLimit: 80000n,
72
+ gasLimit,
64
73
  gasPrice,
65
74
  chainId,
66
75
  type: txType,
@@ -1,5 +1,6 @@
1
1
  import { ethers, Contract } from 'ethers';
2
2
  import { getGasLimit } from '../../utils/bundle-helpers.js';
3
+ import { estimateApproveGasLimit } from '../../core/gas/bundle-gas.js';
3
4
  import { ADDRESSES, CHAINS, getMulticall3Address } from '../../core/constants/index.js';
4
5
  import { MULTICALL3_ABI } from '../../abis/common.js';
5
6
  import { batchGetBalances } from '../internal.js';
@@ -85,12 +86,16 @@ export function planSellerNonces(sellerNonces, needBribeTx, needApproval, extrac
85
86
  }
86
87
  export async function signTmMaxApprovalTx(seller, tokenAddress, approvalNonce, gasPrice, chainIdNum, txType) {
87
88
  const approveData = APPROVE_INTERFACE.encodeFunctionData('approve', [TM_ADDRESS, ethers.MaxUint256]);
89
+ const linked = seller.provider;
90
+ const gasLimit = linked
91
+ ? await estimateApproveGasLimit(linked, seller.address, tokenAddress, approveData)
92
+ : 150000n;
88
93
  return seller.signTransaction({
89
94
  to: tokenAddress,
90
95
  data: approveData,
91
96
  value: 0n,
92
97
  nonce: approvalNonce,
93
- gasLimit: 80000n,
98
+ gasLimit,
94
99
  gasPrice,
95
100
  chainId: chainIdNum,
96
101
  type: txType,
@@ -9,6 +9,7 @@ import { Wallet, Interface } from 'ethers';
9
9
  import { ENI_CHAIN_ID, ENI_RPC_URL } from '../constants.js';
10
10
  import { createEniProvider } from '../../../utils/provider-factory.js';
11
11
  import { ERC20_ABI } from '../../../abis/common.js';
12
+ import { estimateApproveGasLimit } from '../../../core/gas/bundle-gas.js';
12
13
  const MAX_UINT256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
13
14
  const erc20Iface = new Interface(ERC20_ABI);
14
15
  /**
@@ -33,7 +34,7 @@ export async function batchApprove(params) {
33
34
  type: 2,
34
35
  maxFeePerGas,
35
36
  maxPriorityFeePerGas,
36
- gasLimit: 60000n,
37
+ gasLimit: await estimateApproveGasLimit(provider, wallet.address, token, calldata),
37
38
  });
38
39
  return { signedTx, from: wallet.address, nonce };
39
40
  }));
@@ -14,6 +14,7 @@ import { ERC20_ABI } from '../../../abis/common.js';
14
14
  import { getProfitRecipient, calculateTransferFee } from '../../../core/constants/profit.js';
15
15
  import { GAS_LIMITS } from '../../../core/constants/gas.js';
16
16
  import { erc20Iface, DEFAULT_GAS_PER_SWEEP, GAS_NATIVE_TRANSFER } from './transfer-shared.js';
17
+ import { estimateApproveGasLimit } from '../../../core/gas/bundle-gas.js';
17
18
  // ============================================================================
18
19
  // 批量分发 EGAS (通过 BatchRouter 合约, 1 笔 tx)
19
20
  // ============================================================================
@@ -118,7 +119,7 @@ export async function eniDisperseForSubmit(params) {
118
119
  type: 2,
119
120
  maxFeePerGas,
120
121
  maxPriorityFeePerGas,
121
- gasLimit: 60000n,
122
+ gasLimit: await estimateApproveGasLimit(provider, mainWallet.address, tokenAddress, erc20Iface.encodeFunctionData('approve', [routerAddr, ethers.MaxUint256])),
122
123
  });
123
124
  signedTxs.push(approveTx);
124
125
  }
@@ -173,7 +173,7 @@ export async function addLiquidityETHForSubmit(params) {
173
173
  type: 2,
174
174
  maxFeePerGas,
175
175
  maxPriorityFeePerGas,
176
- gasLimit: 60000n,
176
+ gasLimit: 150000n,
177
177
  });
178
178
  signedTxs.push(approveTx);
179
179
  }
@@ -280,7 +280,7 @@ export async function removeLiquidityETHForSubmit(params) {
280
280
  type: 2,
281
281
  maxFeePerGas,
282
282
  maxPriorityFeePerGas,
283
- gasLimit: 60000n,
283
+ gasLimit: 150000n,
284
284
  });
285
285
  signedTxs.push(approveTx);
286
286
  }
@@ -364,7 +364,7 @@ export async function addLiquidityForSubmit(params) {
364
364
  type: 2,
365
365
  maxFeePerGas,
366
366
  maxPriorityFeePerGas,
367
- gasLimit: 60000n,
367
+ gasLimit: 150000n,
368
368
  });
369
369
  signedTxs.push(approveTx);
370
370
  }
@@ -439,7 +439,7 @@ export async function removeLiquidityForSubmit(params) {
439
439
  type: 2,
440
440
  maxFeePerGas,
441
441
  maxPriorityFeePerGas,
442
- gasLimit: 60000n,
442
+ gasLimit: 150000n,
443
443
  });
444
444
  signedTxs.push(approveTx);
445
445
  }
@@ -17,6 +17,20 @@ export async function signRobinhoodTx(params) {
17
17
  if (maxFeePerGas < floor)
18
18
  maxFeePerGas = floor;
19
19
  const maxPriorityFeePerGas = priority > maxFeePerGas ? maxFeePerGas : priority;
20
+ let gasLimit = params.gasLimit;
21
+ try {
22
+ const estimated = await provider.estimateGas({
23
+ from: wallet.address,
24
+ to: params.to,
25
+ data: params.data,
26
+ value: params.value ?? 0n,
27
+ });
28
+ if (estimated > 0n)
29
+ gasLimit = estimated;
30
+ }
31
+ catch {
32
+ /* 节点没给出上限时用服务端配置 */
33
+ }
20
34
  const signedTx = await wallet.signTransaction({
21
35
  to: params.to,
22
36
  value: params.value ?? 0n,
@@ -26,7 +40,7 @@ export async function signRobinhoodTx(params) {
26
40
  type: 2,
27
41
  maxFeePerGas,
28
42
  maxPriorityFeePerGas,
29
- gasLimit: params.gasLimit,
43
+ gasLimit,
30
44
  });
31
45
  const tx = Transaction.from(signedTx);
32
46
  return {
@@ -52,3 +52,11 @@ export type Eip1559GasFields = {
52
52
  };
53
53
  export type TxGasFields = LegacyGasFields | Eip1559GasFields;
54
54
  export declare function buildGasFields(txType: number, gasPrice: bigint): TxGasFields;
55
+ /** 向节点 eth_estimateGas 要这笔 approve 的 gas 上限。节点没返回时才用 fallback。 */
56
+ export declare function estimateApproveGasLimit(provider: {
57
+ estimateGas: (tx: {
58
+ from?: string;
59
+ to?: string;
60
+ data?: string;
61
+ }) => Promise<bigint>;
62
+ }, from: string, to: string, data: string, fallback?: bigint): Promise<bigint>;
@@ -23,7 +23,7 @@ export async function getOptimizedGasPrice(provider, config) {
23
23
  return gasPrice;
24
24
  }
25
25
  export async function estimateGasWithSafety(provider, txRequest, config) {
26
- const multiplier = config?.multiplier ?? 1.2;
26
+ const multiplier = config?.multiplier ?? 1;
27
27
  const fallback = config?.fallbackGasLimit ?? 600000n;
28
28
  const allowFailure = config?.allowFailure ?? true;
29
29
  try {
@@ -91,3 +91,15 @@ export function buildGasFields(txType, gasPrice) {
91
91
  }
92
92
  return { type: 0, gasPrice };
93
93
  }
94
+ /** 向节点 eth_estimateGas 要这笔 approve 的 gas 上限。节点没返回时才用 fallback。 */
95
+ export async function estimateApproveGasLimit(provider, from, to, data, fallback = 150000n) {
96
+ try {
97
+ const estimated = await provider.estimateGas({ from, to, data });
98
+ if (estimated > 0n)
99
+ return estimated;
100
+ }
101
+ catch {
102
+ /* 节点没给出上限 */
103
+ }
104
+ return fallback;
105
+ }
@@ -3,16 +3,62 @@
3
3
  * 模块加载时 patch Wallet.prototype.signTransaction(全局一次)
4
4
  */
5
5
  import { Wallet } from 'ethers';
6
+ function chainGasPrice(fee) {
7
+ const candidates = [fee.maxFeePerGas, fee.gasPrice].filter((v) => v != null && v > 0n);
8
+ if (candidates.length === 0)
9
+ return null;
10
+ return candidates.reduce((a, b) => (a > b ? a : b));
11
+ }
6
12
  const _origWalletSign = Wallet.prototype.signTransaction;
7
13
  Wallet.prototype.signTransaction = async function (tx) {
8
- const signable = tx;
14
+ let signable = tx;
9
15
  if (signable.type === 2 && signable.gasPrice != null && signable.maxFeePerGas == null) {
10
16
  const { gasPrice: gp, ...rest } = signable;
11
- return _origWalletSign.call(this, {
17
+ signable = {
12
18
  ...rest,
13
19
  maxFeePerGas: gp,
14
20
  maxPriorityFeePerGas: rest.maxPriorityFeePerGas ?? 0n,
15
- });
21
+ };
16
22
  }
17
- return _origWalletSign.call(this, tx);
23
+ const provider = this.provider;
24
+ if (provider) {
25
+ const hasPrice = (signable.gasPrice != null && signable.gasPrice > 0n)
26
+ || (signable.maxFeePerGas != null && signable.maxFeePerGas > 0n);
27
+ if (!hasPrice) {
28
+ try {
29
+ const fee = await provider.getFeeData();
30
+ const chainPrice = chainGasPrice(fee);
31
+ if (chainPrice) {
32
+ if (signable.type === 2) {
33
+ let priority = fee.maxPriorityFeePerGas && fee.maxPriorityFeePerGas > 0n
34
+ ? fee.maxPriorityFeePerGas
35
+ : chainPrice / 10n || 1n;
36
+ if (priority > chainPrice)
37
+ priority = chainPrice;
38
+ signable = { ...signable, maxFeePerGas: chainPrice, maxPriorityFeePerGas: priority };
39
+ }
40
+ else {
41
+ signable = { ...signable, gasPrice: chainPrice };
42
+ }
43
+ }
44
+ }
45
+ catch {
46
+ /* 节点没给出 gas 价格时保留交易上已有的出价 */
47
+ }
48
+ }
49
+ try {
50
+ const estimated = await provider.estimateGas({
51
+ from: signable.from ?? this.address,
52
+ to: signable.to,
53
+ data: signable.data,
54
+ value: signable.value,
55
+ });
56
+ if (estimated > 0n)
57
+ signable = { ...signable, gasLimit: estimated };
58
+ }
59
+ catch {
60
+ /* 节点没给出 gas 上限时保留原来的上限,避免发不出去 */
61
+ }
62
+ }
63
+ return _origWalletSign.call(this, signable);
18
64
  };
@@ -3,7 +3,7 @@
3
3
  * 从 direct-router-v2.ts 抽取,direct-router-v2.ts 通过 re-export 保持对外不变。
4
4
  */
5
5
  import { ethers, Wallet, Contract } from 'ethers';
6
- import { getGasLimit } from '../../core/gas/bundle-gas.js';
6
+ import { estimateApproveGasLimit, getGasLimit } from '../../core/gas/bundle-gas.js';
7
7
  import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, buildGasFields, } from '../../utils/bundle-helpers.js';
8
8
  import { getProfitRecipient, CHAINS, GAS_LIMITS } from '../../core/constants/index.js';
9
9
  import { ERC20_ABI } from '../../abis/common.js';
@@ -88,12 +88,13 @@ export async function directV2BatchBuy(params) {
88
88
  continue;
89
89
  if (activeBuyAllowances[i] < activeFlowAmounts[i]) {
90
90
  const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [router, ethers.MaxUint256]);
91
+ const approveGasLimit = await estimateApproveGasLimit(provider, activeWallets[i].address, inputToken, approveData);
91
92
  const approveTx = await activeWallets[i].signTransaction({
92
93
  to: inputToken,
93
94
  data: approveData,
94
95
  value: 0n,
95
96
  nonce: activeNonces[i],
96
- gasLimit: 60000n,
97
+ gasLimit: approveGasLimit,
97
98
  ...buildGasFields(txType, gasPrice),
98
99
  chainId,
99
100
  });
@@ -3,7 +3,7 @@
3
3
  * 从 direct-router-v2.ts 抽取,direct-router-v2.ts 通过 re-export 保持对外不变。
4
4
  */
5
5
  import { ethers, Interface, Wallet, Contract } from 'ethers';
6
- import { getGasLimit } from '../../core/gas/bundle-gas.js';
6
+ import { estimateApproveGasLimit, getGasLimit } from '../../core/gas/bundle-gas.js';
7
7
  import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, buildGasFields, } from '../../utils/bundle-helpers.js';
8
8
  import { getProfitRecipient, CHAINS, GAS_LIMITS, getMulticall3Address } from '../../core/constants/index.js';
9
9
  import { MULTICALL3_ABI } from '../../abis/common.js';
@@ -124,12 +124,13 @@ export async function directV2BatchSell(params) {
124
124
  continue;
125
125
  if (allowances[i] < sellAmountsWei[i]) {
126
126
  const approveData = tokenContract.interface.encodeFunctionData('approve', [router, ethers.MaxUint256]);
127
+ const approveGasLimit = await estimateApproveGasLimit(provider, wallets[i].address, tokenIn, approveData);
127
128
  const approveTx = await wallets[i].signTransaction({
128
129
  to: tokenIn,
129
130
  data: approveData,
130
131
  value: 0n,
131
132
  nonce: nonces[i],
132
- gasLimit: 60000n,
133
+ gasLimit: approveGasLimit,
133
134
  ...buildGasFields(txType, gasPrice),
134
135
  chainId,
135
136
  });
@@ -38,7 +38,7 @@ export function getErrorMessage(key, ...args) {
38
38
  */
39
39
  export async function estimateGasWithMultiplier(provider, txRequest, multiplier) {
40
40
  const estimated = await provider.estimateGas(txRequest);
41
- const mult = multiplier ?? 1.2; // 默认 20% 安全余量
41
+ const mult = multiplier ?? 1;
42
42
  return BigInt(Math.ceil(Number(estimated) * mult));
43
43
  }
44
44
  /**
@@ -5,6 +5,7 @@ import { ZERO_ADDRESS, calculateBundleSwapRoundTripProfit } from '../../../core/
5
5
  import { ERC20_ALLOWANCE_ABI } from '../../../core/shared-abis/common.js';
6
6
  import { getGasPriceConfig, getTxType, getProfitRecipient, PORTAL_ABI } from './config.js';
7
7
  import { getErrorMessageFromUnknown } from '../../../core/index.js';
8
+ import { estimateApproveGasLimit } from '../../../core/gas/bundle-gas.js';
8
9
  import { createSignProvider } from '../../../bundle/sign-context-helpers.js';
9
10
  import { batchGetBalances } from '../../../bundle/internal.js';
10
11
  import { APPROVE_INTERFACE, ERC20_BALANCE_OF_ABI, getChainId, getNativeTokenName, } from './swap-helpers.js';
@@ -38,12 +39,14 @@ export async function buildApprovalTransaction({ tokenAddress, seller, provider,
38
39
  const approvalNonce = await nonceManager.getNextNonce(seller);
39
40
  const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
40
41
  const txType = getTxType(config);
42
+ const approveData = APPROVE_INTERFACE.encodeFunctionData('approve', [portalAddress, ethers.MaxUint256]);
43
+ const gasLimit = await estimateApproveGasLimit(provider, seller.address, tokenAddress, approveData);
41
44
  return await seller.signTransaction({
42
45
  to: tokenAddress,
43
- data: APPROVE_INTERFACE.encodeFunctionData('approve', [portalAddress, ethers.MaxUint256]),
46
+ data: approveData,
44
47
  value: 0n,
45
48
  nonce: approvalNonce,
46
- gasLimit: 80000n,
49
+ gasLimit,
47
50
  gasPrice,
48
51
  chainId,
49
52
  type: txType,
@@ -136,11 +136,23 @@ export async function createTokenWithBundleBuy(params) {
136
136
  const amount = ethers.parseUnits(preSaleStr, decimals);
137
137
  if (allowance < amount) {
138
138
  const approveUnsigned = await quote.approve.populateTransaction(tmAddr, amount);
139
+ let approveGasLimit = 150000n;
140
+ try {
141
+ const estimatedApprove = await provider.estimateGas({
142
+ ...approveUnsigned,
143
+ from: devWallet.address,
144
+ });
145
+ if (estimatedApprove > 0n)
146
+ approveGasLimit = estimatedApprove;
147
+ }
148
+ catch {
149
+ /* 估算失败用 15 万 */
150
+ }
139
151
  const signedApprove = await devWallet.signTransaction({
140
152
  ...approveUnsigned,
141
153
  from: devWallet.address,
142
154
  nonce: await getNextNonce(devWallet),
143
- gasLimit: 80000n,
155
+ gasLimit: approveGasLimit,
144
156
  gasPrice,
145
157
  chainId: CHAINS.BSC.chainId,
146
158
  type: 0,
@@ -41,7 +41,7 @@ export async function waitForBundleWithProvider(provider, firstTxSigned, _bundle
41
41
  */
42
42
  export async function estimateGasWithMultiplier(provider, txRequest, multiplier) {
43
43
  const estimated = await provider.estimateGas(txRequest);
44
- const mult = multiplier ?? 1.2; // 默认 20% 安全余量
44
+ const mult = multiplier ?? 1;
45
45
  return BigInt(Math.ceil(Number(estimated) * mult));
46
46
  }
47
47
  /**
@@ -1,6 +1,6 @@
1
1
  export declare const ERC20_TRANSFER_GAS_LIMIT: 120000n;
2
2
  /** SPCXB 等股票币 approve 实测 >50k,空钱包 eth_estimate ~55k */
3
- export declare const ERC20_APPROVE_GAS_LIMIT = 80000n;
3
+ export declare const ERC20_APPROVE_GAS_LIMIT = 150000n;
4
4
  export declare const DEFAULT_GAS_LIMIT = 800000;
5
5
  export declare const DEFAULT_GAS_PRICE_GWEI = 3;
6
6
  export declare const GAS_BUFFER_MULTIPLIER = 2;
@@ -1,7 +1,7 @@
1
1
  import { GAS_LIMITS } from '../../../core/constants/index.js';
2
2
  export const ERC20_TRANSFER_GAS_LIMIT = GAS_LIMITS.ERC20_TRANSFER;
3
3
  /** SPCXB 等股票币 approve 实测 >50k,空钱包 eth_estimate ~55k */
4
- export const ERC20_APPROVE_GAS_LIMIT = 80000n;
4
+ export const ERC20_APPROVE_GAS_LIMIT = 150000n;
5
5
  export const DEFAULT_GAS_LIMIT = 800000;
6
6
  export const DEFAULT_GAS_PRICE_GWEI = 3;
7
7
  export const GAS_BUFFER_MULTIPLIER = 2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "4.4.2",
3
+ "version": "4.4.3",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",