four-flap-meme-sdk 1.4.24 → 1.4.26
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.
- package/dist/abis/common.d.ts +85 -0
- package/dist/abis/common.js +242 -0
- package/dist/abis/index.d.ts +1 -0
- package/dist/abis/index.js +2 -0
- package/dist/contracts/tm-bundle-merkle/approve-tokenmanager.js +1 -6
- package/dist/contracts/tm-bundle-merkle/core.js +9 -16
- package/dist/contracts/tm-bundle-merkle/internal.js +6 -8
- package/dist/contracts/tm-bundle-merkle/pancake-proxy.d.ts +12 -6
- package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +224 -166
- package/dist/contracts/tm-bundle-merkle/private.js +6 -19
- package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +2 -7
- package/dist/contracts/tm-bundle-merkle/swap-internal.d.ts +1 -1
- package/dist/contracts/tm-bundle-merkle/swap-internal.js +9 -2
- package/dist/contracts/tm-bundle-merkle/swap.js +1 -3
- package/dist/contracts/tm-bundle-merkle/types.d.ts +20 -0
- package/dist/contracts/tm-bundle-merkle/utils.js +164 -175
- package/dist/dex/direct-router.d.ts +2 -1
- package/dist/dex/direct-router.js +25 -140
- package/dist/flap/constants.d.ts +2 -1
- package/dist/flap/constants.js +2 -1
- package/dist/flap/meta.js +6 -4
- package/dist/flap/portal-bundle-merkle/config.js +6 -12
- package/dist/flap/portal-bundle-merkle/core.js +8 -11
- package/dist/flap/portal-bundle-merkle/pancake-proxy.d.ts +12 -10
- package/dist/flap/portal-bundle-merkle/pancake-proxy.js +307 -370
- package/dist/flap/portal-bundle-merkle/private.js +1 -1
- package/dist/flap/portal-bundle-merkle/swap-buy-first.js +12 -30
- package/dist/flap/portal-bundle-merkle/swap.js +13 -26
- package/dist/flap/portal-bundle-merkle/types.d.ts +22 -2
- package/dist/flap/portal-bundle-merkle/utils.js +11 -16
- package/dist/index.d.ts +3 -2
- package/dist/index.js +9 -2
- package/dist/pancake/bundle-buy-first.js +56 -38
- package/dist/pancake/bundle-swap.js +114 -61
- package/dist/utils/bundle-helpers.d.ts +28 -0
- package/dist/utils/bundle-helpers.js +64 -0
- package/dist/utils/constants.d.ts +23 -1
- package/dist/utils/constants.js +37 -7
- package/dist/utils/erc20.js +17 -25
- package/dist/utils/lp-inspect.js +9 -20
- package/dist/utils/private-sale.js +1 -2
- package/dist/utils/quote-helpers.js +3 -29
- package/dist/utils/swap-helpers.js +1 -6
- package/dist/utils/wallet.d.ts +8 -13
- package/dist/utils/wallet.js +154 -342
- package/package.json +1 -1
|
@@ -2,8 +2,8 @@ import { ethers, Wallet } from 'ethers';
|
|
|
2
2
|
import { MerkleClient } from '../../clients/merkle.js';
|
|
3
3
|
import { getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
4
4
|
import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
|
|
5
|
+
import { ZERO_ADDRESS } from '../../utils/constants.js';
|
|
5
6
|
import { CHAIN_ID_MAP, PORTAL_ABI, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
|
|
6
|
-
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
7
7
|
const DEFAULT_GAS_LIMIT = 800000;
|
|
8
8
|
/**
|
|
9
9
|
* 私有购买(单笔)(Merkle 版本)
|
|
@@ -6,36 +6,17 @@
|
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
7
|
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
8
8
|
import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
|
|
9
|
-
import { PROFIT_CONFIG } from '../../utils/constants.js';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
'function balanceOf(address) view returns (uint256)',
|
|
18
|
-
'function decimals() view returns (uint8)'
|
|
19
|
-
];
|
|
20
|
-
const ERC20_ALLOWANCE_ABI = [
|
|
21
|
-
'function allowance(address owner,address spender) view returns (uint256)',
|
|
22
|
-
'function approve(address spender,uint256 amount) returns (bool)',
|
|
23
|
-
'function decimals() view returns (uint8)'
|
|
24
|
-
];
|
|
25
|
-
const APPROVE_INTERFACE = new ethers.Interface([
|
|
26
|
-
'function approve(address,uint256) returns (bool)'
|
|
27
|
-
]);
|
|
28
|
-
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
29
|
-
// ==================== ERC20 → 原生代币报价 ====================
|
|
30
|
-
// BSC 链常量
|
|
31
|
-
const BSC_PANCAKE_V2_ROUTER = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
|
|
32
|
-
const BSC_WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
33
|
-
// ✅ Monad 链常量
|
|
9
|
+
import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
|
|
10
|
+
import { ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI } from '../../abis/common.js';
|
|
11
|
+
import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
|
|
12
|
+
// ✅ ABI 别名
|
|
13
|
+
const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
14
|
+
// ==================== 链常量 ====================
|
|
15
|
+
const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
|
|
16
|
+
const BSC_WBNB = ADDRESSES.BSC.WBNB;
|
|
34
17
|
const MONAD_PANCAKE_V2_ROUTER = '0xb1bc24c34e88f7d43d5923034e3a14b24daacff9';
|
|
35
|
-
const MONAD_WMON =
|
|
36
|
-
const ROUTER_ABI =
|
|
37
|
-
'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)'
|
|
38
|
-
];
|
|
18
|
+
const MONAD_WMON = ADDRESSES.MONAD.WMON;
|
|
19
|
+
const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
|
|
39
20
|
/**
|
|
40
21
|
* 获取 ERC20 代币 → 原生代币的报价
|
|
41
22
|
* @param provider - Provider 实例
|
|
@@ -267,7 +248,8 @@ export async function flapBundleBuyFirstMerkle(params) {
|
|
|
267
248
|
}
|
|
268
249
|
};
|
|
269
250
|
}
|
|
270
|
-
|
|
251
|
+
// ✅ 使用公共模块中的 ERC20_BALANCE_ABI
|
|
252
|
+
const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
|
|
271
253
|
async function calculateBuyerFunds({ buyer, buyerFunds, buyerFundsPercentage, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
|
|
272
254
|
const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
|
|
273
255
|
// ✅ 根据是否使用原生代币获取不同的余额
|
|
@@ -7,41 +7,28 @@ import { ethers, Contract, Wallet } from 'ethers';
|
|
|
7
7
|
import { calculateSellAmount } from '../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
9
9
|
import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
|
|
10
|
-
import { PROFIT_CONFIG } from '../../utils/constants.js';
|
|
11
|
-
import {
|
|
10
|
+
import { PROFIT_CONFIG, ADDRESSES, ZERO_ADDRESS } from '../../utils/constants.js';
|
|
11
|
+
import { ERC20_ALLOWANCE_ABI, V2_ROUTER_QUOTE_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
|
|
12
|
+
import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
|
|
12
13
|
/**
|
|
13
|
-
* 获取 Gas Limit
|
|
14
|
+
* 获取 Gas Limit
|
|
14
15
|
*/
|
|
15
16
|
function getGasLimit(config, defaultGas = 500000) {
|
|
16
17
|
if (config.gasLimit !== undefined) {
|
|
17
18
|
return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
|
|
18
19
|
}
|
|
19
20
|
const multiplier = config.gasLimitMultiplier ?? 1.0;
|
|
20
|
-
|
|
21
|
-
return BigInt(calculatedGas);
|
|
21
|
+
return BigInt(Math.ceil(defaultGas * multiplier));
|
|
22
22
|
}
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
'function quoteExactInput((address inputToken, address outputToken, uint256 inputAmount)) view returns (uint256)'
|
|
27
|
-
];
|
|
28
|
-
const ERC20_ALLOWANCE_ABI = [
|
|
29
|
-
'function allowance(address,address) view returns (uint256)',
|
|
30
|
-
'function approve(address,uint256) returns (bool)',
|
|
31
|
-
'function decimals() view returns (uint8)'
|
|
32
|
-
];
|
|
33
|
-
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
23
|
+
// ✅ ABI 别名
|
|
24
|
+
const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
|
|
25
|
+
const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
|
|
34
26
|
const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const BSC_WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
39
|
-
// ✅ Monad 链常量
|
|
27
|
+
// ✅ 链常量
|
|
28
|
+
const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
|
|
29
|
+
const BSC_WBNB = ADDRESSES.BSC.WBNB;
|
|
40
30
|
const MONAD_PANCAKE_V2_ROUTER = '0xb1bc24c34e88f7d43d5923034e3a14b24daacff9';
|
|
41
|
-
const MONAD_WMON =
|
|
42
|
-
const ROUTER_ABI = [
|
|
43
|
-
'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)'
|
|
44
|
-
];
|
|
31
|
+
const MONAD_WMON = ADDRESSES.MONAD.WMON;
|
|
45
32
|
/**
|
|
46
33
|
* 获取 ERC20 代币 → 原生代币的报价
|
|
47
34
|
* @param provider - Provider 实例
|
|
@@ -341,7 +328,7 @@ async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, pro
|
|
|
341
328
|
throw new Error(`卖出报价失败: ${err}`);
|
|
342
329
|
}
|
|
343
330
|
}
|
|
344
|
-
|
|
331
|
+
// ✅ ERC20_BALANCE_OF_ABI 已在文件开头定义
|
|
345
332
|
async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
|
|
346
333
|
const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
|
|
347
334
|
// ✅ 根据是否使用原生代币获取不同的余额
|
|
@@ -203,6 +203,10 @@ export type PancakeProxyBatchBuyParams = {
|
|
|
203
203
|
v3Fee?: number;
|
|
204
204
|
v3LpAddresses?: string[];
|
|
205
205
|
v3ExactTokenIn?: string;
|
|
206
|
+
/** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
|
|
207
|
+
v3Tokens?: string[];
|
|
208
|
+
/** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
|
|
209
|
+
v3Fees?: number[];
|
|
206
210
|
minOutputAmounts?: (string | bigint)[];
|
|
207
211
|
config: FlapBundleMerkleConfig;
|
|
208
212
|
};
|
|
@@ -218,6 +222,10 @@ export type PancakeProxyBatchBuySignParams = {
|
|
|
218
222
|
v3Fee?: number;
|
|
219
223
|
v3LpAddresses?: string[];
|
|
220
224
|
v3ExactTokenIn?: string;
|
|
225
|
+
/** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
|
|
226
|
+
v3Tokens?: string[];
|
|
227
|
+
/** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
|
|
228
|
+
v3Fees?: number[];
|
|
221
229
|
minOutputAmounts?: (string | bigint)[];
|
|
222
230
|
config: FlapSignConfig;
|
|
223
231
|
quoteToken?: string;
|
|
@@ -240,6 +248,10 @@ export type PancakeProxyBatchSellParams = {
|
|
|
240
248
|
v3Fee?: number;
|
|
241
249
|
v3LpAddresses?: string[];
|
|
242
250
|
v3ExactTokenIn?: string;
|
|
251
|
+
/** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
|
|
252
|
+
v3Tokens?: string[];
|
|
253
|
+
/** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
|
|
254
|
+
v3Fees?: number[];
|
|
243
255
|
minOutputAmounts?: (string | bigint)[];
|
|
244
256
|
config: FlapBundleMerkleConfig;
|
|
245
257
|
};
|
|
@@ -255,13 +267,17 @@ export type PancakeProxyBatchSellSignParams = {
|
|
|
255
267
|
v3Fee?: number;
|
|
256
268
|
v3LpAddresses?: string[];
|
|
257
269
|
v3ExactTokenIn?: string;
|
|
270
|
+
/** V3 多跳:代币路径 [tokenIn, tokenMid1, ..., tokenOut] */
|
|
271
|
+
v3Tokens?: string[];
|
|
272
|
+
/** V3 多跳:费率路径 [fee0, fee1, ...] - 长度 = v3Tokens.length - 1 */
|
|
273
|
+
v3Fees?: number[];
|
|
258
274
|
minOutputAmounts?: (string | bigint)[];
|
|
259
275
|
config: FlapSignConfig;
|
|
260
276
|
};
|
|
261
277
|
/** ✅ PancakeProxy 批量卖出结果(简化版) */
|
|
262
278
|
export type PancakeProxyBatchSellResult = MerkleSignedResult;
|
|
263
279
|
/**
|
|
264
|
-
*
|
|
280
|
+
* PancakeSwap Router 单个授权参数(官方合约)
|
|
265
281
|
*/
|
|
266
282
|
export type PancakeProxyApprovalParams = {
|
|
267
283
|
chain: 'BSC';
|
|
@@ -269,9 +285,11 @@ export type PancakeProxyApprovalParams = {
|
|
|
269
285
|
tokenAddress: string;
|
|
270
286
|
amount: string | 'max';
|
|
271
287
|
rpcUrl: string;
|
|
288
|
+
/** 路由类型,用于确定授权目标(V2 或 V3 Router) */
|
|
289
|
+
routeType?: 'v2' | 'v3-single' | 'v3-multi';
|
|
272
290
|
};
|
|
273
291
|
/**
|
|
274
|
-
*
|
|
292
|
+
* PancakeSwap Router 批量授权参数(官方合约)
|
|
275
293
|
*/
|
|
276
294
|
export type PancakeProxyApprovalBatchParams = {
|
|
277
295
|
chain: FlapChainForMerkleBundle;
|
|
@@ -279,6 +297,8 @@ export type PancakeProxyApprovalBatchParams = {
|
|
|
279
297
|
tokenAddress: string;
|
|
280
298
|
amounts: (string | 'max')[];
|
|
281
299
|
config: FlapSignConfig;
|
|
300
|
+
/** 路由类型,用于确定授权目标(V2 或 V3 Router) */
|
|
301
|
+
routeType?: 'v2' | 'v3-single' | 'v3-multi';
|
|
282
302
|
};
|
|
283
303
|
/** ✅ PancakeProxy 批量授权结果 */
|
|
284
304
|
export type PancakeProxyApprovalBatchResult = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ethers, Wallet, Contract } from 'ethers';
|
|
2
2
|
import { getOptimizedGasPrice, NonceManager } from '../../utils/bundle-helpers.js';
|
|
3
|
+
import { ADDRESSES } from '../../utils/constants.js';
|
|
4
|
+
import { V2_ROUTER_QUOTE_ABI, MULTICALL3_ABI, ERC20_BALANCE_ABI } from '../../abis/common.js';
|
|
3
5
|
import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
|
|
4
6
|
// ==================== 链配置 ====================
|
|
5
7
|
const CHAIN_ID_MAP = {
|
|
@@ -7,19 +9,16 @@ const CHAIN_ID_MAP = {
|
|
|
7
9
|
'MONAD': 143,
|
|
8
10
|
'XLAYER': 196
|
|
9
11
|
};
|
|
10
|
-
// ====================
|
|
11
|
-
//
|
|
12
|
-
const BSC_PANCAKE_V2_ROUTER =
|
|
13
|
-
const BSC_WBNB =
|
|
14
|
-
// Monad 链常量
|
|
12
|
+
// ==================== 链常量 ====================
|
|
13
|
+
// ✅ 使用公共模块
|
|
14
|
+
const BSC_PANCAKE_V2_ROUTER = ADDRESSES.BSC.PancakeV2Router;
|
|
15
|
+
const BSC_WBNB = ADDRESSES.BSC.WBNB;
|
|
15
16
|
const MONAD_PANCAKE_V2_ROUTER = '0xb1bc24c34e88f7d43d5923034e3a14b24daacff9';
|
|
16
|
-
const MONAD_WMON =
|
|
17
|
-
// XLayer 链常量(PotatoSwap V2 Router)
|
|
17
|
+
const MONAD_WMON = ADDRESSES.MONAD.WMON;
|
|
18
18
|
const XLAYER_POTATOSWAP_V2_ROUTER = '0x881fb2f98c13d521009464e7d1cbf16e1b394e8e';
|
|
19
19
|
const XLAYER_WOKB = '0xe538905cf8410324e03a5a23c1c177a474d59b2b';
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
];
|
|
20
|
+
const MULTICALL3_ADDRESS = ADDRESSES.BSC.Multicall3;
|
|
21
|
+
const ROUTER_ABI = V2_ROUTER_QUOTE_ABI;
|
|
23
22
|
/**
|
|
24
23
|
* 获取 ERC20 代币 → 原生代币的报价
|
|
25
24
|
*/
|
|
@@ -101,13 +100,9 @@ async function batchGetBalances(provider, addresses, tokenAddress) {
|
|
|
101
100
|
return Promise.all(addresses.map(addr => provider.getBalance(addr).catch(() => 0n)));
|
|
102
101
|
}
|
|
103
102
|
else {
|
|
104
|
-
|
|
105
|
-
const MULTICALL3_ABI = [
|
|
106
|
-
'function aggregate3(tuple(address target, bool allowFailure, bytes callData)[] calls) view returns (tuple(bool success, bytes returnData)[] returnData)'
|
|
107
|
-
];
|
|
103
|
+
// ✅ 使用公共模块
|
|
108
104
|
const multicall = new ethers.Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
|
|
109
|
-
const
|
|
110
|
-
const iface = new ethers.Interface(ERC20_ABI);
|
|
105
|
+
const iface = new ethers.Interface(ERC20_BALANCE_ABI);
|
|
111
106
|
const calls = addresses.map(addr => ({
|
|
112
107
|
target: tokenAddress,
|
|
113
108
|
allowFailure: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * as Abis from './abis/index.js';
|
|
2
|
-
export {
|
|
2
|
+
export { ERC20_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI, MULTICALL3_ABI, V2_ROUTER_ABI, V2_ROUTER_QUOTE_ABI, V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI, V3_QUOTER_ABI, V2_FACTORY_ABI, V2_PAIR_ABI, V3_FACTORY_ABI, V3_POOL_ABI, FLAP_PORTAL_ABI, TM2_ABI, HELPER3_ABI, } from './abis/common.js';
|
|
3
|
+
export { ADDRESSES, CHAIN, BLOCKRAZOR_BUILDER_EOA as BUILDER_EOA, ZERO_ADDRESS as COMMON_ZERO_ADDRESS, DEFAULT_DEADLINE_MINUTES, V3_FEE_TIERS as COMMON_V3_FEE_TIERS, } from './utils/constants.js';
|
|
3
4
|
export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
|
|
4
5
|
export { ensureSellApprovalV1, checkSellApprovalV1, ensureSellApprovalV2, checkSellApprovalV2, ensureSellApproval, checkSellApproval, ensureFlapSellApproval, checkFlapSellApproval, ensureFlapSellApprovalBatch, checkFlapSellApprovalBatch, checkAllowance, approveToken, checkAllowanceBatch, approveTokenBatch, checkAllowanceRaw, approveTokenRaw, checkAllowanceBatchRaw, approveTokenBatchRaw, type EnsureAllowanceBatchItemResult, type ApproveTokenBatchParams, type ApproveTokenBatchRawParams, type ApproveTokenBatchResult, type ApproveTokenBatchSignResult } from './utils/erc20.js';
|
|
5
6
|
export { parseFourError, type FourErrorCode } from './utils/errors.js';
|
|
@@ -21,7 +22,7 @@ export { createTokenFlow, type CreateTokenFlowInput, type CreateTokenFlowOutput
|
|
|
21
22
|
export { Club48Client, sendBatchPrivateTransactions, sendBackrunBundle, type BundleParams, type BundleStatus, type Club48Config } from './clients/club48.js';
|
|
22
23
|
export { MerkleClient, createMerkleClient, type MerkleConfig, type BundleParams as MerkleBundleParams, type SendBundleOptions, type BundleResult, type TransactionResult } from './clients/merkle.js';
|
|
23
24
|
export { BlockRazorClient, createBlockRazorClient, BLOCKRAZOR_BUILDER_EOA, type BlockRazorConfig, type BlockRazorBundleParams, type SendBundleOptions as BlockRazorSendBundleOptions, type BundleResult as BlockRazorBundleResult, type TransactionResult as BlockRazorTransactionResult, type IncentiveTransactionParams } from './clients/blockrazor.js';
|
|
24
|
-
export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, type GasPriceConfig, type GasEstimateConfig, type BuildTransactionOptions } from './utils/bundle-helpers.js';
|
|
25
|
+
export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, getDeadline, encodeV3Path, decodeV3Path, getGasLimit, getGasPriceConfig, getTxType, getChainId, type GasPriceConfig, type GasEstimateConfig, type BuildTransactionOptions, type CommonBundleConfig, } from './utils/bundle-helpers.js';
|
|
25
26
|
export { createTokenWithBundleBuy as fourCreateTokenWithBundleBuy, batchBuyWithBundle as fourBatchBuyWithBundle, batchSellWithBundle as fourBatchSellWithBundle, type FourBundleConfig, type FourCreateWithBundleBuyParams, type FourCreateWithBundleBuyResult, type FourBatchBuyParams, type FourBatchBuyResult, type FourBatchSellParams, type FourBatchSellResult } from './contracts/tm-bundle.js';
|
|
26
27
|
export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithBundle as flapBatchBuyWithBundle, batchSellWithBundle as flapBatchSellWithBundle, type FlapBundleConfig, type FlapChainForBundle, type FlapCreateWithBundleBuyParams, type FlapCreateWithBundleBuyResult, type FlapBatchBuyParams, type FlapBatchBuyResult, type FlapBatchSellParams, type FlapBatchSellResult } from './flap/portal-bundle.js';
|
|
27
28
|
export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell, type FourPrivateBuyParams, type FourPrivateSellParams, type FourBatchPrivateBuyParams, type FourBatchPrivateSellParams } from './contracts/tm-bundle.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 公共 ABI(统一管理)
|
|
3
|
+
// ============================================================================
|
|
1
4
|
export * as Abis from './abis/index.js';
|
|
2
|
-
export {
|
|
5
|
+
export { ERC20_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI, MULTICALL3_ABI, V2_ROUTER_ABI, V2_ROUTER_QUOTE_ABI, V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI, V3_QUOTER_ABI, V2_FACTORY_ABI, V2_PAIR_ABI, V3_FACTORY_ABI, V3_POOL_ABI, FLAP_PORTAL_ABI, TM2_ABI, HELPER3_ABI, } from './abis/common.js';
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// 公共常量(统一管理)
|
|
8
|
+
// ============================================================================
|
|
9
|
+
export { ADDRESSES, CHAIN, BLOCKRAZOR_BUILDER_EOA as BUILDER_EOA, ZERO_ADDRESS as COMMON_ZERO_ADDRESS, DEFAULT_DEADLINE_MINUTES, V3_FEE_TIERS as COMMON_V3_FEE_TIERS, } from './utils/constants.js';
|
|
3
10
|
export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
|
|
4
11
|
export {
|
|
5
12
|
// Four.meme V1 授权
|
|
@@ -33,7 +40,7 @@ export { createTokenFlow } from './flows/create.js';
|
|
|
33
40
|
export { Club48Client, sendBatchPrivateTransactions, sendBackrunBundle } from './clients/club48.js';
|
|
34
41
|
export { MerkleClient, createMerkleClient } from './clients/merkle.js';
|
|
35
42
|
export { BlockRazorClient, createBlockRazorClient, BLOCKRAZOR_BUILDER_EOA } from './clients/blockrazor.js';
|
|
36
|
-
export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions } from './utils/bundle-helpers.js';
|
|
43
|
+
export { NonceManager, getOptimizedGasPrice, estimateGasWithSafety, estimateGasBatch, buildTransaction, signTransactionsBatch, signTransactionsBatchMultiWallet, validateSignedTransactions, getDeadline, encodeV3Path, decodeV3Path, getGasLimit, getGasPriceConfig, getTxType, getChainId, } from './utils/bundle-helpers.js';
|
|
37
44
|
export { createTokenWithBundleBuy as fourCreateTokenWithBundleBuy, batchBuyWithBundle as fourBatchBuyWithBundle, batchSellWithBundle as fourBatchSellWithBundle } from './contracts/tm-bundle.js';
|
|
38
45
|
export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithBundle as flapBatchBuyWithBundle, batchSellWithBundle as flapBatchSellWithBundle } from './flap/portal-bundle.js';
|
|
39
46
|
export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell } from './contracts/tm-bundle.js';
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* 功能:钱包B先买入代币 → 钱包A卖出相同数量 → 原子执行
|
|
5
5
|
*/
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
|
-
import { NonceManager } from '../utils/bundle-helpers.js';
|
|
8
|
-
import { ADDRESSES, PROFIT_CONFIG } from '../utils/constants.js';
|
|
7
|
+
import { NonceManager, getDeadline } from '../utils/bundle-helpers.js';
|
|
8
|
+
import { ADDRESSES, PROFIT_CONFIG, BLOCKRAZOR_BUILDER_EOA, ZERO_ADDRESS } from '../utils/constants.js';
|
|
9
9
|
import { quoteV2, quoteV3, getTokenToNativeQuote, getWrappedNativeAddress } from '../utils/quote-helpers.js';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI, ERC20_ALLOWANCE_ABI } from '../abis/common.js';
|
|
11
|
+
/**
|
|
12
|
+
* 获取 Gas Limit
|
|
13
|
+
*/
|
|
13
14
|
function getGasLimit(config, defaultGas = 800000) {
|
|
14
15
|
if (config.gasLimit !== undefined) {
|
|
15
16
|
return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
|
|
@@ -33,22 +34,17 @@ async function getGasPrice(provider, config) {
|
|
|
33
34
|
}
|
|
34
35
|
return gasPrice;
|
|
35
36
|
}
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const ERC20_ALLOWANCE_ABI = [
|
|
48
|
-
'function allowance(address,address) view returns (uint256)',
|
|
49
|
-
'function approve(address,uint256) returns (bool)',
|
|
50
|
-
'function decimals() view returns (uint8)'
|
|
51
|
-
];
|
|
37
|
+
// ✅ ABI 别名(从公共模块导入)
|
|
38
|
+
const PANCAKE_V2_ROUTER_ABI = V2_ROUTER_ABI;
|
|
39
|
+
const PANCAKE_V3_ROUTER_ABI = V3_ROUTER02_ABI;
|
|
40
|
+
const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
|
|
41
|
+
// ✅ 使用官方 PancakeSwap Router 地址
|
|
42
|
+
const PANCAKE_V2_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV2Router;
|
|
43
|
+
const PANCAKE_V3_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV3Router;
|
|
44
|
+
// 常量
|
|
45
|
+
const FLAT_FEE = 0n;
|
|
46
|
+
const WBNB_ADDRESS = ADDRESSES.BSC.WBNB;
|
|
47
|
+
// ✅ getDeadline 从 bundle-helpers.js 导入
|
|
52
48
|
const APPROVE_INTERFACE = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
53
49
|
export async function pancakeBundleBuyFirstMerkle(params) {
|
|
54
50
|
const { buyerPrivateKey, sellerPrivateKey, tokenAddress, routeParams, buyerFunds, buyerFundsPercentage, config, quoteToken, quoteTokenDecimals = 18 } = params;
|
|
@@ -337,7 +333,8 @@ async function ensureSellerApproval({ tokenAddress, seller, provider, decimals,
|
|
|
337
333
|
return null;
|
|
338
334
|
}
|
|
339
335
|
const erc20Contract = new Contract(tokenAddress, ERC20_ALLOWANCE_ABI, provider);
|
|
340
|
-
|
|
336
|
+
// ✅ 使用官方 V2 Router 作为授权目标
|
|
337
|
+
const currentAllowance = await erc20Contract.allowance(seller.address, PANCAKE_V2_ROUTER_ADDRESS);
|
|
341
338
|
// ✅ 阈值:MaxUint256 / 2,如果授权额度超过这个值,认为是"无限授权"
|
|
342
339
|
const halfMaxUint = ethers.MaxUint256 / 2n;
|
|
343
340
|
if (currentAllowance >= halfMaxUint) {
|
|
@@ -346,7 +343,7 @@ async function ensureSellerApproval({ tokenAddress, seller, provider, decimals,
|
|
|
346
343
|
const approvalNonce = await nonceManager.getNextNonce(seller);
|
|
347
344
|
return await seller.signTransaction({
|
|
348
345
|
to: tokenAddress,
|
|
349
|
-
data: APPROVE_INTERFACE.encodeFunctionData('approve', [
|
|
346
|
+
data: APPROVE_INTERFACE.encodeFunctionData('approve', [PANCAKE_V2_ROUTER_ADDRESS, ethers.MaxUint256]),
|
|
350
347
|
value: 0n,
|
|
351
348
|
nonce: approvalNonce,
|
|
352
349
|
gasLimit: 80000n,
|
|
@@ -356,32 +353,53 @@ async function ensureSellerApproval({ tokenAddress, seller, provider, decimals,
|
|
|
356
353
|
});
|
|
357
354
|
}
|
|
358
355
|
async function buildRouteTransactions({ routeParams, buyerFundsWei, sellAmountToken, buyer, seller, tokenAddress, useNativeToken = true }) {
|
|
359
|
-
const
|
|
360
|
-
const proxySeller = new Contract(PANCAKE_PROXY_ADDRESS, PANCAKE_PROXY_ABI, seller);
|
|
361
|
-
const deadline = Math.floor(Date.now() / 1000) + 600;
|
|
356
|
+
const deadline = getDeadline();
|
|
362
357
|
// ✅ ERC20 购买时,value 只需要 FLAT_FEE
|
|
363
358
|
const buyValue = useNativeToken ? buyerFundsWei + FLAT_FEE : FLAT_FEE;
|
|
364
359
|
if (routeParams.routeType === 'v2') {
|
|
365
360
|
const { v2Path } = routeParams;
|
|
366
361
|
const reversePath = [...v2Path].reverse();
|
|
367
|
-
|
|
368
|
-
);
|
|
369
|
-
const
|
|
362
|
+
// ✅ 使用官方 V2 Router
|
|
363
|
+
const v2RouterBuyer = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, buyer);
|
|
364
|
+
const v2RouterSeller = new Contract(PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V2_ROUTER_ABI, seller);
|
|
365
|
+
// 买入:BNB → Token
|
|
366
|
+
const buyUnsigned = await v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, v2Path, buyer.address, deadline, { value: buyValue });
|
|
367
|
+
// 卖出:Token → BNB
|
|
368
|
+
const sellUnsigned = await v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountToken, 0n, reversePath, seller.address, deadline);
|
|
370
369
|
return { buyUnsigned, sellUnsigned };
|
|
371
370
|
}
|
|
372
371
|
if (routeParams.routeType === 'v3-single') {
|
|
373
372
|
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
374
|
-
const
|
|
375
|
-
);
|
|
376
|
-
const
|
|
373
|
+
const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
|
|
374
|
+
const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
|
|
375
|
+
const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
|
|
376
|
+
// 买入:WBNB → Token
|
|
377
|
+
const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
|
|
378
|
+
tokenIn: v3TokenIn,
|
|
379
|
+
tokenOut: v3TokenOut,
|
|
380
|
+
fee: v3Fee,
|
|
381
|
+
recipient: buyer.address,
|
|
382
|
+
amountIn: buyerFundsWei,
|
|
383
|
+
amountOutMinimum: 0n,
|
|
384
|
+
sqrtPriceLimitX96: 0n
|
|
385
|
+
}]);
|
|
386
|
+
const buyUnsigned = await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
|
|
387
|
+
// 卖出:Token → WBNB → BNB
|
|
388
|
+
const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
|
|
389
|
+
tokenIn: v3TokenOut,
|
|
390
|
+
tokenOut: v3TokenIn,
|
|
391
|
+
fee: v3Fee,
|
|
392
|
+
recipient: PANCAKE_V3_ROUTER_ADDRESS,
|
|
393
|
+
amountIn: sellAmountToken,
|
|
394
|
+
amountOutMinimum: 0n,
|
|
395
|
+
sqrtPriceLimitX96: 0n
|
|
396
|
+
}]);
|
|
397
|
+
const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
|
|
398
|
+
const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
|
|
377
399
|
return { buyUnsigned, sellUnsigned };
|
|
378
400
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const buyUnsigned = await proxyBuyer.swapV3MultiHop.populateTransaction(v3LpAddresses, v3ExactTokenIn, buyerFundsWei, 0n, buyer.address, { value: buyValue } // ✅ 使用动态 value
|
|
382
|
-
);
|
|
383
|
-
const sellUnsigned = await proxySeller.swapV3MultiHop.populateTransaction(v3LpAddresses, exactTokenOut, sellAmountToken, 0n, seller.address, { value: FLAT_FEE });
|
|
384
|
-
return { buyUnsigned, sellUnsigned };
|
|
401
|
+
// V3 多跳暂不支持官方合约
|
|
402
|
+
throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
|
|
385
403
|
}
|
|
386
404
|
/**
|
|
387
405
|
* ✅ 使用 quote-helpers 统一报价(估算利润)
|