four-flap-meme-sdk 4.0.14 → 4.1.1
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/bundle/four-meme/core/sell-flow.js +6 -9
- package/dist/bundle/four-meme/pancake-proxy/helpers.d.ts +5 -38
- package/dist/bundle/four-meme/pancake-proxy/helpers.js +5 -228
- package/dist/bundle/four-meme/private/sell.js +5 -5
- package/dist/bundle/four-meme/swap-hop-helpers.d.ts +1 -5
- package/dist/bundle/four-meme/swap-hop-helpers.js +1 -63
- package/dist/bundle/four-meme/types/bundle-ops.d.ts +166 -0
- package/dist/bundle/four-meme/types/bundle-ops.js +4 -0
- package/dist/bundle/four-meme/types/buy-first.d.ts +1 -1
- package/dist/bundle/four-meme/types/config.d.ts +95 -0
- package/dist/bundle/four-meme/types/config.js +1 -0
- package/dist/bundle/four-meme/types/core-flow.d.ts +2 -1
- package/dist/bundle/four-meme/types/index.d.ts +5 -611
- package/dist/bundle/four-meme/types/pancake-proxy-types.d.ts +118 -0
- package/dist/bundle/four-meme/types/pancake-proxy-types.js +3 -0
- package/dist/bundle/four-meme/types/swap-types.d.ts +103 -0
- package/dist/bundle/four-meme/types/swap-types.js +1 -0
- package/dist/bundle/four-meme/types/transfer-ops.d.ts +134 -0
- package/dist/bundle/four-meme/types/transfer-ops.js +1 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-build.d.ts +5 -3
- package/dist/chains/bsc/pancake/bundle-buy-first-build.js +25 -23
- package/dist/chains/bsc/pancake/bundle-buy-first-multi-wallet.js +6 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-types.d.ts +4 -0
- package/dist/chains/bsc/pancake/bundle-buy-first.js +6 -0
- package/dist/chains/bsc/pancake/bundle-swap-types.d.ts +4 -0
- package/dist/chains/bsc/pancake/hop-chain.d.ts +1 -18
- package/dist/chains/bsc/pancake/hop-chain.js +1 -229
- package/dist/chains/bsc/pancake/quote.d.ts +18 -1
- package/dist/chains/bsc/pancake/quote.js +39 -1
- package/dist/chains/bsc/pancake/quote.test.d.ts +1 -0
- package/dist/chains/bsc/pancake/quote.test.js +28 -0
- package/dist/chains/bsc/pancake/swap-batch.js +16 -7
- package/dist/chains/bsc/pancake/swap-build.d.ts +1 -1
- package/dist/chains/bsc/pancake/swap-build.js +9 -18
- package/dist/chains/bsc/pancake/swap-quick.js +16 -7
- package/dist/chains/bsc/pancake/swap-single.js +10 -1
- package/dist/chains/eni/platforms/daoaas/portal-direct-submit.js +2 -6
- package/dist/chains/xlayer/eip7702/types-base.d.ts +44 -0
- package/dist/chains/xlayer/eip7702/types-base.js +4 -0
- package/dist/chains/xlayer/eip7702/types-bundle.d.ts +191 -0
- package/dist/chains/xlayer/eip7702/types-bundle.js +1 -0
- package/dist/chains/xlayer/eip7702/types-create.d.ts +222 -0
- package/dist/chains/xlayer/eip7702/types-create.js +1 -0
- package/dist/chains/xlayer/eip7702/types-transfer.d.ts +124 -0
- package/dist/chains/xlayer/eip7702/types-transfer.js +1 -0
- package/dist/chains/xlayer/eip7702/types.d.ts +4 -578
- package/dist/chains/xlayer/eip7702/types.js +0 -3
- package/dist/chains/xlayer/eoa/eoa-dex-types.d.ts +196 -0
- package/dist/chains/xlayer/eoa/eoa-dex-types.js +1 -0
- package/dist/chains/xlayer/eoa/eoa-swap-types.d.ts +283 -0
- package/dist/chains/xlayer/eoa/eoa-swap-types.js +1 -0
- package/dist/chains/xlayer/eoa/eoa-trade-types.d.ts +300 -0
- package/dist/chains/xlayer/eoa/eoa-trade-types.js +6 -0
- package/dist/chains/xlayer/eoa/eoa-types.d.ts +4 -774
- package/dist/chains/xlayer/eoa/eoa-types.js +0 -5
- package/dist/chains/xlayer/eoa/eoa-wash-volume.js +2 -13
- package/dist/chains/xlayer/eoa/hop-chain.d.ts +1 -1
- package/dist/chains/xlayer/eoa/hop-chain.js +4 -83
- package/dist/core/constants/index.d.ts +1 -0
- package/dist/core/constants/index.js +1 -0
- package/dist/core/constants/slippage.d.ts +6 -0
- package/dist/core/constants/slippage.js +15 -0
- package/dist/domains/flap/portal-bundle-merkle/core-helpers.d.ts +1 -1
- package/dist/domains/flap/portal-bundle-merkle/core-helpers.js +6 -4
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/helpers.d.ts +2 -43
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/helpers.js +8 -208
- package/dist/domains/flap/portal-bundle-merkle/private/helpers.js +2 -2
- package/dist/domains/flap/portal-bundle-merkle/private/sell.js +17 -20
- package/dist/domains/flap/portal-bundle-merkle/swap-helpers.d.ts +4 -24
- package/dist/domains/flap/portal-bundle-merkle/swap-helpers.js +12 -166
- package/dist/domains/flap/portal-bundle-merkle/types-bundle.d.ts +137 -0
- package/dist/domains/flap/portal-bundle-merkle/types-bundle.js +7 -0
- package/dist/domains/flap/portal-bundle-merkle/types-config.d.ts +118 -0
- package/dist/domains/flap/portal-bundle-merkle/types-config.js +4 -0
- package/dist/domains/flap/portal-bundle-merkle/types-pancake.d.ts +118 -0
- package/dist/domains/flap/portal-bundle-merkle/types-pancake.js +4 -0
- package/dist/domains/flap/portal-bundle-merkle/types-transfer.d.ts +70 -0
- package/dist/domains/flap/portal-bundle-merkle/types-transfer.js +1 -0
- package/dist/domains/flap/portal-bundle-merkle/types.d.ts +4 -441
- package/dist/domains/holders/internal/disperse.js +2 -18
- package/dist/domains/lp-inspect/inspect-helpers.d.ts +1 -0
- package/dist/domains/lp-inspect/inspect-helpers.js +3 -16
- package/dist/utils/hop-chains.d.ts +0 -3
- package/dist/utils/hop-chains.js +4 -5
- package/dist/utils/pancake-router-tx.d.ts +41 -0
- package/dist/utils/pancake-router-tx.js +174 -0
- package/dist/utils/swap-helpers.d.ts +6 -2
- package/dist/utils/swap-helpers.js +24 -4
- package/dist/utils/wallet.js +12 -12
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { ethers, Contract, Interface } from 'ethers';
|
|
5
5
|
import { getGasLimit } from '../../../core/gas/bundle-gas.js';
|
|
6
6
|
import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
7
|
-
import { ADDRESSES } from '../../../core/constants/index.js';
|
|
7
|
+
import { ADDRESSES, CHAINS, applySlippageBps, reverseSlippageBps } from '../../../core/constants/index.js';
|
|
8
8
|
import { MULTICALL3_ABI, ERC20_ABI } from '../../../abis/common.js';
|
|
9
9
|
import { getBundleErrorMessage } from '../../errors.js';
|
|
10
10
|
import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount, } from '../../config-helpers.js';
|
|
@@ -123,7 +123,7 @@ async function resolveSellOutputs(params) {
|
|
|
123
123
|
// 如果已提供 minOutputAmounts,直接使用,跳过报价查询
|
|
124
124
|
if (minOutputAmounts && minOutputAmounts.length === sellers.length) {
|
|
125
125
|
const minOuts = minOutputAmounts.map((m) => (typeof m === 'string' ? ethers.parseEther(m) : m));
|
|
126
|
-
const quotedOutputs = minOuts.map((value) => (value
|
|
126
|
+
const quotedOutputs = minOuts.map((value) => reverseSlippageBps(value));
|
|
127
127
|
return { minOuts, quotedOutputs };
|
|
128
128
|
}
|
|
129
129
|
// 如果只有 1 个,直接调用(避免 multicall 开销)
|
|
@@ -131,8 +131,7 @@ async function resolveSellOutputs(params) {
|
|
|
131
131
|
try {
|
|
132
132
|
const result = await trySell('BSC', rpcUrl, tokenAddress, amountsWei[0]);
|
|
133
133
|
const quotedOutputs = [result.funds];
|
|
134
|
-
|
|
135
|
-
const minOuts = [0n];
|
|
134
|
+
const minOuts = [applySlippageBps(result.funds)];
|
|
136
135
|
return { minOuts, quotedOutputs };
|
|
137
136
|
}
|
|
138
137
|
catch {
|
|
@@ -140,7 +139,7 @@ async function resolveSellOutputs(params) {
|
|
|
140
139
|
}
|
|
141
140
|
}
|
|
142
141
|
// ✅ 使用 Multicall3 批量获取报价
|
|
143
|
-
const provider = createSignProvider(rpcUrl,
|
|
142
|
+
const provider = createSignProvider(rpcUrl, CHAINS.BSC.chainId, 'BSC');
|
|
144
143
|
const helper3Address = ADDRESSES.BSC.TokenManagerHelper3;
|
|
145
144
|
const helper3Iface = new Interface(Helper3Abi);
|
|
146
145
|
const multicall = new Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
|
|
@@ -165,8 +164,7 @@ async function resolveSellOutputs(params) {
|
|
|
165
164
|
}
|
|
166
165
|
return 0n;
|
|
167
166
|
});
|
|
168
|
-
|
|
169
|
-
const minOuts = quotedOutputs.map(() => 0n);
|
|
167
|
+
const minOuts = quotedOutputs.map((q) => applySlippageBps(q));
|
|
170
168
|
return { minOuts, quotedOutputs };
|
|
171
169
|
}
|
|
172
170
|
catch {
|
|
@@ -180,8 +178,7 @@ async function resolveSellOutputs(params) {
|
|
|
180
178
|
return 0n;
|
|
181
179
|
}
|
|
182
180
|
}));
|
|
183
|
-
|
|
184
|
-
const minOuts = quotedOutputs.map(() => 0n);
|
|
181
|
+
const minOuts = quotedOutputs.map((q) => applySlippageBps(q));
|
|
185
182
|
return { minOuts, quotedOutputs };
|
|
186
183
|
}
|
|
187
184
|
}
|
|
@@ -1,45 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PancakeSwap 官方 Router 交易模块 —
|
|
2
|
+
* PancakeSwap 官方 Router 交易模块 — four-meme 辅助
|
|
3
|
+
*
|
|
4
|
+
* 交易构建 / 报价 / 授权目标与 flap 共用 utils/pancake-router-tx。
|
|
5
|
+
* decimals 不走缓存,与原先 four-meme 调用约定一致。
|
|
3
6
|
*/
|
|
4
|
-
import { Wallet, Contract } from 'ethers';
|
|
5
7
|
import type { JsonRpcProvider } from 'ethers';
|
|
6
|
-
import type { ContractTransaction } from 'ethers/contract';
|
|
7
8
|
import type { FourPancakeProxyBatchBuySignParams } from '../types/index.js';
|
|
8
|
-
|
|
9
|
-
* 查询代币 decimals
|
|
10
|
-
*/
|
|
9
|
+
export { buildV2Transactions, buildV3SingleTransactions, buildV3MultiHopTransactions, batchGetV2Quotes, getApprovalTarget, } from '../../../utils/pancake-router-tx.js';
|
|
11
10
|
export declare function getTokenDecimals(tokenAddress: string, provider: JsonRpcProvider): Promise<number>;
|
|
12
|
-
/**
|
|
13
|
-
* 判断是否需要发送 BNB
|
|
14
|
-
*/
|
|
15
11
|
export type PancakeBuyRouteFields = Pick<FourPancakeProxyBatchBuySignParams, 'v2Path' | 'v3TokenIn' | 'v3ExactTokenIn'>;
|
|
16
12
|
export declare function needSendBNB(routeType: FourPancakeProxyBatchBuySignParams['routeType'], params: PancakeBuyRouteFields): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* ✅ 构建 V2 交易(使用官方 Router)
|
|
19
|
-
*/
|
|
20
|
-
export declare function buildV2Transactions(routers: Contract[], wallets: Wallet[], amountsWei: bigint[], minOuts: bigint[], path: string[], isBuy: boolean, needBNB: boolean): Promise<ContractTransaction[]>;
|
|
21
|
-
/**
|
|
22
|
-
* ✅ 构建 V3 单跳交易(使用官方 SwapRouter02 + multicall)
|
|
23
|
-
*/
|
|
24
|
-
export declare function buildV3SingleTransactions(routers: Contract[], wallets: Wallet[], tokenIn: string, tokenOut: string, fee: number, amountsWei: bigint[], minOuts: bigint[], isBuy: boolean, needBNB: boolean): Promise<ContractTransaction[]>;
|
|
25
|
-
/**
|
|
26
|
-
* ✅ 构建 V3 多跳交易(使用官方 SwapRouter02 的 exactInput)
|
|
27
|
-
*
|
|
28
|
-
* @param routers - V3 Router 合约数组
|
|
29
|
-
* @param wallets - 钱包数组
|
|
30
|
-
* @param tokens - 代币路径 [tokenIn, tokenMid1, ..., tokenOut]
|
|
31
|
-
* @param fees - 费率路径 [fee0, fee1, ...]
|
|
32
|
-
* @param amountsWei - 每个钱包的输入金额
|
|
33
|
-
* @param minOuts - 最小输出金额
|
|
34
|
-
* @param isBuy - 是否为买入操作
|
|
35
|
-
* @param needBNB - 是否需要发送 BNB
|
|
36
|
-
*/
|
|
37
|
-
export declare function buildV3MultiHopTransactions(routers: Contract[], wallets: Wallet[], tokens: string[], fees: number[], amountsWei: bigint[], minOuts: bigint[], isBuy: boolean, needBNB: boolean): Promise<ContractTransaction[]>;
|
|
38
|
-
/**
|
|
39
|
-
* ✅ 使用 Multicall3 批量获取 V2 报价
|
|
40
|
-
*/
|
|
41
|
-
export declare function batchGetV2Quotes(provider: JsonRpcProvider, amountsWei: bigint[], v2Path: string[]): Promise<bigint[]>;
|
|
42
|
-
/**
|
|
43
|
-
* 根据 routeType 获取授权目标地址
|
|
44
|
-
*/
|
|
45
|
-
export declare function getApprovalTarget(routeType: string): string;
|
|
@@ -1,232 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { Contract, Interface } from 'ethers';
|
|
5
|
-
import { getDeadline, encodeV3Path } from '../../../utils/bundle-helpers.js';
|
|
6
|
-
import { V2_ROUTER_ABI, ERC20_ABI, MULTICALL3_ABI } from '../../../abis/common.js';
|
|
7
|
-
import { MULTICALL3_ADDRESS, WBNB_ADDRESS, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ADDRESS, V3_ROUTER_ABI, } from './constants.js';
|
|
8
|
-
/**
|
|
9
|
-
* 查询代币 decimals
|
|
10
|
-
*/
|
|
1
|
+
import { getTokenDecimals as fetchTokenDecimals } from '../../../utils/swap-helpers.js';
|
|
2
|
+
import { needSendBNBFromRoute } from '../../../utils/pancake-router-tx.js';
|
|
3
|
+
export { buildV2Transactions, buildV3SingleTransactions, buildV3MultiHopTransactions, batchGetV2Quotes, getApprovalTarget, } from '../../../utils/pancake-router-tx.js';
|
|
11
4
|
export async function getTokenDecimals(tokenAddress, provider) {
|
|
12
|
-
|
|
13
|
-
const token = new Contract(tokenAddress, ERC20_ABI, provider);
|
|
14
|
-
const decimals = await token.decimals();
|
|
15
|
-
return Number(decimals);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return 18;
|
|
19
|
-
}
|
|
5
|
+
return fetchTokenDecimals(provider, tokenAddress, { fallback: 18 });
|
|
20
6
|
}
|
|
21
7
|
export function needSendBNB(routeType, params) {
|
|
22
|
-
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
if (routeType === 'v3-single' && params.v3TokenIn && params.v3TokenIn.toLowerCase() === WBNB_ADDRESS.toLowerCase()) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
if (routeType === 'v3-multi' &&
|
|
29
|
-
params.v3ExactTokenIn &&
|
|
30
|
-
params.v3ExactTokenIn.toLowerCase() === WBNB_ADDRESS.toLowerCase()) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* ✅ 构建 V2 交易(使用官方 Router)
|
|
37
|
-
*/
|
|
38
|
-
export async function buildV2Transactions(routers, wallets, amountsWei, minOuts, path, isBuy, needBNB) {
|
|
39
|
-
const deadline = getDeadline();
|
|
40
|
-
return Promise.all(routers.map(async (router, i) => {
|
|
41
|
-
if (isBuy && needBNB) {
|
|
42
|
-
// ✅ 买入:BNB → Token,使用 swapExactETHForTokensSupportingFeeOnTransferTokens
|
|
43
|
-
return router.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(minOuts[i], // amountOutMin
|
|
44
|
-
path, // path
|
|
45
|
-
wallets[i].address, // to
|
|
46
|
-
deadline, // deadline
|
|
47
|
-
{ value: amountsWei[i] });
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
// ✅ 卖出:Token → BNB,使用 swapExactTokensForETHSupportingFeeOnTransferTokens
|
|
51
|
-
return router.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(amountsWei[i], // amountIn
|
|
52
|
-
minOuts[i], // amountOutMin
|
|
53
|
-
path, // path
|
|
54
|
-
wallets[i].address, // to
|
|
55
|
-
deadline);
|
|
56
|
-
}
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* ✅ 构建 V3 单跳交易(使用官方 SwapRouter02 + multicall)
|
|
61
|
-
*/
|
|
62
|
-
export async function buildV3SingleTransactions(routers, wallets, tokenIn, tokenOut, fee, amountsWei, minOuts, isBuy, needBNB) {
|
|
63
|
-
const deadline = getDeadline();
|
|
64
|
-
const v3RouterIface = new Interface(V3_ROUTER_ABI);
|
|
65
|
-
return Promise.all(routers.map(async (router, i) => {
|
|
66
|
-
const isTokenOutWBNB = tokenOut.toLowerCase() === WBNB_ADDRESS.toLowerCase();
|
|
67
|
-
// ✅ 构建 exactInputSingle calldata
|
|
68
|
-
const exactInputSingleData = v3RouterIface.encodeFunctionData('exactInputSingle', [
|
|
69
|
-
{
|
|
70
|
-
tokenIn: tokenIn,
|
|
71
|
-
tokenOut: tokenOut,
|
|
72
|
-
fee: fee,
|
|
73
|
-
recipient: isTokenOutWBNB ? PANCAKE_V3_ROUTER_ADDRESS : wallets[i].address, // 如果输出是 WBNB,先发给 Router
|
|
74
|
-
amountIn: amountsWei[i],
|
|
75
|
-
amountOutMinimum: minOuts[i],
|
|
76
|
-
sqrtPriceLimitX96: 0n,
|
|
77
|
-
},
|
|
78
|
-
]);
|
|
79
|
-
if (isBuy && needBNB) {
|
|
80
|
-
// ✅ 买入:BNB → Token,只需要 exactInputSingle
|
|
81
|
-
// 通过 multicall 包装,传入 deadline 和 ETH value
|
|
82
|
-
return router.multicall.populateTransaction(deadline, [exactInputSingleData], { value: amountsWei[i] });
|
|
83
|
-
}
|
|
84
|
-
else if (!isBuy && isTokenOutWBNB) {
|
|
85
|
-
// ✅ 卖出:Token → WBNB → BNB,需要 exactInputSingle + unwrapWETH9
|
|
86
|
-
const unwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [
|
|
87
|
-
minOuts[i], // amountMinimum
|
|
88
|
-
wallets[i].address, // recipient
|
|
89
|
-
]);
|
|
90
|
-
return router.multicall.populateTransaction(deadline, [exactInputSingleData, unwrapData]);
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
// ✅ Token → Token,只需要 exactInputSingle
|
|
94
|
-
return router.multicall.populateTransaction(deadline, [exactInputSingleData]);
|
|
95
|
-
}
|
|
96
|
-
}));
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* ✅ 构建 V3 多跳交易(使用官方 SwapRouter02 的 exactInput)
|
|
100
|
-
*
|
|
101
|
-
* @param routers - V3 Router 合约数组
|
|
102
|
-
* @param wallets - 钱包数组
|
|
103
|
-
* @param tokens - 代币路径 [tokenIn, tokenMid1, ..., tokenOut]
|
|
104
|
-
* @param fees - 费率路径 [fee0, fee1, ...]
|
|
105
|
-
* @param amountsWei - 每个钱包的输入金额
|
|
106
|
-
* @param minOuts - 最小输出金额
|
|
107
|
-
* @param isBuy - 是否为买入操作
|
|
108
|
-
* @param needBNB - 是否需要发送 BNB
|
|
109
|
-
*/
|
|
110
|
-
export async function buildV3MultiHopTransactions(routers, wallets, tokens, fees, amountsWei, minOuts, isBuy, needBNB) {
|
|
111
|
-
if (!tokens || tokens.length < 2) {
|
|
112
|
-
throw new Error('V3 多跳需要至少 2 个代币(v3Tokens)');
|
|
113
|
-
}
|
|
114
|
-
if (!fees || fees.length !== tokens.length - 1) {
|
|
115
|
-
throw new Error(`V3 多跳费率数量 (${fees?.length || 0}) 必须等于代币数量 - 1 (${tokens.length - 1})(v3Fees)`);
|
|
116
|
-
}
|
|
117
|
-
const deadline = getDeadline();
|
|
118
|
-
const v3RouterIface = new Interface(V3_ROUTER_ABI);
|
|
119
|
-
// 编码正向 path(用于买入:BNB → Token)
|
|
120
|
-
const forwardPath = encodeV3Path(tokens, fees);
|
|
121
|
-
// 编码反向 path(用于卖出:Token → BNB)
|
|
122
|
-
const reversedTokens = [...tokens].reverse();
|
|
123
|
-
const reversedFees = [...fees].reverse();
|
|
124
|
-
const reversePath = encodeV3Path(reversedTokens, reversedFees);
|
|
125
|
-
const tokenOut = tokens[tokens.length - 1];
|
|
126
|
-
const isTokenOutWBNB = tokenOut.toLowerCase() === WBNB_ADDRESS.toLowerCase();
|
|
127
|
-
return Promise.all(routers.map(async (router, i) => {
|
|
128
|
-
if (isBuy && needBNB) {
|
|
129
|
-
// ✅ 买入:BNB → ... → Token
|
|
130
|
-
const swapData = v3RouterIface.encodeFunctionData('exactInput', [
|
|
131
|
-
{
|
|
132
|
-
path: forwardPath,
|
|
133
|
-
recipient: wallets[i].address,
|
|
134
|
-
amountIn: amountsWei[i],
|
|
135
|
-
amountOutMinimum: minOuts[i],
|
|
136
|
-
},
|
|
137
|
-
]);
|
|
138
|
-
return router.multicall.populateTransaction(deadline, [swapData], { value: amountsWei[i] });
|
|
139
|
-
}
|
|
140
|
-
else if (!isBuy) {
|
|
141
|
-
// ✅ 卖出:Token → ... → BNB
|
|
142
|
-
const swapData = v3RouterIface.encodeFunctionData('exactInput', [
|
|
143
|
-
{
|
|
144
|
-
path: reversePath,
|
|
145
|
-
recipient: isTokenOutWBNB ? PANCAKE_V3_ROUTER_ADDRESS : wallets[i].address,
|
|
146
|
-
amountIn: amountsWei[i],
|
|
147
|
-
amountOutMinimum: minOuts[i],
|
|
148
|
-
},
|
|
149
|
-
]);
|
|
150
|
-
if (isTokenOutWBNB) {
|
|
151
|
-
// 需要 unwrapWETH9
|
|
152
|
-
const unwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [minOuts[i], wallets[i].address]);
|
|
153
|
-
return router.multicall.populateTransaction(deadline, [swapData, unwrapData]);
|
|
154
|
-
}
|
|
155
|
-
return router.multicall.populateTransaction(deadline, [swapData]);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// Token → Token(不需要 BNB)
|
|
159
|
-
const swapData = v3RouterIface.encodeFunctionData('exactInput', [
|
|
160
|
-
{
|
|
161
|
-
path: forwardPath,
|
|
162
|
-
recipient: wallets[i].address,
|
|
163
|
-
amountIn: amountsWei[i],
|
|
164
|
-
amountOutMinimum: minOuts[i],
|
|
165
|
-
},
|
|
166
|
-
]);
|
|
167
|
-
return router.multicall.populateTransaction(deadline, [swapData]);
|
|
168
|
-
}
|
|
169
|
-
}));
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* ✅ 使用 Multicall3 批量获取 V2 报价
|
|
173
|
-
*/
|
|
174
|
-
export async function batchGetV2Quotes(provider, amountsWei, v2Path) {
|
|
175
|
-
if (amountsWei.length === 0)
|
|
176
|
-
return [];
|
|
177
|
-
if (amountsWei.length === 1) {
|
|
178
|
-
try {
|
|
179
|
-
const v2Router = new Contract(PANCAKE_V2_ROUTER_ADDRESS, V2_ROUTER_ABI, provider);
|
|
180
|
-
const amounts = await v2Router.getAmountsOut(amountsWei[0], v2Path);
|
|
181
|
-
return [amounts[amounts.length - 1]];
|
|
182
|
-
}
|
|
183
|
-
catch {
|
|
184
|
-
return [0n];
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
try {
|
|
188
|
-
const v2RouterIface = new Interface(V2_ROUTER_ABI);
|
|
189
|
-
const multicall = new Contract(MULTICALL3_ADDRESS, MULTICALL3_ABI, provider);
|
|
190
|
-
const calls = amountsWei.map((amount) => ({
|
|
191
|
-
target: PANCAKE_V2_ROUTER_ADDRESS,
|
|
192
|
-
allowFailure: true,
|
|
193
|
-
callData: v2RouterIface.encodeFunctionData('getAmountsOut', [amount, v2Path]),
|
|
194
|
-
}));
|
|
195
|
-
const results = await multicall.aggregate3.staticCall(calls);
|
|
196
|
-
return results.map((r) => {
|
|
197
|
-
if (r.success && r.returnData && r.returnData !== '0x') {
|
|
198
|
-
try {
|
|
199
|
-
const decoded = v2RouterIface.decodeFunctionResult('getAmountsOut', r.returnData);
|
|
200
|
-
const amounts = decoded[0];
|
|
201
|
-
return amounts[amounts.length - 1];
|
|
202
|
-
}
|
|
203
|
-
catch {
|
|
204
|
-
return 0n;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return 0n;
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
return await Promise.all(amountsWei.map(async (amount) => {
|
|
212
|
-
try {
|
|
213
|
-
const v2Router = new Contract(PANCAKE_V2_ROUTER_ADDRESS, V2_ROUTER_ABI, provider);
|
|
214
|
-
const amounts = await v2Router.getAmountsOut(amount, v2Path);
|
|
215
|
-
return amounts[amounts.length - 1];
|
|
216
|
-
}
|
|
217
|
-
catch {
|
|
218
|
-
return 0n;
|
|
219
|
-
}
|
|
220
|
-
}));
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* 根据 routeType 获取授权目标地址
|
|
225
|
-
*/
|
|
226
|
-
export function getApprovalTarget(routeType) {
|
|
227
|
-
if (routeType === 'v2') {
|
|
228
|
-
return PANCAKE_V2_ROUTER_ADDRESS;
|
|
229
|
-
}
|
|
230
|
-
// V3 路由授权给 V3 Router
|
|
231
|
-
return PANCAKE_V3_ROUTER_ADDRESS;
|
|
8
|
+
return needSendBNBFromRoute(routeType, params);
|
|
232
9
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { ethers, Wallet } from 'ethers';
|
|
5
5
|
import { getGasLimit } from '../../../core/gas/bundle-gas.js';
|
|
6
6
|
import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
7
|
-
import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA, CHAINS } from '../../../core/constants/index.js';
|
|
7
|
+
import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA, CHAINS, applySlippageBps, reverseSlippageBps } from '../../../core/constants/index.js';
|
|
8
8
|
import { TM2_ABI } from '../../../abis/common.js';
|
|
9
9
|
import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount, } from '../../config-helpers.js';
|
|
10
10
|
import { trySell } from '../../../domains/four/contracts/tm.js';
|
|
@@ -31,7 +31,7 @@ export async function fourPrivateSellMerkle(params) {
|
|
|
31
31
|
const [gasPrice, sellNonce, sellUnsigned] = await Promise.all([
|
|
32
32
|
getOptimizedGasPrice(provider, getGasPriceConfig(config)),
|
|
33
33
|
wallet.getNonce(),
|
|
34
|
-
tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei,
|
|
34
|
+
tm2.sellToken.populateTransaction(0n, tokenAddress, amountWei, minOut),
|
|
35
35
|
]);
|
|
36
36
|
// ✅ 已移除授权检查(前端负责确保授权)
|
|
37
37
|
// ✅ 利润计算(同步)
|
|
@@ -121,7 +121,7 @@ export async function fourBatchPrivateSellMerkle(params) {
|
|
|
121
121
|
minFundsEach !== undefined
|
|
122
122
|
? Promise.resolve((() => {
|
|
123
123
|
const minOutWei = typeof minFundsEach === 'string' ? ethers.parseEther(minFundsEach) : minFundsEach;
|
|
124
|
-
return new Array(wallets.length).fill((minOutWei
|
|
124
|
+
return new Array(wallets.length).fill(reverseSlippageBps(minOutWei));
|
|
125
125
|
})())
|
|
126
126
|
: Promise.all(amountsWei.map(async (amount) => {
|
|
127
127
|
try {
|
|
@@ -133,8 +133,8 @@ export async function fourBatchPrivateSellMerkle(params) {
|
|
|
133
133
|
}
|
|
134
134
|
})),
|
|
135
135
|
]);
|
|
136
|
-
//
|
|
137
|
-
const minOuts =
|
|
136
|
+
// 报价 × (1 - 100bps)
|
|
137
|
+
const minOuts = quotedOutputs.map((q) => applySlippageBps(q));
|
|
138
138
|
// ✅ 计算总利润和找出收益最高的钱包(同步计算)
|
|
139
139
|
const extractProfit = shouldExtractProfit();
|
|
140
140
|
let totalProfit = 0n;
|
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import type { DisperseHopPath } from './types/index.js';
|
|
3
|
-
export declare const NATIVE_TRANSFER_GAS_LIMIT = 21055n;
|
|
1
|
+
export { generateDisperseHopPaths, buildNativeHopChain, NATIVE_TRANSFER_GAS_LIMIT, } from '../../utils/hop-chains.js';
|
|
4
2
|
export type { DisperseHopPath } from './types/index.js';
|
|
5
|
-
export declare function generateDisperseHopPaths(targetAddresses: string[], hopCount: number, provider: JsonRpcProvider): DisperseHopPath[];
|
|
6
|
-
export declare function buildNativeHopChain(payer: Wallet, path: DisperseHopPath, finalAmount: bigint, gasPrice: bigint, chainId: number, txType: 0 | 2, payerNonce: number): Promise<string[]>;
|
|
@@ -1,63 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { generateWallets } from '../../utils/wallet.js';
|
|
3
|
-
export const NATIVE_TRANSFER_GAS_LIMIT = 21055n;
|
|
4
|
-
export function generateDisperseHopPaths(targetAddresses, hopCount, provider) {
|
|
5
|
-
if (hopCount <= 0) {
|
|
6
|
-
return targetAddresses.map((addr) => ({
|
|
7
|
-
targetAddress: addr,
|
|
8
|
-
hopWallets: [],
|
|
9
|
-
hopWalletsInfo: [],
|
|
10
|
-
}));
|
|
11
|
-
}
|
|
12
|
-
return targetAddresses.map((targetAddress) => {
|
|
13
|
-
const hopWalletsInfo = generateWallets(hopCount);
|
|
14
|
-
const hopWallets = hopWalletsInfo.map((w) => new Wallet(w.privateKey, provider));
|
|
15
|
-
return { targetAddress, hopWallets, hopWalletsInfo };
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
export async function buildNativeHopChain(payer, path, finalAmount, gasPrice, chainId, txType, payerNonce) {
|
|
19
|
-
const signedTxs = [];
|
|
20
|
-
const hopCount = path.hopWallets.length;
|
|
21
|
-
if (hopCount === 0) {
|
|
22
|
-
signedTxs.push(await payer.signTransaction({
|
|
23
|
-
to: path.targetAddress,
|
|
24
|
-
value: finalAmount,
|
|
25
|
-
nonce: payerNonce,
|
|
26
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
27
|
-
gasPrice,
|
|
28
|
-
chainId,
|
|
29
|
-
type: txType,
|
|
30
|
-
}));
|
|
31
|
-
return signedTxs;
|
|
32
|
-
}
|
|
33
|
-
const hopGasCost = NATIVE_TRANSFER_GAS_LIMIT * gasPrice;
|
|
34
|
-
const amountsPerHop = [];
|
|
35
|
-
for (let i = 0; i < hopCount; i++) {
|
|
36
|
-
const remainingHops = hopCount - i;
|
|
37
|
-
amountsPerHop.push(finalAmount + hopGasCost * BigInt(remainingHops));
|
|
38
|
-
}
|
|
39
|
-
signedTxs.push(await payer.signTransaction({
|
|
40
|
-
to: path.hopWallets[0].address,
|
|
41
|
-
value: amountsPerHop[0],
|
|
42
|
-
nonce: payerNonce,
|
|
43
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
44
|
-
gasPrice,
|
|
45
|
-
chainId,
|
|
46
|
-
type: txType,
|
|
47
|
-
}));
|
|
48
|
-
for (let i = 0; i < hopCount; i++) {
|
|
49
|
-
const fromWallet = path.hopWallets[i];
|
|
50
|
-
const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
|
|
51
|
-
const amount = i === hopCount - 1 ? finalAmount : amountsPerHop[i + 1];
|
|
52
|
-
signedTxs.push(await fromWallet.signTransaction({
|
|
53
|
-
to: toAddress,
|
|
54
|
-
value: amount,
|
|
55
|
-
nonce: 0,
|
|
56
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
57
|
-
gasPrice,
|
|
58
|
-
chainId,
|
|
59
|
-
type: txType,
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
|
-
return signedTxs;
|
|
63
|
-
}
|
|
1
|
+
export { generateDisperseHopPaths, buildNativeHopChain, NATIVE_TRANSFER_GAS_LIMIT, } from '../../utils/hop-chains.js';
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { FourTokenTaxInfo } from '../../../core/clients/four.js';
|
|
2
|
+
import type { FourRaisedToken } from '../../../domains/four/raised-token.js';
|
|
3
|
+
import type { FourBundleMerkleConfig, FourSignConfig, MerkleSignedResult } from './config.js';
|
|
4
|
+
/** ✅ 创建代币 + 购买参数(Merkle 版本 - 完整) */
|
|
5
|
+
export type FourCreateWithBundleBuyMerkleParams = {
|
|
6
|
+
privateKeys: string[];
|
|
7
|
+
buyAmounts: string[];
|
|
8
|
+
b0Amount?: string;
|
|
9
|
+
tokenInfo: {
|
|
10
|
+
name: string;
|
|
11
|
+
symbol: string;
|
|
12
|
+
description: string;
|
|
13
|
+
imageUrl?: string;
|
|
14
|
+
imageFile?: Blob;
|
|
15
|
+
label?: 'Meme' | 'AI' | 'Defi' | 'Games' | 'Infra' | 'De-Sci' | 'Social' | 'Depin' | 'Charity' | 'Others';
|
|
16
|
+
preSale?: string;
|
|
17
|
+
webUrl?: string;
|
|
18
|
+
twitterUrl?: string;
|
|
19
|
+
telegramUrl?: string;
|
|
20
|
+
/** ✅ AntiSniperFeeMode(开盘高税模式) */
|
|
21
|
+
feePlan?: boolean;
|
|
22
|
+
/** ✅ 税币配置(Tax Token, creatorType=5) */
|
|
23
|
+
tokenTaxInfo?: FourTokenTaxInfo;
|
|
24
|
+
/** 官网计价币 symbol,如 BNB / USDT / USD1 */
|
|
25
|
+
quoteSymbol?: string;
|
|
26
|
+
raisedToken?: FourRaisedToken;
|
|
27
|
+
};
|
|
28
|
+
config: FourBundleMerkleConfig;
|
|
29
|
+
};
|
|
30
|
+
/** ✅ 创建代币 + 购买参数(仅签名版本 - 精简) */
|
|
31
|
+
export type FourCreateWithBundleBuySignParams = {
|
|
32
|
+
privateKeys: string[];
|
|
33
|
+
buyAmounts: string[];
|
|
34
|
+
b0Amount?: string;
|
|
35
|
+
tokenInfo: {
|
|
36
|
+
name: string;
|
|
37
|
+
symbol: string;
|
|
38
|
+
description: string;
|
|
39
|
+
imageUrl?: string;
|
|
40
|
+
imageFile?: Blob;
|
|
41
|
+
label?: 'Meme' | 'AI' | 'Defi' | 'Games' | 'Infra' | 'De-Sci' | 'Social' | 'Depin' | 'Charity' | 'Others';
|
|
42
|
+
preSale?: string;
|
|
43
|
+
webUrl?: string;
|
|
44
|
+
twitterUrl?: string;
|
|
45
|
+
telegramUrl?: string;
|
|
46
|
+
/** ✅ AntiSniperFeeMode(开盘高税模式) */
|
|
47
|
+
feePlan?: boolean;
|
|
48
|
+
/** ✅ 税币配置(Tax Token, creatorType=5) */
|
|
49
|
+
tokenTaxInfo?: FourTokenTaxInfo;
|
|
50
|
+
quoteSymbol?: string;
|
|
51
|
+
raisedToken?: FourRaisedToken;
|
|
52
|
+
};
|
|
53
|
+
config: FourSignConfig;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* ✅ 创建代币 + 购买结果(简化版)
|
|
57
|
+
* 包含 tokenAddress 用于返回创建的代币地址
|
|
58
|
+
*/
|
|
59
|
+
export type FourCreateWithBundleBuyMerkleResult = MerkleSignedResult;
|
|
60
|
+
/** ✅ 批量购买参数(Merkle 版本 - 完整) */
|
|
61
|
+
export type FourBatchBuyMerkleParams = {
|
|
62
|
+
privateKeys: string[];
|
|
63
|
+
buyAmounts: string[];
|
|
64
|
+
tokenAddress: string;
|
|
65
|
+
config: FourBundleMerkleConfig;
|
|
66
|
+
};
|
|
67
|
+
/** ✅ 批量购买参数(仅签名版本 - 精简) */
|
|
68
|
+
export type FourBatchBuySignParams = {
|
|
69
|
+
privateKeys: string[];
|
|
70
|
+
buyAmounts: string[];
|
|
71
|
+
tokenAddress: string;
|
|
72
|
+
config: FourSignConfig;
|
|
73
|
+
};
|
|
74
|
+
/** ✅ 批量购买结果(简化版) */
|
|
75
|
+
export type FourBatchBuyMerkleResult = MerkleSignedResult;
|
|
76
|
+
/** ✅ 批量卖出参数(Merkle 版本 - 完整) */
|
|
77
|
+
export type FourBatchSellMerkleParams = {
|
|
78
|
+
privateKeys: string[];
|
|
79
|
+
sellAmounts: string[];
|
|
80
|
+
tokenAddress: string;
|
|
81
|
+
minOutputAmounts?: (string | bigint)[];
|
|
82
|
+
config: FourBundleMerkleConfig;
|
|
83
|
+
};
|
|
84
|
+
/** ✅ 批量卖出参数(仅签名版本 - 精简) */
|
|
85
|
+
export type FourBatchSellSignParams = {
|
|
86
|
+
privateKeys: string[];
|
|
87
|
+
sellAmounts: string[];
|
|
88
|
+
tokenAddress: string;
|
|
89
|
+
minOutputAmounts?: (string | bigint)[];
|
|
90
|
+
config: FourSignConfig;
|
|
91
|
+
};
|
|
92
|
+
/** ✅ 批量卖出结果(简化版) */
|
|
93
|
+
export type FourBatchSellMerkleResult = MerkleSignedResult;
|
|
94
|
+
/** ✅ 私有交易基础配置(Merkle 版本 - 完整) */
|
|
95
|
+
export type FourPrivateMerkleBase = {
|
|
96
|
+
config: FourBundleMerkleConfig;
|
|
97
|
+
};
|
|
98
|
+
/** ✅ 私有交易基础配置(仅签名版本 - 精简) */
|
|
99
|
+
export type FourPrivateSignBase = {
|
|
100
|
+
config: FourSignConfig;
|
|
101
|
+
};
|
|
102
|
+
/** ✅ 私有购买参数(Merkle 版本 - 完整) */
|
|
103
|
+
export type FourPrivateBuyMerkleParams = FourPrivateMerkleBase & {
|
|
104
|
+
privateKey: string;
|
|
105
|
+
tokenAddress: string;
|
|
106
|
+
funds: string;
|
|
107
|
+
to?: string;
|
|
108
|
+
};
|
|
109
|
+
/** ✅ 私有购买参数(仅签名版本 - 精简) */
|
|
110
|
+
export type FourPrivateBuySignParams = FourPrivateSignBase & {
|
|
111
|
+
privateKey: string;
|
|
112
|
+
tokenAddress: string;
|
|
113
|
+
funds: string;
|
|
114
|
+
to?: string;
|
|
115
|
+
/** ERC20 计价跟买;不传则按 BNB `msg.value` */
|
|
116
|
+
quoteTokenAddress?: string;
|
|
117
|
+
quoteDecimals?: number;
|
|
118
|
+
};
|
|
119
|
+
/** ✅ 私有卖出参数(Merkle 版本 - 完整) */
|
|
120
|
+
export type FourPrivateSellMerkleParams = FourPrivateMerkleBase & {
|
|
121
|
+
privateKey: string;
|
|
122
|
+
tokenAddress: string;
|
|
123
|
+
amount: string;
|
|
124
|
+
minFunds?: bigint;
|
|
125
|
+
};
|
|
126
|
+
/** ✅ 私有卖出参数(仅签名版本 - 精简) */
|
|
127
|
+
export type FourPrivateSellSignParams = FourPrivateSignBase & {
|
|
128
|
+
privateKey: string;
|
|
129
|
+
tokenAddress: string;
|
|
130
|
+
amount: string;
|
|
131
|
+
minFunds?: bigint;
|
|
132
|
+
};
|
|
133
|
+
/** ✅ 私有交易结果(简化版) */
|
|
134
|
+
export type FourPrivateTransactionResult = MerkleSignedResult;
|
|
135
|
+
/** ✅ 批量私有购买参数(Merkle 版本 - 完整) */
|
|
136
|
+
export type FourBatchPrivateBuyMerkleParams = FourPrivateMerkleBase & {
|
|
137
|
+
privateKeys: string[];
|
|
138
|
+
fundsList: string[];
|
|
139
|
+
tokenAddress: string;
|
|
140
|
+
quoteTokenAddress?: string;
|
|
141
|
+
quoteDecimals?: number;
|
|
142
|
+
};
|
|
143
|
+
/** ✅ 批量私有购买参数(仅签名版本 - 精简) */
|
|
144
|
+
export type FourBatchPrivateBuySignParams = FourPrivateSignBase & {
|
|
145
|
+
privateKeys: string[];
|
|
146
|
+
fundsList: string[];
|
|
147
|
+
tokenAddress: string;
|
|
148
|
+
quoteTokenAddress?: string;
|
|
149
|
+
quoteDecimals?: number;
|
|
150
|
+
};
|
|
151
|
+
/** ✅ 批量私有卖出参数(Merkle 版本 - 完整) */
|
|
152
|
+
export type FourBatchPrivateSellMerkleParams = FourPrivateMerkleBase & {
|
|
153
|
+
privateKeys: string[];
|
|
154
|
+
amounts: string[];
|
|
155
|
+
tokenAddress: string;
|
|
156
|
+
minFundsEach?: bigint;
|
|
157
|
+
};
|
|
158
|
+
/** ✅ 批量私有卖出参数(仅签名版本 - 精简) */
|
|
159
|
+
export type FourBatchPrivateSellSignParams = FourPrivateSignBase & {
|
|
160
|
+
privateKeys: string[];
|
|
161
|
+
amounts: string[];
|
|
162
|
+
tokenAddress: string;
|
|
163
|
+
minFundsEach?: bigint;
|
|
164
|
+
};
|
|
165
|
+
/** ✅ 批量私有交易结果(简化版) */
|
|
166
|
+
export type FourBatchPrivateMerkleResult = MerkleSignedResult;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonBundleConfig } from '../../../utils/bundle-helpers.js';
|
|
2
2
|
import type { GeneratedWallet } from '../../../utils/wallet.js';
|
|
3
|
-
import type { FourSignConfig, UserType } from './
|
|
3
|
+
import type { FourSignConfig, UserType } from './config.js';
|
|
4
4
|
export type FourBuyFirstSignConfig = FourSignConfig & {
|
|
5
5
|
reserveGasBNB?: number;
|
|
6
6
|
userType?: UserType;
|