four-flap-meme-sdk 1.3.93 → 1.3.94
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/clients/blockrazor.js +1 -0
- package/dist/contracts/tm-bundle-merkle/config.d.ts +0 -5
- package/dist/contracts/tm-bundle-merkle/config.js +0 -10
- package/dist/contracts/tm-bundle-merkle/core.js +24 -92
- package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +54 -103
- package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +1 -0
- package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +6 -36
- package/dist/contracts/tm-bundle-merkle/swap.d.ts +3 -0
- package/dist/contracts/tm-bundle-merkle/swap.js +6 -59
- package/dist/flap/portal-bundle-merkle/config.d.ts +0 -8
- package/dist/flap/portal-bundle-merkle/config.js +0 -17
- package/dist/flap/portal-bundle-merkle/core.js +68 -120
- package/dist/flap/portal-bundle-merkle/pancake-proxy.js +78 -136
- package/dist/flap/portal-bundle-merkle/swap-buy-first.d.ts +2 -0
- package/dist/flap/portal-bundle-merkle/swap-buy-first.js +30 -49
- package/dist/flap/portal-bundle-merkle/swap.d.ts +2 -0
- package/dist/flap/portal-bundle-merkle/swap.js +47 -75
- package/dist/flap/portal-bundle-merkle/types.d.ts +0 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/pancake/bundle-buy-first.d.ts +1 -1
- package/dist/pancake/bundle-buy-first.js +17 -49
- package/dist/pancake/bundle-swap.d.ts +4 -1
- package/dist/pancake/bundle-swap.js +33 -98
- package/dist/sol/constants.d.ts +126 -0
- package/dist/sol/constants.js +145 -0
- package/dist/sol/dex/index.d.ts +8 -0
- package/dist/sol/dex/index.js +12 -0
- package/dist/sol/dex/meteora/client.d.ts +76 -0
- package/dist/sol/dex/meteora/client.js +219 -0
- package/dist/sol/dex/meteora/damm-v1-bundle.d.ts +61 -0
- package/dist/sol/dex/meteora/damm-v1-bundle.js +112 -0
- package/dist/sol/dex/meteora/damm-v1.d.ts +118 -0
- package/dist/sol/dex/meteora/damm-v1.js +315 -0
- package/dist/sol/dex/meteora/damm-v2-bundle.d.ts +82 -0
- package/dist/sol/dex/meteora/damm-v2-bundle.js +242 -0
- package/dist/sol/dex/meteora/damm-v2.d.ts +172 -0
- package/dist/sol/dex/meteora/damm-v2.js +632 -0
- package/dist/sol/dex/meteora/dbc-bundle.d.ts +123 -0
- package/dist/sol/dex/meteora/dbc-bundle.js +304 -0
- package/dist/sol/dex/meteora/dbc.d.ts +192 -0
- package/dist/sol/dex/meteora/dbc.js +619 -0
- package/dist/sol/dex/meteora/dlmm-bundle.d.ts +39 -0
- package/dist/sol/dex/meteora/dlmm-bundle.js +189 -0
- package/dist/sol/dex/meteora/dlmm.d.ts +157 -0
- package/dist/sol/dex/meteora/dlmm.js +671 -0
- package/dist/sol/dex/meteora/index.d.ts +25 -0
- package/dist/sol/dex/meteora/index.js +65 -0
- package/dist/sol/dex/meteora/types.d.ts +787 -0
- package/dist/sol/dex/meteora/types.js +110 -0
- package/dist/sol/dex/orca/index.d.ts +10 -0
- package/dist/sol/dex/orca/index.js +16 -0
- package/dist/sol/dex/orca/orca-bundle.d.ts +41 -0
- package/dist/sol/dex/orca/orca-bundle.js +173 -0
- package/dist/sol/dex/orca/orca.d.ts +65 -0
- package/dist/sol/dex/orca/orca.js +474 -0
- package/dist/sol/dex/orca/types.d.ts +263 -0
- package/dist/sol/dex/orca/types.js +38 -0
- package/dist/sol/dex/orca/wavebreak-bundle.d.ts +34 -0
- package/dist/sol/dex/orca/wavebreak-bundle.js +198 -0
- package/dist/sol/dex/orca/wavebreak-types.d.ts +227 -0
- package/dist/sol/dex/orca/wavebreak-types.js +23 -0
- package/dist/sol/dex/orca/wavebreak.d.ts +78 -0
- package/dist/sol/dex/orca/wavebreak.js +497 -0
- package/dist/sol/dex/pump/index.d.ts +9 -0
- package/dist/sol/dex/pump/index.js +14 -0
- package/dist/sol/dex/pump/pump-bundle.d.ts +92 -0
- package/dist/sol/dex/pump/pump-bundle.js +383 -0
- package/dist/sol/dex/pump/pump-swap-bundle.d.ts +103 -0
- package/dist/sol/dex/pump/pump-swap-bundle.js +380 -0
- package/dist/sol/dex/pump/pump-swap.d.ts +46 -0
- package/dist/sol/dex/pump/pump-swap.js +199 -0
- package/dist/sol/dex/pump/pump.d.ts +35 -0
- package/dist/sol/dex/pump/pump.js +352 -0
- package/dist/sol/dex/pump/types.d.ts +215 -0
- package/dist/sol/dex/pump/types.js +5 -0
- package/dist/sol/dex/raydium/index.d.ts +8 -0
- package/dist/sol/dex/raydium/index.js +12 -0
- package/dist/sol/dex/raydium/launchlab.d.ts +68 -0
- package/dist/sol/dex/raydium/launchlab.js +210 -0
- package/dist/sol/dex/raydium/raydium-bundle.d.ts +64 -0
- package/dist/sol/dex/raydium/raydium-bundle.js +324 -0
- package/dist/sol/dex/raydium/raydium.d.ts +40 -0
- package/dist/sol/dex/raydium/raydium.js +366 -0
- package/dist/sol/dex/raydium/types.d.ts +240 -0
- package/dist/sol/dex/raydium/types.js +5 -0
- package/dist/sol/index.d.ts +10 -0
- package/dist/sol/index.js +16 -0
- package/dist/sol/jito/bundle.d.ts +90 -0
- package/dist/sol/jito/bundle.js +263 -0
- package/dist/sol/jito/index.d.ts +7 -0
- package/dist/sol/jito/index.js +7 -0
- package/dist/sol/jito/tip.d.ts +51 -0
- package/dist/sol/jito/tip.js +83 -0
- package/dist/sol/jito/types.d.ts +100 -0
- package/dist/sol/jito/types.js +5 -0
- package/dist/sol/token/create-complete.d.ts +115 -0
- package/dist/sol/token/create-complete.js +235 -0
- package/dist/sol/token/create-token.d.ts +57 -0
- package/dist/sol/token/create-token.js +230 -0
- package/dist/sol/token/index.d.ts +9 -0
- package/dist/sol/token/index.js +14 -0
- package/dist/sol/token/metadata-upload.d.ts +86 -0
- package/dist/sol/token/metadata-upload.js +173 -0
- package/dist/sol/token/metadata.d.ts +92 -0
- package/dist/sol/token/metadata.js +274 -0
- package/dist/sol/token/types.d.ts +153 -0
- package/dist/sol/token/types.js +5 -0
- package/dist/sol/types.d.ts +176 -0
- package/dist/sol/types.js +7 -0
- package/dist/sol/utils/balance.d.ts +160 -0
- package/dist/sol/utils/balance.js +638 -0
- package/dist/sol/utils/connection.d.ts +78 -0
- package/dist/sol/utils/connection.js +168 -0
- package/dist/sol/utils/index.d.ts +9 -0
- package/dist/sol/utils/index.js +9 -0
- package/dist/sol/utils/lp-inspect.d.ts +129 -0
- package/dist/sol/utils/lp-inspect.js +900 -0
- package/dist/sol/utils/transfer.d.ts +125 -0
- package/dist/sol/utils/transfer.js +220 -0
- package/dist/sol/utils/wallet.d.ts +107 -0
- package/dist/sol/utils/wallet.js +210 -0
- package/dist/utils/erc20.d.ts +2 -108
- package/dist/utils/erc20.js +17 -65
- package/package.json +39 -4
- package/dist/flap/portal-bundle-merkle/encryption.d.ts +0 -16
- package/dist/flap/portal-bundle-merkle/encryption.js +0 -146
|
@@ -29,6 +29,7 @@ export interface FourBundleSwapSignParams {
|
|
|
29
29
|
sellPercentage?: number;
|
|
30
30
|
buyerPrivateKey: string;
|
|
31
31
|
tokenAddress: string;
|
|
32
|
+
slippageTolerance?: number;
|
|
32
33
|
config: FourSwapSignConfig;
|
|
33
34
|
}
|
|
34
35
|
export interface FourBundleSwapParams {
|
|
@@ -37,6 +38,7 @@ export interface FourBundleSwapParams {
|
|
|
37
38
|
sellPercentage?: number;
|
|
38
39
|
buyerPrivateKey: string;
|
|
39
40
|
tokenAddress: string;
|
|
41
|
+
slippageTolerance?: number;
|
|
40
42
|
config: FourSwapConfig;
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
@@ -67,6 +69,7 @@ export interface FourBatchSwapSignParams {
|
|
|
67
69
|
buyerPrivateKeys: string[];
|
|
68
70
|
buyerRatios?: number[];
|
|
69
71
|
tokenAddress: string;
|
|
72
|
+
slippageTolerance?: number;
|
|
70
73
|
config: FourSwapSignConfig;
|
|
71
74
|
}
|
|
72
75
|
/**
|
|
@@ -8,14 +8,11 @@ import { calculateSellAmount } from '../../utils/swap-helpers.js';
|
|
|
8
8
|
import { NonceManager, getOptimizedGasPrice, getGasLimit, getGasPriceConfig, getTxType } from '../../utils/bundle-helpers.js';
|
|
9
9
|
import { ADDRESSES, PROFIT_CONFIG } from '../../utils/constants.js';
|
|
10
10
|
import { TM_ABI, HELPER3_ABI, TM_ADDRESS } from './swap-internal.js';
|
|
11
|
-
import { getBribeAmount } from './config.js';
|
|
12
|
-
// ✅ BlockRazor Builder EOA 地址(用于贿赂)
|
|
13
|
-
const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
|
|
14
11
|
/**
|
|
15
12
|
* Four内盘捆绑换手
|
|
16
13
|
*/
|
|
17
14
|
export async function fourBundleSwapMerkle(params) {
|
|
18
|
-
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, config } = params;
|
|
15
|
+
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, slippageTolerance = 0.5, config } = params;
|
|
19
16
|
const chainIdNum = config.chainId ?? 56;
|
|
20
17
|
const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
|
|
21
18
|
chainId: chainIdNum,
|
|
@@ -68,16 +65,11 @@ export async function fourBundleSwapMerkle(params) {
|
|
|
68
65
|
const profitAmount = extractProfit && sellerWillGetBNB > 0n
|
|
69
66
|
? (sellerWillGetBNB * BigInt(profitRateBps)) / 10000n
|
|
70
67
|
: 0n;
|
|
71
|
-
// ✅ 获取贿赂金额
|
|
72
|
-
const bribeAmount = getBribeAmount(config);
|
|
73
|
-
const needBribeTx = bribeAmount > 0n;
|
|
74
68
|
// ✅ 优化:第三批并行 - 构建交易、获取 nonces
|
|
75
69
|
const tmSeller = new Contract(TM_ADDRESS, TM_ABI, seller);
|
|
76
70
|
const tmBuyer = new Contract(TM_ADDRESS, TM_ABI, buyer);
|
|
77
71
|
// 计算需要的 nonce 数量
|
|
78
72
|
let sellerNonceCount = 1; // 卖出交易
|
|
79
|
-
if (needBribeTx)
|
|
80
|
-
sellerNonceCount++; // 贿赂交易
|
|
81
73
|
if (needApproval)
|
|
82
74
|
sellerNonceCount++; // 授权交易
|
|
83
75
|
if (extractProfit)
|
|
@@ -104,28 +96,13 @@ export async function fourBundleSwapMerkle(params) {
|
|
|
104
96
|
const { sellerNonces, buyerNonce } = noncesResult;
|
|
105
97
|
// 分配 nonces
|
|
106
98
|
let idx = 0;
|
|
107
|
-
let bribeNonce;
|
|
108
99
|
let approvalNonce;
|
|
109
|
-
if (needBribeTx)
|
|
110
|
-
bribeNonce = sellerNonces[idx++];
|
|
111
100
|
if (needApproval)
|
|
112
101
|
approvalNonce = sellerNonces[idx++];
|
|
113
102
|
const sellerNonce = sellerNonces[idx++];
|
|
114
103
|
const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
|
|
115
104
|
// ✅ 并行签名所有交易
|
|
116
105
|
const signPromises = [];
|
|
117
|
-
// ✅ 贿赂交易放在首位
|
|
118
|
-
if (needBribeTx && bribeNonce !== undefined) {
|
|
119
|
-
signPromises.push(seller.signTransaction({
|
|
120
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
121
|
-
value: bribeAmount,
|
|
122
|
-
nonce: bribeNonce,
|
|
123
|
-
gasPrice,
|
|
124
|
-
gasLimit: 21000n,
|
|
125
|
-
chainId: chainIdNum,
|
|
126
|
-
type: txType
|
|
127
|
-
}));
|
|
128
|
-
}
|
|
129
106
|
// 授权交易
|
|
130
107
|
if (needApproval && approvalNonce !== undefined) {
|
|
131
108
|
const approveInterface = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
@@ -160,7 +137,7 @@ export async function fourBundleSwapMerkle(params) {
|
|
|
160
137
|
type: txType,
|
|
161
138
|
value: buyerFunds
|
|
162
139
|
}));
|
|
163
|
-
//
|
|
140
|
+
// 利润交易
|
|
164
141
|
if (extractProfit && profitAmount > 0n && profitNonce !== undefined) {
|
|
165
142
|
signPromises.push(seller.signTransaction({
|
|
166
143
|
to: PROFIT_CONFIG.RECIPIENT,
|
|
@@ -175,20 +152,15 @@ export async function fourBundleSwapMerkle(params) {
|
|
|
175
152
|
const signedTxs = await Promise.all(signPromises);
|
|
176
153
|
// 解析签名结果
|
|
177
154
|
let signIdx = 0;
|
|
178
|
-
let bribeTx = null;
|
|
179
155
|
let approvalTx = null;
|
|
180
|
-
if (needBribeTx)
|
|
181
|
-
bribeTx = signedTxs[signIdx++];
|
|
182
156
|
if (needApproval)
|
|
183
157
|
approvalTx = signedTxs[signIdx++];
|
|
184
158
|
const signedSell = signedTxs[signIdx++];
|
|
185
159
|
const signedBuy = signedTxs[signIdx++];
|
|
186
160
|
const profitTx = extractProfit && profitAmount > 0n ? signedTxs[signIdx] : null;
|
|
187
161
|
nonceManager.clearTemp();
|
|
188
|
-
//
|
|
162
|
+
// 组装交易列表
|
|
189
163
|
const allTransactions = [];
|
|
190
|
-
if (bribeTx)
|
|
191
|
-
allTransactions.push(bribeTx);
|
|
192
164
|
if (approvalTx)
|
|
193
165
|
allTransactions.push(approvalTx);
|
|
194
166
|
allTransactions.push(signedSell, signedBuy);
|
|
@@ -213,7 +185,7 @@ export async function fourBundleSwapMerkle(params) {
|
|
|
213
185
|
* 限制:最多 24 个买方(服务器限制 25 笔交易,包含 1 笔利润交易)
|
|
214
186
|
*/
|
|
215
187
|
export async function fourBatchSwapMerkle(params) {
|
|
216
|
-
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, tokenAddress, config } = params;
|
|
188
|
+
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, tokenAddress, slippageTolerance = 0.5, config } = params;
|
|
217
189
|
// ✅ 校验买方数量(最多 24 个)
|
|
218
190
|
const MAX_BUYERS = 24;
|
|
219
191
|
if (buyerPrivateKeys.length === 0) {
|
|
@@ -286,9 +258,6 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
286
258
|
const profitAmount = totalBuyerFunds > 0n
|
|
287
259
|
? (totalBuyerFunds * BigInt(profitRateBps)) / 10000n
|
|
288
260
|
: 0n;
|
|
289
|
-
// ✅ 获取贿赂金额
|
|
290
|
-
const bribeAmount = getBribeAmount(config);
|
|
291
|
-
const needBribeTx = bribeAmount > 0n;
|
|
292
261
|
// ✅ 并行构建所有交易
|
|
293
262
|
const tmSeller = new Contract(TM_ADDRESS, TM_ABI, seller);
|
|
294
263
|
const [sellUnsigned, ...buyUnsignedList] = await Promise.all([
|
|
@@ -304,8 +273,6 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
304
273
|
// ✅ 计算 nonce
|
|
305
274
|
// seller 需要的 nonce 数量
|
|
306
275
|
let sellerNonceCount = 1; // 卖出交易
|
|
307
|
-
if (needBribeTx)
|
|
308
|
-
sellerNonceCount++; // 贿赂交易
|
|
309
276
|
if (needApproval)
|
|
310
277
|
sellerNonceCount++; // 授权交易
|
|
311
278
|
sellerNonceCount++; // 利润交易
|
|
@@ -315,10 +282,7 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
315
282
|
// 分配 seller nonces
|
|
316
283
|
const sellerNonces = Array.from({ length: sellerNonceCount }, (_, i) => initialNonces[0] + i);
|
|
317
284
|
let idx = 0;
|
|
318
|
-
let bribeNonce;
|
|
319
285
|
let approvalNonce;
|
|
320
|
-
if (needBribeTx)
|
|
321
|
-
bribeNonce = sellerNonces[idx++];
|
|
322
286
|
if (needApproval)
|
|
323
287
|
approvalNonce = sellerNonces[idx++];
|
|
324
288
|
const sellerNonce = sellerNonces[idx++];
|
|
@@ -327,18 +291,6 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
327
291
|
const buyerNonces = initialNonces.slice(1);
|
|
328
292
|
// ✅ 并行签名所有交易
|
|
329
293
|
const signPromises = [];
|
|
330
|
-
// ✅ 贿赂交易放在首位
|
|
331
|
-
if (needBribeTx && bribeNonce !== undefined) {
|
|
332
|
-
signPromises.push(seller.signTransaction({
|
|
333
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
334
|
-
value: bribeAmount,
|
|
335
|
-
nonce: bribeNonce,
|
|
336
|
-
gasPrice,
|
|
337
|
-
gasLimit: 21000n,
|
|
338
|
-
chainId: chainIdNum,
|
|
339
|
-
type: txType
|
|
340
|
-
}));
|
|
341
|
-
}
|
|
342
294
|
// 授权交易
|
|
343
295
|
if (needApproval && approvalNonce !== undefined) {
|
|
344
296
|
const approveInterface = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
@@ -377,7 +329,7 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
377
329
|
value: buyAmountsWei[i]
|
|
378
330
|
}));
|
|
379
331
|
});
|
|
380
|
-
//
|
|
332
|
+
// 利润交易
|
|
381
333
|
if (profitAmount > 0n) {
|
|
382
334
|
signPromises.push(seller.signTransaction({
|
|
383
335
|
to: PROFIT_CONFIG.RECIPIENT,
|
|
@@ -392,10 +344,7 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
392
344
|
const signedTxs = await Promise.all(signPromises);
|
|
393
345
|
// 解析签名结果
|
|
394
346
|
let signIdx = 0;
|
|
395
|
-
let bribeTx = null;
|
|
396
347
|
let approvalTx = null;
|
|
397
|
-
if (needBribeTx)
|
|
398
|
-
bribeTx = signedTxs[signIdx++];
|
|
399
348
|
if (needApproval)
|
|
400
349
|
approvalTx = signedTxs[signIdx++];
|
|
401
350
|
const signedSell = signedTxs[signIdx++];
|
|
@@ -403,10 +352,8 @@ export async function fourBatchSwapMerkle(params) {
|
|
|
403
352
|
signIdx += buyers.length;
|
|
404
353
|
const profitTx = profitAmount > 0n ? signedTxs[signIdx] : null;
|
|
405
354
|
nonceManager.clearTemp();
|
|
406
|
-
// ✅
|
|
355
|
+
// ✅ 按顺序组装交易数组
|
|
407
356
|
const signedTransactions = [];
|
|
408
|
-
if (bribeTx)
|
|
409
|
-
signedTransactions.push(bribeTx);
|
|
410
357
|
if (approvalTx)
|
|
411
358
|
signedTransactions.push(approvalTx);
|
|
412
359
|
signedTransactions.push(signedSell);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { FlapBundleMerkleConfig, FlapSignConfig, FlapChainForMerkleBundle } from './types.js';
|
|
2
2
|
export type { FlapBundleMerkleConfig, FlapSignConfig, FlapChainForMerkleBundle };
|
|
3
|
-
export declare const BLOCKRAZOR_BUILDER_EOA = "0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20";
|
|
4
3
|
export type FlapAnyConfig = FlapBundleMerkleConfig | FlapSignConfig;
|
|
5
4
|
export declare const CHAIN_ID_MAP: Record<FlapChainForMerkleBundle, number>;
|
|
6
5
|
export declare const MERKLE_SUPPORTED_CHAIN_IDS: readonly [56, 1];
|
|
@@ -71,10 +70,3 @@ export declare function calculateBatchProfit(amounts: bigint[], config?: FlapAny
|
|
|
71
70
|
totalProfit: bigint;
|
|
72
71
|
remainingAmounts: bigint[];
|
|
73
72
|
};
|
|
74
|
-
/**
|
|
75
|
-
* 获取 BlockRazor 贿赂金额(wei)
|
|
76
|
-
* ✅ 用于提高 bundle 打包优先级
|
|
77
|
-
* @param config 配置
|
|
78
|
-
* @returns 贿赂金额(wei),如果未配置则返回 0n
|
|
79
|
-
*/
|
|
80
|
-
export declare function getBribeAmount(config?: FlapAnyConfig): bigint;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
2
|
import { PROFIT_CONFIG } from '../../utils/constants.js';
|
|
3
|
-
// ✅ BlockRazor Builder EOA 地址(用于贿赂)
|
|
4
|
-
// 参考文档: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
|
|
5
|
-
export const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
|
|
6
3
|
// ✅ Chain ID 映射
|
|
7
4
|
// 注意:Merkle 捆绑服务目前只支持 BSC (56) 和 ETH (1)
|
|
8
5
|
// 其他链仅用于非捆绑的签名交易
|
|
@@ -123,17 +120,3 @@ export function calculateBatchProfit(amounts, config) {
|
|
|
123
120
|
}
|
|
124
121
|
return { totalProfit, remainingAmounts };
|
|
125
122
|
}
|
|
126
|
-
/**
|
|
127
|
-
* 获取 BlockRazor 贿赂金额(wei)
|
|
128
|
-
* ✅ 用于提高 bundle 打包优先级
|
|
129
|
-
* @param config 配置
|
|
130
|
-
* @returns 贿赂金额(wei),如果未配置则返回 0n
|
|
131
|
-
*/
|
|
132
|
-
export function getBribeAmount(config) {
|
|
133
|
-
if (!config)
|
|
134
|
-
return 0n;
|
|
135
|
-
const bribeAmount = config.bribeAmount;
|
|
136
|
-
if (!bribeAmount || bribeAmount <= 0)
|
|
137
|
-
return 0n;
|
|
138
|
-
return ethers.parseEther(String(bribeAmount));
|
|
139
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers, Wallet, Contract, Interface } from 'ethers';
|
|
2
2
|
import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
|
|
3
3
|
import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
|
|
4
|
-
import { CHAIN_ID_MAP, PORTAL_ABI, getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient
|
|
4
|
+
import { CHAIN_ID_MAP, PORTAL_ABI, getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient } from './config.js';
|
|
5
5
|
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
6
6
|
const MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11';
|
|
7
7
|
const MULTICALL3_ABI = [
|
|
@@ -153,25 +153,6 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
153
153
|
populateBuyTransactionsWithQuote(buyers, portalAddr, tokenAddress, adjustedFundsList, inputToken, useNativeToken),
|
|
154
154
|
allocateBuyerNonces(buyers, extractProfit, maxFundsIndex, totalProfit, nonceManager)
|
|
155
155
|
]);
|
|
156
|
-
// ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
|
|
157
|
-
const bribeAmount = getBribeAmount(config);
|
|
158
|
-
const bribeTxs = [];
|
|
159
|
-
if (bribeAmount > 0n && maxFundsIndex >= 0 && buyers.length > 0) {
|
|
160
|
-
// 贿赂交易使用 maxFundsIndex 钱包的第一个 nonce
|
|
161
|
-
const bribeNonce = buyerNonces[maxFundsIndex];
|
|
162
|
-
const bribeTx = await buyers[maxFundsIndex].signTransaction({
|
|
163
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
164
|
-
value: bribeAmount,
|
|
165
|
-
nonce: bribeNonce,
|
|
166
|
-
gasPrice,
|
|
167
|
-
gasLimit: 21000n,
|
|
168
|
-
chainId,
|
|
169
|
-
type: getTxType(config)
|
|
170
|
-
});
|
|
171
|
-
bribeTxs.push(bribeTx);
|
|
172
|
-
// 调整 maxFundsIndex 钱包的 nonce(买入交易 +1)
|
|
173
|
-
buyerNonces[maxFundsIndex] = bribeNonce + 1;
|
|
174
|
-
}
|
|
175
156
|
const signedBuys = await signBuyTransactions({
|
|
176
157
|
unsignedBuys,
|
|
177
158
|
buyers,
|
|
@@ -183,25 +164,21 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
183
164
|
fundsList: adjustedFundsList, // ✅ 使用调整后的金额
|
|
184
165
|
useNativeToken // ✅ 传递是否使用原生代币
|
|
185
166
|
});
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
});
|
|
199
|
-
profitTxs.push(profitTx);
|
|
200
|
-
}
|
|
167
|
+
signedTxs.push(...signedBuys);
|
|
168
|
+
await appendProfitTransaction({
|
|
169
|
+
extractProfit,
|
|
170
|
+
totalProfit,
|
|
171
|
+
buyers,
|
|
172
|
+
maxIndex: maxFundsIndex,
|
|
173
|
+
nonces: buyerNonces,
|
|
174
|
+
gasPrice,
|
|
175
|
+
chainId,
|
|
176
|
+
config,
|
|
177
|
+
signedTxs
|
|
178
|
+
});
|
|
201
179
|
nonceManager.clearTemp();
|
|
202
|
-
// ✅ 组装顺序:贿赂 → 创建代币 → 买入 → 利润
|
|
203
180
|
return {
|
|
204
|
-
signedTransactions:
|
|
181
|
+
signedTransactions: signedTxs,
|
|
205
182
|
tokenAddress,
|
|
206
183
|
metadata: buildProfitMetadata(extractProfit, totalBuyAmount, totalProfit, buyers.length)
|
|
207
184
|
};
|
|
@@ -257,24 +234,6 @@ export async function batchBuyWithBundleMerkle(params) {
|
|
|
257
234
|
]);
|
|
258
235
|
if (presetNonces) {
|
|
259
236
|
}
|
|
260
|
-
// ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
|
|
261
|
-
const bribeAmount = getBribeAmount(config);
|
|
262
|
-
const bribeTxs = [];
|
|
263
|
-
if (bribeAmount > 0n && maxFundsIndex >= 0 && buyers.length > 0) {
|
|
264
|
-
const bribeNonce = buyerNonces[maxFundsIndex];
|
|
265
|
-
const bribeTx = await buyers[maxFundsIndex].signTransaction({
|
|
266
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
267
|
-
value: bribeAmount,
|
|
268
|
-
nonce: bribeNonce,
|
|
269
|
-
gasPrice,
|
|
270
|
-
gasLimit: 21000n,
|
|
271
|
-
chainId,
|
|
272
|
-
type: getTxType(config)
|
|
273
|
-
});
|
|
274
|
-
bribeTxs.push(bribeTx);
|
|
275
|
-
// 调整 maxFundsIndex 钱包的 nonce(买入交易 +1)
|
|
276
|
-
buyerNonces[maxFundsIndex] = bribeNonce + 1;
|
|
277
|
-
}
|
|
278
237
|
const signedBuys = await signBuyTransactions({
|
|
279
238
|
unsignedBuys,
|
|
280
239
|
buyers,
|
|
@@ -286,25 +245,21 @@ export async function batchBuyWithBundleMerkle(params) {
|
|
|
286
245
|
fundsList: adjustedFundsList, // ✅ 使用调整后的金额
|
|
287
246
|
useNativeToken // ✅ USDT 购买时 value=0,BNB 购买时 value=金额
|
|
288
247
|
});
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
});
|
|
302
|
-
profitTxs.push(profitTx);
|
|
303
|
-
}
|
|
248
|
+
signedTxs.push(...signedBuys);
|
|
249
|
+
await appendProfitTransaction({
|
|
250
|
+
extractProfit,
|
|
251
|
+
totalProfit: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
|
|
252
|
+
buyers,
|
|
253
|
+
maxIndex: maxFundsIndex,
|
|
254
|
+
nonces: buyerNonces,
|
|
255
|
+
gasPrice,
|
|
256
|
+
chainId,
|
|
257
|
+
config,
|
|
258
|
+
signedTxs
|
|
259
|
+
});
|
|
304
260
|
nonceManager.clearTemp();
|
|
305
|
-
// ✅ 组装顺序:贿赂 → 买入 → 利润
|
|
306
261
|
return {
|
|
307
|
-
signedTransactions:
|
|
262
|
+
signedTransactions: signedTxs,
|
|
308
263
|
metadata: buildProfitMetadata(extractProfit, totalBuyAmount, nativeProfitAmount, buyers.length)
|
|
309
264
|
};
|
|
310
265
|
}
|
|
@@ -355,27 +310,18 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
355
310
|
}
|
|
356
311
|
}
|
|
357
312
|
}
|
|
358
|
-
// ✅
|
|
359
|
-
const bribeAmount = getBribeAmount(config);
|
|
360
|
-
const needBribeTx = bribeAmount > 0n && maxRevenueIndex >= 0;
|
|
313
|
+
// ✅ 修复:根据是否需要利润交易,统一分配 nonces
|
|
361
314
|
const needProfitTx = extractProfit && totalTokenProfit > 0n && maxRevenueIndex >= 0;
|
|
362
|
-
// 计算 maxRevenueIndex 钱包需要的 nonce 数量:贿赂(可选) + 卖出 + 利润(可选)
|
|
363
|
-
const maxRevenueNonceCount = 1 + (needBribeTx ? 1 : 0) + (needProfitTx ? 1 : 0);
|
|
364
315
|
let nonces;
|
|
365
|
-
let bribeNonce;
|
|
366
316
|
let profitNonce;
|
|
367
317
|
if (presetNonces && presetNonces.length === wallets.length) {
|
|
368
|
-
// ✅ 使用前端传入的 nonces
|
|
369
|
-
nonces =
|
|
370
|
-
|
|
371
|
-
bribeNonce = nonces[maxRevenueIndex];
|
|
372
|
-
nonces[maxRevenueIndex] = bribeNonce + 1; // 卖出交易 nonce +1
|
|
373
|
-
}
|
|
374
|
-
profitNonce = needProfitTx ? nonces[maxRevenueIndex] + 1 : undefined;
|
|
318
|
+
// ✅ 使用前端传入的 nonces,但需要调整避免利润交易冲突
|
|
319
|
+
nonces = adjustNoncesForProfit(presetNonces);
|
|
320
|
+
profitNonce = needProfitTx ? presetNonces[maxRevenueIndex] + 1 : undefined;
|
|
375
321
|
}
|
|
376
|
-
else if (
|
|
377
|
-
// maxRevenueIndex
|
|
378
|
-
const maxRevenueNonces = await nonceManager.getNextNonceBatch(wallets[maxRevenueIndex],
|
|
322
|
+
else if (needProfitTx) {
|
|
323
|
+
// maxRevenueIndex 钱包需要 2 个连续 nonce(卖出 + 利润)
|
|
324
|
+
const maxRevenueNonces = await nonceManager.getNextNonceBatch(wallets[maxRevenueIndex], 2);
|
|
379
325
|
// 其他钱包各需要 1 个 nonce
|
|
380
326
|
const otherWallets = wallets.filter((_, i) => i !== maxRevenueIndex);
|
|
381
327
|
const otherNonces = otherWallets.length > 0
|
|
@@ -384,24 +330,18 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
384
330
|
// 组装最终的 nonces 数组(保持原顺序)
|
|
385
331
|
nonces = [];
|
|
386
332
|
let otherIdx = 0;
|
|
387
|
-
let nonceIdx = 0;
|
|
388
|
-
if (needBribeTx) {
|
|
389
|
-
bribeNonce = maxRevenueNonces[nonceIdx++]; // 贿赂交易用第一个 nonce
|
|
390
|
-
}
|
|
391
333
|
for (let i = 0; i < wallets.length; i++) {
|
|
392
334
|
if (i === maxRevenueIndex) {
|
|
393
|
-
nonces.push(maxRevenueNonces[
|
|
335
|
+
nonces.push(maxRevenueNonces[0]); // 卖出交易用第一个 nonce
|
|
394
336
|
}
|
|
395
337
|
else {
|
|
396
338
|
nonces.push(otherNonces[otherIdx++]);
|
|
397
339
|
}
|
|
398
340
|
}
|
|
399
|
-
|
|
400
|
-
profitNonce = maxRevenueNonces[nonceIdx]; // 利润交易用最后一个 nonce
|
|
401
|
-
}
|
|
341
|
+
profitNonce = maxRevenueNonces[1]; // 利润交易用第二个 nonce
|
|
402
342
|
}
|
|
403
343
|
else {
|
|
404
|
-
//
|
|
344
|
+
// 不需要利润交易,所有钱包各 1 个 nonce
|
|
405
345
|
nonces = await nonceManager.getNextNoncesForWallets(wallets);
|
|
406
346
|
}
|
|
407
347
|
const minOuts = resolveMinOutputs(minOutputAmounts, wallets.length, quotedOutputs);
|
|
@@ -413,21 +353,7 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
413
353
|
minOutputAmount: minOuts[i],
|
|
414
354
|
permitData: '0x'
|
|
415
355
|
})));
|
|
416
|
-
// ✅
|
|
417
|
-
const bribeTxs = [];
|
|
418
|
-
if (needBribeTx && bribeNonce !== undefined) {
|
|
419
|
-
const bribeTx = await wallets[maxRevenueIndex].signTransaction({
|
|
420
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
421
|
-
value: bribeAmount,
|
|
422
|
-
nonce: bribeNonce,
|
|
423
|
-
gasPrice,
|
|
424
|
-
gasLimit: 21000n,
|
|
425
|
-
chainId,
|
|
426
|
-
type: getTxType(config)
|
|
427
|
-
});
|
|
428
|
-
bribeTxs.push(bribeTx);
|
|
429
|
-
}
|
|
430
|
-
// ✅ 签名所有卖出交易(并行)
|
|
356
|
+
// ✅ 签名所有交易(并行)
|
|
431
357
|
// ✅ 卖出交易 value 必须为 0,不能发送原生代币
|
|
432
358
|
const signedList = await Promise.all(unsignedList.map((unsigned, i) => wallets[i].signTransaction({
|
|
433
359
|
...unsigned,
|
|
@@ -439,13 +365,16 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
439
365
|
type: getTxType(config),
|
|
440
366
|
value: 0n // ✅ 卖出交易不发送原生代币
|
|
441
367
|
})));
|
|
442
|
-
|
|
443
|
-
|
|
368
|
+
signedTxs.push(...signedList);
|
|
369
|
+
// ✅ 修复:使用预先分配的 profitNonce 添加利润交易
|
|
444
370
|
if (needProfitTx && profitNonce !== undefined) {
|
|
445
371
|
// ERC20 输出时:获取代币利润等值的原生代币(BNB)报价
|
|
446
372
|
let nativeProfitAmount = totalTokenProfit;
|
|
447
373
|
if (!useNativeOutput && outputToken) {
|
|
448
374
|
nativeProfitAmount = await getTokenToNativeQuote(provider, outputToken, totalTokenProfit, chainId);
|
|
375
|
+
// 如果报价失败(返回 0),跳过利润提取
|
|
376
|
+
if (nativeProfitAmount === 0n) {
|
|
377
|
+
}
|
|
449
378
|
}
|
|
450
379
|
if (nativeProfitAmount > 0n) {
|
|
451
380
|
const profitTx = await wallets[maxRevenueIndex].signTransaction({
|
|
@@ -457,13 +386,12 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
457
386
|
chainId,
|
|
458
387
|
type: getTxType(config)
|
|
459
388
|
});
|
|
460
|
-
|
|
389
|
+
signedTxs.push(profitTx);
|
|
461
390
|
}
|
|
462
391
|
}
|
|
463
392
|
nonceManager.clearTemp();
|
|
464
|
-
// ✅ 组装顺序:贿赂 → 卖出 → 利润
|
|
465
393
|
return {
|
|
466
|
-
signedTransactions:
|
|
394
|
+
signedTransactions: signedTxs
|
|
467
395
|
};
|
|
468
396
|
}
|
|
469
397
|
// ✅ Provider 缓存(复用连接,减少初始化开销)
|
|
@@ -607,6 +535,22 @@ async function signBuyTransactions({ unsignedBuys, buyers, nonces, gasLimits, ga
|
|
|
607
535
|
value: useNativeToken ? fundsList[i] : 0n // ✅ 非原生代币时 value 为 0
|
|
608
536
|
})));
|
|
609
537
|
}
|
|
538
|
+
async function appendProfitTransaction({ extractProfit, totalProfit, buyers, maxIndex, nonces, gasPrice, chainId, config, signedTxs }) {
|
|
539
|
+
if (!extractProfit || totalProfit === 0n || buyers.length === 0 || maxIndex < 0) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const profitNonce = (nonces[maxIndex] ?? 0) + 1;
|
|
543
|
+
const profitTx = await buyers[maxIndex].signTransaction({
|
|
544
|
+
to: getProfitRecipient(),
|
|
545
|
+
value: totalProfit,
|
|
546
|
+
nonce: profitNonce,
|
|
547
|
+
gasPrice,
|
|
548
|
+
gasLimit: 23000n,
|
|
549
|
+
chainId,
|
|
550
|
+
type: getTxType(config)
|
|
551
|
+
});
|
|
552
|
+
signedTxs.push(profitTx);
|
|
553
|
+
}
|
|
610
554
|
function buildProfitMetadata(extractProfit, totalBuyAmount, totalProfit, buyerCount) {
|
|
611
555
|
if (!extractProfit) {
|
|
612
556
|
return undefined;
|
|
@@ -684,8 +628,12 @@ async function quoteSellOutputsWithQuote(portal, tokenAddress, amountsWei, outpu
|
|
|
684
628
|
}));
|
|
685
629
|
}
|
|
686
630
|
}
|
|
687
|
-
function resolveMinOutputs(
|
|
688
|
-
|
|
631
|
+
function resolveMinOutputs(provided, walletCount, _quotedOutputs) {
|
|
632
|
+
if (provided && provided.length === walletCount) {
|
|
633
|
+
return provided.map(m => typeof m === 'string' ? ethers.parseEther(m) : BigInt(m));
|
|
634
|
+
}
|
|
635
|
+
// ✅ 默认 minOutput = 0,不设置滑点限制
|
|
636
|
+
// 原因:大额交易时 5% 滑点可能不够,导致交易失败
|
|
689
637
|
return Array(walletCount).fill(0n);
|
|
690
638
|
}
|
|
691
|
-
// ✅
|
|
639
|
+
// ✅ appendSellProfitTransaction 已内联到 batchSellWithBundleMerkle 中,避免 nonce 竞争问题
|