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
|
@@ -8,7 +8,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
10
|
import { PROFIT_CONFIG } from '../../utils/constants.js';
|
|
11
|
-
import { getGasPriceConfig, getTxType, getProfitRecipient
|
|
11
|
+
import { getGasPriceConfig, getTxType, getProfitRecipient } from './config.js';
|
|
12
12
|
/**
|
|
13
13
|
* 获取 Gas Limit(支持 FlapAnyConfig)
|
|
14
14
|
*/
|
|
@@ -116,7 +116,7 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
116
116
|
]);
|
|
117
117
|
const { amount: sellAmountWei, decimals } = sellAmountResult;
|
|
118
118
|
const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
|
|
119
|
-
// ✅ 优化:第二批并行 - approval、quote
|
|
119
|
+
// ✅ 优化:第二批并行 - approval、quote
|
|
120
120
|
const [approvalTx, quote] = await Promise.all([
|
|
121
121
|
config.skipApprovalCheck
|
|
122
122
|
? Promise.resolve(null)
|
|
@@ -134,6 +134,7 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
134
134
|
tokenAddress,
|
|
135
135
|
sellAmountWei,
|
|
136
136
|
provider: chainContext.provider,
|
|
137
|
+
slippageBps: config.slippageBps,
|
|
137
138
|
skipQuoteOnError: config.skipQuoteOnError,
|
|
138
139
|
outputToken // ✅ 传递输出代币
|
|
139
140
|
})
|
|
@@ -143,6 +144,7 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
143
144
|
buyer,
|
|
144
145
|
quotedNative: quote.quotedNative,
|
|
145
146
|
reserveGasEth: config.reserveGasETH,
|
|
147
|
+
slippageBps: config.slippageBps,
|
|
146
148
|
nativeToken: chainContext.nativeToken,
|
|
147
149
|
useNativeToken,
|
|
148
150
|
quoteToken,
|
|
@@ -157,9 +159,6 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
157
159
|
// 将代币利润转换为等值 BNB
|
|
158
160
|
nativeProfitAmount = await getTokenToNativeQuote(chainContext.provider, quoteToken, tokenProfitAmount, chainContext.chainId);
|
|
159
161
|
}
|
|
160
|
-
// ✅ 获取贿赂金额
|
|
161
|
-
const bribeAmount = getBribeAmount(config);
|
|
162
|
-
const needBribeTx = bribeAmount > 0n;
|
|
163
162
|
// ✅ 优化:第四批并行 - 构建交易、获取 nonces、验证余额
|
|
164
163
|
const portalSeller = new Contract(chainContext.portalAddress, PORTAL_ABI, seller);
|
|
165
164
|
const portalBuyer = new Contract(chainContext.portalAddress, PORTAL_ABI, buyer);
|
|
@@ -184,7 +183,6 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
184
183
|
buyer,
|
|
185
184
|
approvalExists: !!approvalTx,
|
|
186
185
|
extractProfit: nativeProfitAmount > 0n,
|
|
187
|
-
needBribeTx, // ✅ 新增:是否需要贿赂交易
|
|
188
186
|
nonceManager
|
|
189
187
|
}),
|
|
190
188
|
validateBalances({
|
|
@@ -220,38 +218,23 @@ export async function flapBundleSwapMerkle(params) {
|
|
|
220
218
|
txType,
|
|
221
219
|
value: useNativeToken ? buyerNeed.maxBuyerValue : 0n // ✅ ERC20 购买时 value=0
|
|
222
220
|
});
|
|
223
|
-
// ✅
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
221
|
+
// ✅ 优化:并行签名所有交易(包括利润交易)
|
|
222
|
+
const signPromises = [
|
|
223
|
+
seller.signTransaction(sellTx),
|
|
224
|
+
buyer.signTransaction(buyTx),
|
|
225
|
+
buildProfitTransaction({
|
|
226
|
+
seller,
|
|
227
|
+
profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
|
|
228
|
+
profitNonce: noncePlan.profitNonce,
|
|
230
229
|
gasPrice,
|
|
231
|
-
gasLimit: 21000n,
|
|
232
230
|
chainId: chainContext.chainId,
|
|
233
|
-
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const [signedSell, signedBuy] = await Promise.all([
|
|
238
|
-
seller.signTransaction(sellTx),
|
|
239
|
-
buyer.signTransaction(buyTx)
|
|
240
|
-
]);
|
|
241
|
-
// ✅ 利润交易放在末尾
|
|
242
|
-
const profitTx = await buildProfitTransaction({
|
|
243
|
-
seller,
|
|
244
|
-
profitAmount: nativeProfitAmount, // ✅ 使用转换后的原生代币利润
|
|
245
|
-
profitNonce: noncePlan.profitNonce,
|
|
246
|
-
gasPrice,
|
|
247
|
-
chainId: chainContext.chainId,
|
|
248
|
-
txType
|
|
249
|
-
});
|
|
231
|
+
txType
|
|
232
|
+
})
|
|
233
|
+
];
|
|
234
|
+
const [signedSell, signedBuy, profitTx] = await Promise.all(signPromises);
|
|
250
235
|
nonceManager.clearTemp();
|
|
251
|
-
//
|
|
236
|
+
// 组装交易列表
|
|
252
237
|
const allTransactions = [];
|
|
253
|
-
if (bribeTx)
|
|
254
|
-
allTransactions.push(bribeTx);
|
|
255
238
|
if (approvalTx)
|
|
256
239
|
allTransactions.push(approvalTx);
|
|
257
240
|
allTransactions.push(signedSell, signedBuy);
|
|
@@ -318,28 +301,32 @@ async function buildApprovalTransaction({ tokenAddress, seller, provider, decima
|
|
|
318
301
|
type: txType
|
|
319
302
|
});
|
|
320
303
|
}
|
|
321
|
-
async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, provider, skipQuoteOnError, outputToken = ZERO_ADDRESS // ✅ 默认使用原生代币
|
|
304
|
+
async function quoteSellOutput({ portalAddress, tokenAddress, sellAmountWei, provider, slippageBps, skipQuoteOnError, outputToken = ZERO_ADDRESS // ✅ 默认使用原生代币
|
|
322
305
|
}) {
|
|
323
306
|
const portal = new Contract(portalAddress, PORTAL_ABI, provider);
|
|
307
|
+
const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
|
|
324
308
|
try {
|
|
325
309
|
const quotedNative = await portal.quoteExactInput.staticCall({
|
|
326
310
|
inputToken: tokenAddress,
|
|
327
311
|
outputToken, // ✅ 使用动态输出代币
|
|
328
312
|
inputAmount: sellAmountWei
|
|
329
313
|
});
|
|
330
|
-
|
|
331
|
-
|
|
314
|
+
const keep = BigInt(10000 - safeSlippage);
|
|
315
|
+
const minOutNative = (quotedNative * keep) / 10000n;
|
|
316
|
+
return { quotedNative, minOutNative };
|
|
332
317
|
}
|
|
333
318
|
catch (err) {
|
|
334
319
|
if (skipQuoteOnError ?? true) {
|
|
320
|
+
console.warn(`⚠️ 报价失败,使用 minOut = 0: ${err}`);
|
|
335
321
|
return { quotedNative: 0n, minOutNative: 0n };
|
|
336
322
|
}
|
|
337
323
|
throw new Error(`卖出报价失败: ${err}`);
|
|
338
324
|
}
|
|
339
325
|
}
|
|
340
326
|
const ERC20_BALANCE_OF_ABI = ['function balanceOf(address) view returns (uint256)'];
|
|
341
|
-
async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
|
|
327
|
+
async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, slippageBps, nativeToken, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
|
|
342
328
|
const reserveGas = ethers.parseEther((reserveGasEth || 0.0005).toString());
|
|
329
|
+
const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
|
|
343
330
|
// ✅ 根据是否使用原生代币获取不同的余额
|
|
344
331
|
let buyerBalance;
|
|
345
332
|
if (useNativeToken) {
|
|
@@ -350,8 +337,11 @@ async function calculateBuyerNeed({ buyer, quotedNative, reserveGasEth, nativeTo
|
|
|
350
337
|
const erc20 = new Contract(quoteToken, ERC20_BALANCE_OF_ABI, provider || buyer.provider);
|
|
351
338
|
buyerBalance = await erc20.balanceOf(buyer.address);
|
|
352
339
|
}
|
|
353
|
-
|
|
354
|
-
|
|
340
|
+
let estimatedBuyerNeed = 0n;
|
|
341
|
+
if (quotedNative > 0n) {
|
|
342
|
+
const increase = BigInt(10000 + safeSlippage);
|
|
343
|
+
estimatedBuyerNeed = (quotedNative * increase) / 10000n;
|
|
344
|
+
}
|
|
355
345
|
// ✅ 原生代币需要预留 Gas,ERC20 不需要
|
|
356
346
|
const buyerNeedTotal = useNativeToken
|
|
357
347
|
? estimatedBuyerNeed + reserveGas
|
|
@@ -395,25 +385,23 @@ async function validateBalances({ buyerNeed, buyerAddress, portalGasCost, provid
|
|
|
395
385
|
}
|
|
396
386
|
/**
|
|
397
387
|
* ✅ 优化:使用批量 nonce 获取(JSON-RPC 批量请求)
|
|
398
|
-
* 交易顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
|
|
399
388
|
*/
|
|
400
|
-
async function planNonces({ seller, buyer, approvalExists, extractProfit,
|
|
401
|
-
if (
|
|
402
|
-
// 卖方需要多个 nonce
|
|
403
|
-
const sellerTxCount = countTruthy([
|
|
389
|
+
async function planNonces({ seller, buyer, approvalExists, extractProfit, nonceManager }) {
|
|
390
|
+
if (approvalExists || extractProfit) {
|
|
391
|
+
// 卖方需要多个 nonce:使用 getNextNonceBatch
|
|
392
|
+
const sellerTxCount = countTruthy([approvalExists, true, extractProfit]);
|
|
404
393
|
// ✅ 优化:并行获取 seller 和 buyer 的 nonce
|
|
405
394
|
const [sellerNonces, buyerNonces] = await Promise.all([
|
|
406
395
|
nonceManager.getNextNonceBatch(seller, sellerTxCount),
|
|
407
396
|
nonceManager.getNextNoncesForWallets([buyer])
|
|
408
397
|
]);
|
|
409
398
|
let idx = 0;
|
|
410
|
-
const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
|
|
411
399
|
if (approvalExists)
|
|
412
400
|
idx++;
|
|
413
401
|
const sellerNonce = sellerNonces[idx++];
|
|
414
402
|
const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
|
|
415
403
|
const buyerNonce = buyerNonces[0];
|
|
416
|
-
return { sellerNonce, buyerNonce,
|
|
404
|
+
return { sellerNonce, buyerNonce, profitNonce };
|
|
417
405
|
}
|
|
418
406
|
// ✅ 优化:使用 getNextNoncesForWallets 批量获取(单次网络往返)
|
|
419
407
|
const nonces = await nonceManager.getNextNoncesForWallets([seller, buyer]);
|
|
@@ -495,7 +483,7 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
495
483
|
]);
|
|
496
484
|
const { amount: sellAmountWei, decimals } = sellAmountResult;
|
|
497
485
|
const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
|
|
498
|
-
// ✅
|
|
486
|
+
// ✅ 并行获取:授权、报价
|
|
499
487
|
const [approvalTx, quote] = await Promise.all([
|
|
500
488
|
config.skipApprovalCheck
|
|
501
489
|
? Promise.resolve(null)
|
|
@@ -513,12 +501,15 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
513
501
|
tokenAddress,
|
|
514
502
|
sellAmountWei,
|
|
515
503
|
provider: chainContext.provider,
|
|
504
|
+
slippageBps: config.slippageBps,
|
|
516
505
|
skipQuoteOnError: config.skipQuoteOnError,
|
|
517
506
|
outputToken
|
|
518
507
|
})
|
|
519
508
|
]);
|
|
520
|
-
// ✅
|
|
521
|
-
const
|
|
509
|
+
// ✅ 计算每个买方的买入金额(按比例分配)
|
|
510
|
+
const safeSlippage = Math.max(0, Math.min(5000, config.slippageBps ?? 100));
|
|
511
|
+
const increase = BigInt(10000 + safeSlippage);
|
|
512
|
+
const totalBuyAmount = (quote.quotedNative * increase) / 10000n;
|
|
522
513
|
let buyAmountsWei;
|
|
523
514
|
if (params.buyerRatios && params.buyerRatios.length === buyers.length) {
|
|
524
515
|
// 按比例分配
|
|
@@ -584,29 +575,12 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
584
575
|
// ✅ 并行获取所有 nonce
|
|
585
576
|
const sellNonce = await nonceManager.getNextNonce(seller);
|
|
586
577
|
const buyerNonces = await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
|
|
587
|
-
//
|
|
588
|
-
const bribeAmount = getBribeAmount(config);
|
|
589
|
-
let bribeTx = null;
|
|
590
|
-
let bribeNonceOffset = 0;
|
|
591
|
-
if (bribeAmount > 0n) {
|
|
592
|
-
const bribeNonce = sellNonce; // 使用卖方的第一个 nonce
|
|
593
|
-
bribeTx = await seller.signTransaction({
|
|
594
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
595
|
-
value: bribeAmount,
|
|
596
|
-
nonce: bribeNonce,
|
|
597
|
-
gasPrice,
|
|
598
|
-
gasLimit: 21000n,
|
|
599
|
-
chainId: chainContext.chainId,
|
|
600
|
-
type: txType
|
|
601
|
-
});
|
|
602
|
-
bribeNonceOffset = 1; // 卖出交易的 nonce 需要 +1
|
|
603
|
-
}
|
|
604
|
-
// 利润交易放在末尾(由卖方发送,与贿赂交易同一钱包)
|
|
578
|
+
// 利润交易 nonce(从第一个买方发送)
|
|
605
579
|
let profitTx = null;
|
|
606
580
|
if (nativeProfitAmount > 0n) {
|
|
607
|
-
|
|
608
|
-
const profitNonce =
|
|
609
|
-
profitTx = await
|
|
581
|
+
const profitPayer = buyers[0];
|
|
582
|
+
const profitNonce = await nonceManager.getNextNonce(profitPayer);
|
|
583
|
+
profitTx = await profitPayer.signTransaction({
|
|
610
584
|
to: getProfitRecipient(),
|
|
611
585
|
value: nativeProfitAmount,
|
|
612
586
|
nonce: profitNonce,
|
|
@@ -620,7 +594,7 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
620
594
|
// ✅ 并行签名所有交易
|
|
621
595
|
const sellTx = buildTransactionRequest(sellUnsigned, {
|
|
622
596
|
from: seller.address,
|
|
623
|
-
nonce: sellNonce
|
|
597
|
+
nonce: sellNonce,
|
|
624
598
|
gasLimit: finalGasLimit,
|
|
625
599
|
gasPrice,
|
|
626
600
|
priorityFee,
|
|
@@ -644,10 +618,8 @@ export async function flapBatchSwapMerkle(params) {
|
|
|
644
618
|
return buyer.signTransaction(buyTx);
|
|
645
619
|
})
|
|
646
620
|
]);
|
|
647
|
-
// ✅
|
|
621
|
+
// ✅ 按顺序组装交易数组
|
|
648
622
|
const signedTransactions = [];
|
|
649
|
-
if (bribeTx)
|
|
650
|
-
signedTransactions.push(bribeTx);
|
|
651
623
|
if (approvalTx)
|
|
652
624
|
signedTransactions.push(approvalTx);
|
|
653
625
|
signedTransactions.push(signedSell);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * as Abis from './abis/index.js';
|
|
2
|
+
export * as Sol from './sol/index.js';
|
|
2
3
|
export { ADDRESSES, CHAIN } from './utils/constants.js';
|
|
3
4
|
export { isExclusiveOnChain, isExclusiveOffChain } from './utils/mpcExclusive.js';
|
|
4
|
-
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
|
|
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 } from './utils/erc20.js';
|
|
5
6
|
export { parseFourError, type FourErrorCode } from './utils/errors.js';
|
|
6
7
|
export { getTokenManagerV1, getTokenManagerV2, getTokenManagerHelper3, getTokenManagerV1Writer, getTokenManagerV2Writer, getTokenManagerHelper3Writer, getTokenManagerAddress, type ChainName } from './utils/contract-factory.js';
|
|
7
8
|
export { FourClient, buildLoginMessage, type FourConfig, type GenerateNonceReq, type LoginReq, type CreateTokenReq, type CreateTokenResp } from './clients/four.js';
|
package/dist/index.js
CHANGED
|
@@ -13,9 +13,9 @@ export interface PancakeBuyFirstSignConfig {
|
|
|
13
13
|
txType?: 0 | 2;
|
|
14
14
|
chainId?: number;
|
|
15
15
|
reserveGasBNB?: number;
|
|
16
|
+
slippageBps?: number;
|
|
16
17
|
skipQuoteOnError?: boolean;
|
|
17
18
|
skipApprovalCheck?: boolean;
|
|
18
|
-
bribeAmount?: number;
|
|
19
19
|
}
|
|
20
20
|
export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
|
|
21
21
|
export interface V2RouteParams {
|
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
7
|
import { NonceManager } from '../utils/bundle-helpers.js';
|
|
8
8
|
import { ADDRESSES, PROFIT_CONFIG } from '../utils/constants.js';
|
|
9
|
-
// ✅ BlockRazor Builder EOA 地址(用于贿赂)
|
|
10
|
-
// 参考文档: https://blockrazor.gitbook.io/blockrazor/bsc/block-builder/send-bundle
|
|
11
|
-
const BLOCKRAZOR_BUILDER_EOA = '0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20';
|
|
12
9
|
function getGasLimit(config, defaultGas = 800000) {
|
|
13
10
|
if (config.gasLimit !== undefined) {
|
|
14
11
|
return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
|
|
@@ -101,7 +98,8 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
101
98
|
const buyerNeed = calculateBuyerNeed({
|
|
102
99
|
quotedNative,
|
|
103
100
|
buyerBalance: buyerFundsInfo.buyerBalance,
|
|
104
|
-
reserveGas: buyerFundsInfo.reserveGas
|
|
101
|
+
reserveGas: buyerFundsInfo.reserveGas,
|
|
102
|
+
slippageBps: config.slippageBps
|
|
105
103
|
});
|
|
106
104
|
const finalGasLimit = getGasLimit(config);
|
|
107
105
|
const gasPrice = await getGasPrice(context.provider, config);
|
|
@@ -127,33 +125,14 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
127
125
|
});
|
|
128
126
|
const profitBase = estimatedProfitFromSell > 0n ? estimatedProfitFromSell : (buyerFundsInfo.buyerFundsWei * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
|
|
129
127
|
const profitAmount = profitBase;
|
|
130
|
-
// ✅ 获取贿赂金额
|
|
131
|
-
const bribeAmount = config.bribeAmount && config.bribeAmount > 0
|
|
132
|
-
? ethers.parseEther(String(config.bribeAmount))
|
|
133
|
-
: 0n;
|
|
134
|
-
const needBribeTx = bribeAmount > 0n;
|
|
135
128
|
const noncePlan = await planNonces({
|
|
136
129
|
buyer,
|
|
137
130
|
seller,
|
|
138
131
|
sameAddress,
|
|
139
132
|
approvalExists: !!approvalTx,
|
|
140
133
|
extractProfit: profitAmount > 0n,
|
|
141
|
-
needBribeTx, // ✅ 新增
|
|
142
134
|
nonceManager
|
|
143
135
|
});
|
|
144
|
-
// ✅ 贿赂交易放在首位(由卖方发送,与利润交易同一钱包)
|
|
145
|
-
let bribeTx = null;
|
|
146
|
-
if (needBribeTx && noncePlan.bribeNonce !== undefined) {
|
|
147
|
-
bribeTx = await seller.signTransaction({
|
|
148
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
149
|
-
value: bribeAmount,
|
|
150
|
-
nonce: noncePlan.bribeNonce,
|
|
151
|
-
gasPrice,
|
|
152
|
-
gasLimit: 21000n,
|
|
153
|
-
chainId: context.chainId,
|
|
154
|
-
type: txType
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
136
|
const signedBuy = await buyer.signTransaction({
|
|
158
137
|
...swapUnsigned.buyUnsigned,
|
|
159
138
|
from: buyer.address,
|
|
@@ -172,7 +151,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
172
151
|
chainId: context.chainId,
|
|
173
152
|
type: txType
|
|
174
153
|
});
|
|
175
|
-
// ✅ 利润交易放在末尾
|
|
176
154
|
const profitTx = await buildProfitTransaction({
|
|
177
155
|
seller,
|
|
178
156
|
profitAmount,
|
|
@@ -194,10 +172,7 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
194
172
|
provider: context.provider,
|
|
195
173
|
buyerAddress: buyer.address
|
|
196
174
|
});
|
|
197
|
-
// ✅ 组装顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
|
|
198
175
|
const allTransactions = [];
|
|
199
|
-
if (bribeTx)
|
|
200
|
-
allTransactions.push(bribeTx);
|
|
201
176
|
if (approvalTx)
|
|
202
177
|
allTransactions.push(approvalTx);
|
|
203
178
|
allTransactions.push(signedBuy, signedSell);
|
|
@@ -328,9 +303,13 @@ async function quoteSellerNative({ provider, tokenAddress, sellAmountToken }) {
|
|
|
328
303
|
return 0n;
|
|
329
304
|
}
|
|
330
305
|
}
|
|
331
|
-
function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas }) {
|
|
332
|
-
|
|
333
|
-
|
|
306
|
+
function calculateBuyerNeed({ quotedNative, buyerBalance, reserveGas, slippageBps }) {
|
|
307
|
+
let estimatedBuyerNeed = 0n;
|
|
308
|
+
if (quotedNative > 0n) {
|
|
309
|
+
const safeSlippage = Math.max(0, Math.min(5000, slippageBps ?? 100));
|
|
310
|
+
const increase = BigInt(10000 + safeSlippage);
|
|
311
|
+
estimatedBuyerNeed = (quotedNative * increase) / 10000n;
|
|
312
|
+
}
|
|
334
313
|
const buyerNeedTotal = estimatedBuyerNeed + reserveGas;
|
|
335
314
|
if (buyerBalance < buyerNeedTotal) {
|
|
336
315
|
throw new Error(`买方余额不足:\n - 需要: ${ethers.formatEther(buyerNeedTotal)} BNB\n - 实际: ${ethers.formatEther(buyerBalance)} BNB`);
|
|
@@ -402,39 +381,28 @@ async function estimateProfitAmount({ provider, tokenAddress, sellAmountToken })
|
|
|
402
381
|
return 0n;
|
|
403
382
|
}
|
|
404
383
|
}
|
|
405
|
-
|
|
406
|
-
* ✅ 规划 nonce
|
|
407
|
-
* 交易顺序:贿赂 → 授权 → 买入 → 卖出 → 利润
|
|
408
|
-
*/
|
|
409
|
-
async function planNonces({ buyer, seller, sameAddress, approvalExists, extractProfit, needBribeTx, nonceManager }) {
|
|
384
|
+
async function planNonces({ buyer, seller, sameAddress, approvalExists, extractProfit, nonceManager }) {
|
|
410
385
|
if (sameAddress) {
|
|
411
|
-
|
|
412
|
-
const txCount = countTruthy([needBribeTx, approvalExists, true, true, extractProfit]);
|
|
386
|
+
const txCount = countTruthy([approvalExists, true, true, extractProfit]);
|
|
413
387
|
const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
|
|
414
388
|
let idx = 0;
|
|
415
|
-
const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
|
|
416
389
|
if (approvalExists)
|
|
417
390
|
idx++;
|
|
418
391
|
const buyerNonce = nonces[idx++];
|
|
419
392
|
const sellerNonce = nonces[idx++];
|
|
420
393
|
const profitNonce = extractProfit ? nonces[idx] : undefined;
|
|
421
|
-
return { buyerNonce, sellerNonce,
|
|
394
|
+
return { buyerNonce, sellerNonce, profitNonce };
|
|
422
395
|
}
|
|
423
|
-
if (
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
// ✅ 并行获取 seller 和 buyer 的 nonce
|
|
427
|
-
const [sellerNonces, buyerNonce] = await Promise.all([
|
|
428
|
-
nonceManager.getNextNonceBatch(seller, sellerTxCount),
|
|
429
|
-
nonceManager.getNextNonce(buyer)
|
|
430
|
-
]);
|
|
396
|
+
if (approvalExists || extractProfit) {
|
|
397
|
+
const sellerTxCount = countTruthy([approvalExists, true, extractProfit]);
|
|
398
|
+
const sellerNonces = await nonceManager.getNextNonceBatch(seller, sellerTxCount);
|
|
431
399
|
let idx = 0;
|
|
432
|
-
const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
|
|
433
400
|
if (approvalExists)
|
|
434
401
|
idx++;
|
|
435
402
|
const sellerNonce = sellerNonces[idx++];
|
|
436
403
|
const profitNonce = extractProfit ? sellerNonces[idx] : undefined;
|
|
437
|
-
|
|
404
|
+
const buyerNonce = await nonceManager.getNextNonce(buyer);
|
|
405
|
+
return { buyerNonce, sellerNonce, profitNonce };
|
|
438
406
|
}
|
|
439
407
|
const [buyerNonce, sellerNonce] = await Promise.all([
|
|
440
408
|
nonceManager.getNextNonce(buyer),
|
|
@@ -8,8 +8,8 @@ export interface PancakeSwapSignConfig {
|
|
|
8
8
|
txType?: 0 | 2;
|
|
9
9
|
chainId?: number;
|
|
10
10
|
reserveGasBNB?: number;
|
|
11
|
+
slippageTolerance?: number;
|
|
11
12
|
skipApprovalCheck?: boolean;
|
|
12
|
-
bribeAmount?: number;
|
|
13
13
|
}
|
|
14
14
|
export type SwapRouteType = 'v2' | 'v3-single' | 'v3-multi';
|
|
15
15
|
export interface PancakeSwapConfig extends CommonBundleConfig {
|
|
@@ -46,6 +46,7 @@ export interface PancakeBundleSwapSignParams {
|
|
|
46
46
|
buyerPrivateKey: string;
|
|
47
47
|
tokenAddress: string;
|
|
48
48
|
routeParams: RouteParams;
|
|
49
|
+
slippageTolerance?: number;
|
|
49
50
|
config: PancakeSwapSignConfig;
|
|
50
51
|
quoteToken?: string;
|
|
51
52
|
quoteTokenDecimals?: number;
|
|
@@ -57,6 +58,7 @@ export interface PancakeBundleSwapParams {
|
|
|
57
58
|
buyerPrivateKey: string;
|
|
58
59
|
tokenAddress: string;
|
|
59
60
|
routeParams: RouteParams;
|
|
61
|
+
slippageTolerance?: number;
|
|
60
62
|
config: PancakeSwapConfig;
|
|
61
63
|
}
|
|
62
64
|
/** ✅ Pancake Swap 结果(简化版) */
|
|
@@ -88,6 +90,7 @@ export interface PancakeBatchSwapSignParams {
|
|
|
88
90
|
buyerRatios?: number[];
|
|
89
91
|
tokenAddress: string;
|
|
90
92
|
routeParams: RouteParams;
|
|
93
|
+
slippageTolerance?: number;
|
|
91
94
|
config: PancakeSwapSignConfig;
|
|
92
95
|
quoteToken?: string;
|
|
93
96
|
quoteTokenDecimals?: number;
|