four-flap-meme-sdk 1.4.67 → 1.4.68
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.
|
@@ -105,34 +105,23 @@ export async function fourBundleBuyFirstMerkle(params) {
|
|
|
105
105
|
if (buyerFundsWei <= 0n) {
|
|
106
106
|
throw new Error('buyerFunds 需要大于 0');
|
|
107
107
|
}
|
|
108
|
-
// ✅ 优化:第二批并行 - buyQuote、sellerTokenBal、decimals
|
|
108
|
+
// ✅ 优化:第二批并行 - buyQuote、sellerTokenBal、decimals
|
|
109
109
|
const helper3 = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER3_ABI, provider);
|
|
110
110
|
const erc20 = new Contract(tokenAddress, [
|
|
111
111
|
'function balanceOf(address) view returns (uint256)',
|
|
112
|
-
'function decimals() view returns (uint8)'
|
|
113
|
-
'function allowance(address,address) view returns (uint256)'
|
|
112
|
+
'function decimals() view returns (uint8)'
|
|
114
113
|
], provider);
|
|
115
|
-
const [buyQuote, sellerTokenBal, decimals
|
|
114
|
+
const [buyQuote, sellerTokenBal, decimals] = await Promise.all([
|
|
116
115
|
helper3.tryBuy(tokenAddress, 0n, buyerFundsWei),
|
|
117
116
|
erc20.balanceOf(seller.address),
|
|
118
|
-
erc20.decimals()
|
|
119
|
-
erc20.allowance(seller.address, TM_ADDRESS)
|
|
117
|
+
erc20.decimals()
|
|
120
118
|
]);
|
|
121
|
-
// ✅ 检查是否需要授权(授权额度小于 10 亿代币时需要授权)
|
|
122
|
-
const APPROVAL_THRESHOLD = ethers.parseUnits('1000000000', decimals);
|
|
123
|
-
const needApproval = currentAllowance < APPROVAL_THRESHOLD;
|
|
124
119
|
const estimatedTokenAmount = buyQuote.estimatedAmount ?? buyQuote[2];
|
|
125
120
|
if (!estimatedTokenAmount || estimatedTokenAmount <= 0n) {
|
|
126
121
|
throw new Error('报价失败:无法估算可买入的代币数量');
|
|
127
122
|
}
|
|
128
|
-
// ✅
|
|
129
|
-
|
|
130
|
-
// 每多一笔买入,减少 0.5% 的卖出数量(保守估计)
|
|
131
|
-
let sellAmountWei = estimatedTokenAmount;
|
|
132
|
-
if (buyCount > 1) {
|
|
133
|
-
const slippageReductionBps = BigInt((buyCount - 1) * 50); // 每多1笔减少 0.5% = 50 bps
|
|
134
|
-
sellAmountWei = estimatedTokenAmount * (10000n - slippageReductionBps) / 10000n;
|
|
135
|
-
}
|
|
123
|
+
// ✅ 直接使用报价的代币数量(与 Flap 一致,不做滑点调整)
|
|
124
|
+
const sellAmountWei = estimatedTokenAmount;
|
|
136
125
|
// 卖方余额检查
|
|
137
126
|
if (!sameAddress && sellerTokenBal < sellAmountWei) {
|
|
138
127
|
throw new Error(`卖方代币余额不足: 需要 ${ethers.formatUnits(sellAmountWei, decimals)},实际 ${ethers.formatUnits(sellerTokenBal, decimals)}`);
|
|
@@ -151,7 +140,7 @@ export async function fourBundleBuyFirstMerkle(params) {
|
|
|
151
140
|
// ✅ 构建多笔买入和卖出交易
|
|
152
141
|
const buyUnsignedPromises = buyAmountsWei.map(amount => tmBuyer.buyTokenAMAP.populateTransaction(0n, tokenAddress, buyer.address, amount, 0n, { value: amount }));
|
|
153
142
|
const sellUnsignedPromises = sellAmountsWei.map(amount => tmSeller.sellToken.populateTransaction(0n, tokenAddress, amount, 0n));
|
|
154
|
-
// ✅ 规划多笔交易 nonce
|
|
143
|
+
// ✅ 规划多笔交易 nonce(与 Flap 一致,不含授权)
|
|
155
144
|
const multiNoncePlan = await planMultiNonces({
|
|
156
145
|
buyer,
|
|
157
146
|
seller,
|
|
@@ -159,7 +148,6 @@ export async function fourBundleBuyFirstMerkle(params) {
|
|
|
159
148
|
sellCount,
|
|
160
149
|
extractProfit,
|
|
161
150
|
needBribeTx,
|
|
162
|
-
needApproval, // ✅ 新增
|
|
163
151
|
sameAddress,
|
|
164
152
|
nonceManager
|
|
165
153
|
});
|
|
@@ -204,35 +192,16 @@ export async function fourBundleBuyFirstMerkle(params) {
|
|
|
204
192
|
type: txType,
|
|
205
193
|
value: 0n
|
|
206
194
|
}));
|
|
207
|
-
// ✅ 授权交易(放在买入后、卖出前)
|
|
208
|
-
let approvalTx = null;
|
|
209
|
-
if (needApproval && multiNoncePlan.approvalNonce !== undefined) {
|
|
210
|
-
const approveInterface = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
211
|
-
const approveData = approveInterface.encodeFunctionData('approve', [TM_ADDRESS, ethers.MaxUint256]);
|
|
212
|
-
approvalTx = await seller.signTransaction({
|
|
213
|
-
to: tokenAddress,
|
|
214
|
-
data: approveData,
|
|
215
|
-
value: 0n,
|
|
216
|
-
nonce: multiNoncePlan.approvalNonce,
|
|
217
|
-
gasLimit: 80000n,
|
|
218
|
-
gasPrice,
|
|
219
|
-
chainId: chainIdNum,
|
|
220
|
-
type: txType
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
195
|
const [signedBuys, signedSells] = await Promise.all([
|
|
224
196
|
Promise.all(buySignPromises),
|
|
225
197
|
Promise.all(sellSignPromises)
|
|
226
198
|
]);
|
|
227
199
|
nonceManager.clearTemp();
|
|
228
|
-
// ✅ 组装交易列表:贿赂 → 买入(多笔) →
|
|
200
|
+
// ✅ 组装交易列表:贿赂 → 买入(多笔) → 卖出(多笔)(与 Flap 一致)
|
|
229
201
|
const allTransactions = [];
|
|
230
202
|
if (bribeTx)
|
|
231
203
|
allTransactions.push(bribeTx);
|
|
232
|
-
allTransactions.push(...signedBuys);
|
|
233
|
-
if (approvalTx)
|
|
234
|
-
allTransactions.push(approvalTx);
|
|
235
|
-
allTransactions.push(...signedSells);
|
|
204
|
+
allTransactions.push(...signedBuys, ...signedSells);
|
|
236
205
|
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
237
206
|
let profitHopWallets;
|
|
238
207
|
if (extractProfit && profitAmount > 0n && multiNoncePlan.profitNonce !== undefined) {
|
|
@@ -266,39 +235,38 @@ export async function fourBundleBuyFirstMerkle(params) {
|
|
|
266
235
|
};
|
|
267
236
|
}
|
|
268
237
|
/**
|
|
269
|
-
* ✅ 规划多笔交易 nonce
|
|
270
|
-
* 交易顺序:贿赂 → 买入(多笔) →
|
|
238
|
+
* ✅ 规划多笔交易 nonce(与 Flap 一致)
|
|
239
|
+
* 交易顺序:贿赂 → 买入(多笔) → 卖出(多笔) → 利润
|
|
271
240
|
*/
|
|
272
|
-
async function planMultiNonces({ buyer, seller, buyCount, sellCount, extractProfit, needBribeTx,
|
|
241
|
+
async function planMultiNonces({ buyer, seller, buyCount, sellCount, extractProfit, needBribeTx, sameAddress, nonceManager }) {
|
|
273
242
|
const profitNonceCount = extractProfit ? 1 : 0;
|
|
274
|
-
const approvalTxCount = needApproval ? 1 : 0;
|
|
275
243
|
if (sameAddress) {
|
|
276
|
-
//
|
|
244
|
+
// 同一地址:贿赂(可选) + 买入(多笔) + 卖出(多笔) + 利润(可选)
|
|
277
245
|
const bribeTxCount = needBribeTx ? 1 : 0;
|
|
278
|
-
const totalTxCount = bribeTxCount + buyCount +
|
|
246
|
+
const totalTxCount = bribeTxCount + buyCount + sellCount + profitNonceCount;
|
|
279
247
|
const nonces = await nonceManager.getNextNonceBatch(buyer, totalTxCount);
|
|
280
248
|
let idx = 0;
|
|
281
249
|
const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
|
|
282
250
|
const buyerNonces = nonces.slice(idx, idx + buyCount);
|
|
283
251
|
idx += buyCount;
|
|
284
|
-
const approvalNonce = needApproval ? nonces[idx++] : undefined;
|
|
285
252
|
const sellerNonces = nonces.slice(idx, idx + sellCount);
|
|
286
253
|
idx += sellCount;
|
|
287
254
|
const profitNonce = extractProfit ? nonces[idx] : undefined;
|
|
288
|
-
return { buyerNonces, sellerNonces, bribeNonce,
|
|
255
|
+
return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
|
|
289
256
|
}
|
|
290
|
-
//
|
|
257
|
+
// 不同地址
|
|
258
|
+
// 买方:buyCount 个 nonce
|
|
259
|
+
// 卖方:贿赂(可选) + sellCount + 利润(可选) 个 nonce
|
|
291
260
|
const bribeTxCount = needBribeTx ? 1 : 0;
|
|
292
|
-
const sellerTxCount = bribeTxCount +
|
|
261
|
+
const sellerTxCount = bribeTxCount + sellCount + profitNonceCount;
|
|
293
262
|
const [buyerNonces, sellerNoncesAll] = await Promise.all([
|
|
294
263
|
nonceManager.getNextNonceBatch(buyer, buyCount),
|
|
295
264
|
nonceManager.getNextNonceBatch(seller, sellerTxCount)
|
|
296
265
|
]);
|
|
297
266
|
let idx = 0;
|
|
298
267
|
const bribeNonce = needBribeTx ? sellerNoncesAll[idx++] : undefined;
|
|
299
|
-
const approvalNonce = needApproval ? sellerNoncesAll[idx++] : undefined;
|
|
300
268
|
const sellerNonces = sellerNoncesAll.slice(idx, idx + sellCount);
|
|
301
269
|
idx += sellCount;
|
|
302
270
|
const profitNonce = extractProfit ? sellerNoncesAll[idx] : undefined;
|
|
303
|
-
return { buyerNonces, sellerNonces, bribeNonce,
|
|
271
|
+
return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
|
|
304
272
|
}
|
|
@@ -121,31 +121,10 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
121
121
|
buyerFundsWei: buyerFundsInfo.buyerFundsWei,
|
|
122
122
|
provider: context.provider
|
|
123
123
|
});
|
|
124
|
-
// ✅
|
|
125
|
-
const approvalTarget = routeParams.routeType === 'v2'
|
|
126
|
-
? PANCAKE_V2_ROUTER_ADDRESS
|
|
127
|
-
: PANCAKE_V3_ROUTER_ADDRESS;
|
|
128
|
-
const erc20ForApproval = new Contract(tokenAddress, [
|
|
129
|
-
'function allowance(address,address) view returns (uint256)',
|
|
130
|
-
'function decimals() view returns (uint8)'
|
|
131
|
-
], context.provider);
|
|
132
|
-
const [currentAllowance, tokenDecimals] = await Promise.all([
|
|
133
|
-
erc20ForApproval.allowance(seller.address, approvalTarget),
|
|
134
|
-
erc20ForApproval.decimals()
|
|
135
|
-
]);
|
|
136
|
-
const APPROVAL_THRESHOLD = ethers.parseUnits('1000000000', tokenDecimals);
|
|
137
|
-
const needApproval = currentAllowance < APPROVAL_THRESHOLD;
|
|
138
|
-
// ✅ 多笔买入时减少卖出数量以应对滑点
|
|
139
|
-
// 原因:分批买入会推高价格,实际获得的代币 < 一次性买入的报价
|
|
140
|
-
// 每多一笔买入,减少 0.5% 的卖出数量(保守估计)
|
|
141
|
-
let adjustedSellAmount = quoteResult.quotedTokenOut;
|
|
142
|
-
if (buyCount > 1) {
|
|
143
|
-
const slippageReductionBps = BigInt((buyCount - 1) * 50); // 每多1笔减少 0.5% = 50 bps
|
|
144
|
-
adjustedSellAmount = quoteResult.quotedTokenOut * (10000n - slippageReductionBps) / 10000n;
|
|
145
|
-
}
|
|
124
|
+
// ✅ 直接使用报价的代币数量(与 Flap 一致,不做滑点调整)
|
|
146
125
|
// ✅ 拆分买入和卖出金额
|
|
147
126
|
const buyAmountsWei = splitAmount(buyerFundsInfo.buyerFundsWei, buyCount);
|
|
148
|
-
const sellAmountsWei = splitAmount(
|
|
127
|
+
const sellAmountsWei = splitAmount(quoteResult.quotedTokenOut, sellCount);
|
|
149
128
|
// ✅ 构建多笔买入和卖出交易
|
|
150
129
|
const swapUnsignedArray = await buildMultiRouteTransactions({
|
|
151
130
|
routeParams,
|
|
@@ -195,7 +174,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
195
174
|
sameAddress,
|
|
196
175
|
extractProfit: profitAmount > 0n,
|
|
197
176
|
needBribeTx,
|
|
198
|
-
needApproval, // ✅ 新增
|
|
199
177
|
nonceManager
|
|
200
178
|
});
|
|
201
179
|
// ✅ 贿赂交易放在首位(由卖方发送,与利润交易同一钱包)
|
|
@@ -221,22 +199,6 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
221
199
|
chainId: context.chainId,
|
|
222
200
|
type: txType
|
|
223
201
|
})));
|
|
224
|
-
// ✅ 授权交易(放在买入后、卖出前)
|
|
225
|
-
let approvalTx = null;
|
|
226
|
-
if (needApproval && multiNoncePlan.approvalNonce !== undefined) {
|
|
227
|
-
const approveInterface = new ethers.Interface(['function approve(address,uint256) returns (bool)']);
|
|
228
|
-
const approveData = approveInterface.encodeFunctionData('approve', [approvalTarget, ethers.MaxUint256]);
|
|
229
|
-
approvalTx = await seller.signTransaction({
|
|
230
|
-
to: tokenAddress,
|
|
231
|
-
data: approveData,
|
|
232
|
-
value: 0n,
|
|
233
|
-
nonce: multiNoncePlan.approvalNonce,
|
|
234
|
-
gasLimit: 80000n,
|
|
235
|
-
gasPrice,
|
|
236
|
-
chainId: context.chainId,
|
|
237
|
-
type: txType
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
202
|
// ✅ 并行签名所有卖出交易
|
|
241
203
|
const signedSells = await Promise.all(swapUnsignedArray.sellUnsignedArray.map((unsigned, i) => seller.signTransaction({
|
|
242
204
|
...unsigned,
|
|
@@ -260,14 +222,11 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
260
222
|
provider: context.provider,
|
|
261
223
|
buyerAddress: buyer.address
|
|
262
224
|
});
|
|
263
|
-
// ✅ 组装顺序:贿赂 → 买入(多笔) →
|
|
225
|
+
// ✅ 组装顺序:贿赂 → 买入(多笔) → 卖出(多笔)(与 Flap 一致)
|
|
264
226
|
const allTransactions = [];
|
|
265
227
|
if (bribeTx)
|
|
266
228
|
allTransactions.push(bribeTx);
|
|
267
|
-
allTransactions.push(...signedBuys);
|
|
268
|
-
if (approvalTx)
|
|
269
|
-
allTransactions.push(approvalTx);
|
|
270
|
-
allTransactions.push(...signedSells);
|
|
229
|
+
allTransactions.push(...signedBuys, ...signedSells);
|
|
271
230
|
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
272
231
|
const profitResult = await buildProfitTransaction({
|
|
273
232
|
provider: context.provider,
|
|
@@ -577,42 +536,40 @@ async function planNonces({ buyer, seller, sameAddress, extractProfit, needBribe
|
|
|
577
536
|
return { buyerNonce, sellerNonce };
|
|
578
537
|
}
|
|
579
538
|
/**
|
|
580
|
-
* ✅ 规划多笔交易 nonce
|
|
581
|
-
* 交易顺序:贿赂 → 买入(多笔) →
|
|
539
|
+
* ✅ 规划多笔交易 nonce(与 Flap 一致)
|
|
540
|
+
* 交易顺序:贿赂 → 买入(多笔) → 卖出(多笔) → 利润
|
|
582
541
|
*/
|
|
583
|
-
async function planMultiNonces({ buyer, seller, buyCount, sellCount, sameAddress, extractProfit, needBribeTx,
|
|
584
|
-
nonceManager }) {
|
|
542
|
+
async function planMultiNonces({ buyer, seller, buyCount, sellCount, sameAddress, extractProfit, needBribeTx, nonceManager }) {
|
|
585
543
|
const profitNonceCount = extractProfit ? 1 : 0;
|
|
586
|
-
const approvalTxCount = needApproval ? 1 : 0;
|
|
587
544
|
if (sameAddress) {
|
|
588
|
-
//
|
|
545
|
+
// 同一地址:贿赂(可选) + 买入(多笔) + 卖出(多笔) + 利润(可选)
|
|
589
546
|
const bribeTxCount = needBribeTx ? 1 : 0;
|
|
590
|
-
const totalTxCount = bribeTxCount + buyCount +
|
|
547
|
+
const totalTxCount = bribeTxCount + buyCount + sellCount + profitNonceCount;
|
|
591
548
|
const nonces = await nonceManager.getNextNonceBatch(buyer, totalTxCount);
|
|
592
549
|
let idx = 0;
|
|
593
550
|
const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
|
|
594
551
|
const buyerNonces = nonces.slice(idx, idx + buyCount);
|
|
595
552
|
idx += buyCount;
|
|
596
|
-
const approvalNonce = needApproval ? nonces[idx++] : undefined;
|
|
597
553
|
const sellerNonces = nonces.slice(idx, idx + sellCount);
|
|
598
554
|
idx += sellCount;
|
|
599
555
|
const profitNonce = extractProfit ? nonces[idx] : undefined;
|
|
600
|
-
return { buyerNonces, sellerNonces, bribeNonce,
|
|
556
|
+
return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
|
|
601
557
|
}
|
|
602
|
-
//
|
|
558
|
+
// 不同地址
|
|
559
|
+
// 买方:buyCount 个 nonce
|
|
560
|
+
// 卖方:贿赂(可选) + sellCount + 利润(可选) 个 nonce
|
|
603
561
|
const bribeTxCount = needBribeTx ? 1 : 0;
|
|
604
|
-
const sellerTxCount = bribeTxCount +
|
|
562
|
+
const sellerTxCount = bribeTxCount + sellCount + profitNonceCount;
|
|
605
563
|
const [buyerNonces, sellerNoncesAll] = await Promise.all([
|
|
606
564
|
nonceManager.getNextNonceBatch(buyer, buyCount),
|
|
607
565
|
nonceManager.getNextNonceBatch(seller, sellerTxCount)
|
|
608
566
|
]);
|
|
609
567
|
let idx = 0;
|
|
610
568
|
const bribeNonce = needBribeTx ? sellerNoncesAll[idx++] : undefined;
|
|
611
|
-
const approvalNonce = needApproval ? sellerNoncesAll[idx++] : undefined;
|
|
612
569
|
const sellerNonces = sellerNoncesAll.slice(idx, idx + sellCount);
|
|
613
570
|
idx += sellCount;
|
|
614
571
|
const profitNonce = extractProfit ? sellerNoncesAll[idx] : undefined;
|
|
615
|
-
return { buyerNonces, sellerNonces, bribeNonce,
|
|
572
|
+
return { buyerNonces, sellerNonces, bribeNonce, profitNonce };
|
|
616
573
|
}
|
|
617
574
|
/**
|
|
618
575
|
* 构建利润多跳转账交易(强制 2 跳中转)
|