four-flap-meme-sdk 1.3.99 → 1.4.2

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.
@@ -2,7 +2,7 @@ import { ethers, Wallet } from 'ethers';
2
2
  import { MerkleClient } from '../../clients/merkle.js';
3
3
  import { getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
4
4
  import { FLAP_PORTAL_ADDRESSES } from '../constants.js';
5
- import { CHAIN_ID_MAP, PORTAL_ABI, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient } from './config.js';
5
+ import { CHAIN_ID_MAP, PORTAL_ABI, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
6
6
  const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
7
7
  const DEFAULT_GAS_LIMIT = 800000;
8
8
  /**
@@ -32,27 +32,55 @@ export async function flapPrivateBuyMerkle(params) {
32
32
  }, { value: actualAmountWei })
33
33
  ]);
34
34
  const gasLimit = resolveGasLimit(config.gasLimitMultiplier);
35
- const signedTxs = [];
36
- signedTxs.push(await wallet.signTransaction({
35
+ // 获取贿赂金额
36
+ const bribeAmount = getBribeAmount(config);
37
+ const needBribeTx = bribeAmount > 0n;
38
+ const needProfitTx = extractProfit && profitWei > 0n;
39
+ // ✅ 分配 nonces:贿赂 → 买入 → 利润
40
+ let nonceIdx = 0;
41
+ const bribeNonce = needBribeTx ? currentNonce + nonceIdx++ : undefined;
42
+ const buyNonce = currentNonce + nonceIdx++;
43
+ const profitNonce = needProfitTx ? currentNonce + nonceIdx : undefined;
44
+ // ✅ 并行签名所有交易(贿赂、买入、利润)
45
+ const signPromises = [];
46
+ const txType = getTxType(config);
47
+ // 贿赂交易
48
+ if (needBribeTx && bribeNonce !== undefined) {
49
+ signPromises.push(wallet.signTransaction({
50
+ to: BLOCKRAZOR_BUILDER_EOA,
51
+ value: bribeAmount,
52
+ nonce: bribeNonce,
53
+ gasPrice,
54
+ gasLimit: 21000n,
55
+ chainId,
56
+ type: txType
57
+ }));
58
+ }
59
+ // 买入交易
60
+ signPromises.push(wallet.signTransaction({
37
61
  ...unsigned,
38
62
  from: wallet.address,
39
- nonce: currentNonce,
63
+ nonce: buyNonce,
40
64
  gasLimit,
41
65
  gasPrice,
42
66
  chainId,
43
- type: getTxType(config),
67
+ type: txType,
44
68
  value: actualAmountWei
45
69
  }));
46
- await appendSingleProfitTransfer({
47
- extractProfit,
48
- profitWei,
49
- wallet,
50
- baseNonce: currentNonce,
51
- gasPrice,
52
- chainId,
53
- config,
54
- signedTxs
55
- });
70
+ // 利润交易
71
+ if (needProfitTx && profitNonce !== undefined) {
72
+ signPromises.push(wallet.signTransaction({
73
+ to: getProfitRecipient(),
74
+ value: profitWei,
75
+ nonce: profitNonce,
76
+ gasPrice,
77
+ gasLimit: 21000n,
78
+ chainId,
79
+ type: txType
80
+ }));
81
+ }
82
+ // ✅ 并行签名完成后按顺序返回
83
+ const signedTxs = await Promise.all(signPromises);
56
84
  return { signedTransactions: signedTxs };
57
85
  }
58
86
  /**
@@ -65,41 +93,73 @@ export async function flapPrivateSellMerkle(params) {
65
93
  const portalAddr = FLAP_PORTAL_ADDRESSES[chain];
66
94
  const amountWei = ethers.parseUnits(amount, 18);
67
95
  const portal = new ethers.Contract(portalAddr, PORTAL_ABI, wallet);
68
- // ✅ 并行获取 gasPrice、nonce 和报价
69
- const [gasPrice, currentNonce, { quotedOutput, minOut }] = await Promise.all([
96
+ // ✅ 并行获取 gasPrice、nonce、报价和构建未签名交易
97
+ const [gasPrice, currentNonce, { quotedOutput }, unsigned] = await Promise.all([
70
98
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
71
99
  wallet.getNonce(),
72
- resolveSingleSellOutputs(portal, tokenAddress, amountWei, minOutputAmount)
100
+ resolveSingleSellOutputs(portal, tokenAddress, amountWei, minOutputAmount),
101
+ portal.swapExactInput.populateTransaction({
102
+ inputToken: tokenAddress,
103
+ outputToken: ZERO_ADDRESS,
104
+ inputAmount: amountWei,
105
+ minOutputAmount: 0n, // ✅ 已移除滑点保护
106
+ permitData: '0x',
107
+ })
73
108
  ]);
74
- // 构建未签名交易
75
- const unsigned = await portal.swapExactInput.populateTransaction({
76
- inputToken: tokenAddress,
77
- outputToken: ZERO_ADDRESS,
78
- inputAmount: amountWei,
79
- minOutputAmount: minOut,
80
- permitData: '0x',
81
- });
82
109
  const gasLimit = resolveGasLimit(config.gasLimitMultiplier);
83
- const signedTxs = [];
84
- signedTxs.push(await wallet.signTransaction({
110
+ const txType = getTxType(config);
111
+ // ✅ 获取贿赂金额
112
+ const bribeAmount = getBribeAmount(config);
113
+ const needBribeTx = bribeAmount > 0n;
114
+ // ✅ 利润计算
115
+ const extractProfit = shouldExtractProfit(config);
116
+ const { profit: profitWei } = extractProfit && quotedOutput > 0n
117
+ ? calculateProfit(quotedOutput, config)
118
+ : { profit: 0n };
119
+ const needProfitTx = extractProfit && profitWei > 0n;
120
+ // ✅ 分配 nonces:贿赂 → 卖出 → 利润
121
+ let nonceIdx = 0;
122
+ const bribeNonce = needBribeTx ? currentNonce + nonceIdx++ : undefined;
123
+ const sellNonce = currentNonce + nonceIdx++;
124
+ const profitNonce = needProfitTx ? currentNonce + nonceIdx : undefined;
125
+ // ✅ 并行签名所有交易(贿赂、卖出、利润)
126
+ const signPromises = [];
127
+ // 贿赂交易
128
+ if (needBribeTx && bribeNonce !== undefined) {
129
+ signPromises.push(wallet.signTransaction({
130
+ to: BLOCKRAZOR_BUILDER_EOA,
131
+ value: bribeAmount,
132
+ nonce: bribeNonce,
133
+ gasPrice,
134
+ gasLimit: 21000n,
135
+ chainId,
136
+ type: txType
137
+ }));
138
+ }
139
+ // 卖出交易
140
+ signPromises.push(wallet.signTransaction({
85
141
  ...unsigned,
86
142
  from: wallet.address,
87
- nonce: currentNonce,
143
+ nonce: sellNonce,
88
144
  gasLimit,
89
145
  gasPrice,
90
146
  chainId,
91
- type: getTxType(config)
147
+ type: txType
92
148
  }));
93
- await appendSingleSellProfitTransfer({
94
- extractProfit: shouldExtractProfit(config),
95
- quotedOutput,
96
- wallet,
97
- baseNonce: currentNonce,
98
- gasPrice,
99
- chainId,
100
- config,
101
- signedTxs
102
- });
149
+ // 利润交易
150
+ if (needProfitTx && profitNonce !== undefined) {
151
+ signPromises.push(wallet.signTransaction({
152
+ to: getProfitRecipient(),
153
+ value: profitWei,
154
+ nonce: profitNonce,
155
+ gasPrice,
156
+ gasLimit: 21000n,
157
+ chainId,
158
+ type: txType
159
+ }));
160
+ }
161
+ // ✅ 并行签名完成后按顺序返回
162
+ const signedTxs = await Promise.all(signPromises);
103
163
  return { signedTransactions: signedTxs };
104
164
  }
105
165
  /**
@@ -121,6 +181,10 @@ export async function flapBatchPrivateBuyMerkle(params) {
121
181
  const maxFundsIndex = findMaxIndex(originalAmountsWei);
122
182
  const minOuts = resolveBatchMinOutputs(minOutputAmounts, wallets.length);
123
183
  const portals = wallets.map(w => new ethers.Contract(portalAddr, PORTAL_ABI, w));
184
+ // ✅ 获取贿赂金额
185
+ const bribeAmount = getBribeAmount(config);
186
+ const needBribeTx = bribeAmount > 0n;
187
+ const needProfitTx = extractProfit && totalProfit > 0n;
124
188
  // ✅ 并行获取 gasPrice、所有 nonces 和构建未签名交易
125
189
  const [gasPrice, initialNonces, unsignedList] = await Promise.all([
126
190
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
@@ -133,14 +197,39 @@ export async function flapBatchPrivateBuyMerkle(params) {
133
197
  permitData: '0x',
134
198
  }, { value: actualAmountsWei[i] })))
135
199
  ]);
136
- // ✅ 为需要支付利润的钱包预留额外 nonce
200
+ // ✅ 分配 nonces:贿赂(可选) → 买入 → 利润(可选)
201
+ let payerNonceOffset = 0;
202
+ let bribeNonce;
203
+ if (needBribeTx && maxFundsIndex >= 0) {
204
+ bribeNonce = initialNonces[maxFundsIndex];
205
+ payerNonceOffset++;
206
+ }
137
207
  const nonces = initialNonces.map((n, i) => {
138
- // 如果这个钱包需要支付利润,它的主交易 nonce 不变,利润交易用 nonce+1
208
+ if (i === maxFundsIndex) {
209
+ return n + payerNonceOffset; // payer 的买入 nonce 需要偏移
210
+ }
139
211
  return n;
140
212
  });
213
+ const profitNonce = needProfitTx && maxFundsIndex >= 0
214
+ ? initialNonces[maxFundsIndex] + payerNonceOffset + 1
215
+ : undefined;
141
216
  const gasLimit = resolveGasLimit(config.gasLimitMultiplier);
142
217
  const gasLimits = new Array(wallets.length).fill(gasLimit);
143
- // 并行签名所有交易
218
+ const signedTxs = [];
219
+ // ✅ 贿赂交易放在首位
220
+ if (needBribeTx && bribeNonce !== undefined && maxFundsIndex >= 0) {
221
+ const bribeTx = await wallets[maxFundsIndex].signTransaction({
222
+ to: BLOCKRAZOR_BUILDER_EOA,
223
+ value: bribeAmount,
224
+ nonce: bribeNonce,
225
+ gasPrice,
226
+ gasLimit: 21000n,
227
+ chainId,
228
+ type: getTxType(config)
229
+ });
230
+ signedTxs.push(bribeTx);
231
+ }
232
+ // ✅ 并行签名所有买入交易
144
233
  const signedList = await signBatchTransactions({
145
234
  unsignedList,
146
235
  wallets,
@@ -151,10 +240,9 @@ export async function flapBatchPrivateBuyMerkle(params) {
151
240
  config,
152
241
  values: actualAmountsWei
153
242
  });
154
- const signedTxs = [...signedList];
155
- // 添加利润交易(使用 nonce + 1)
156
- if (extractProfit && totalProfit > 0n && maxFundsIndex >= 0) {
157
- const profitNonce = initialNonces[maxFundsIndex] + 1;
243
+ signedTxs.push(...signedList);
244
+ // 利润交易放在末尾
245
+ if (needProfitTx && profitNonce !== undefined && maxFundsIndex >= 0) {
158
246
  const profitTx = await wallets[maxFundsIndex].signTransaction({
159
247
  to: getProfitRecipient(),
160
248
  value: totalProfit,
@@ -182,50 +270,75 @@ export async function flapBatchPrivateSellMerkle(params) {
182
270
  const amountsWei = amounts.map(a => ethers.parseUnits(a, 18));
183
271
  const portal = new ethers.Contract(portalAddr, PORTAL_ABI, provider);
184
272
  const portals = wallets.map(w => new ethers.Contract(portalAddr, PORTAL_ABI, w));
185
- // ✅ 并行获取 gasPrice、所有 nonces 和所有报价
186
- const [gasPrice, initialNonces, quotedOutputs] = await Promise.all([
273
+ // ✅ 并行获取 gasPrice、所有 nonces、所有报价和构建未签名交易
274
+ const [gasPrice, initialNonces, quotedOutputs, unsignedList] = await Promise.all([
187
275
  getOptimizedGasPrice(provider, getGasPriceConfig(config)),
188
276
  Promise.all(wallets.map(w => w.getNonce())),
189
277
  Promise.all(amountsWei.map(amount => portal.quoteExactInput.staticCall({
190
278
  inputToken: tokenAddress,
191
279
  outputToken: ZERO_ADDRESS,
192
280
  inputAmount: amount
193
- }).catch(() => 0n)))
281
+ }).catch(() => 0n))),
282
+ // ✅ 并行构建未签名交易(已移除滑点保护:minOuts 固定为 0)
283
+ Promise.all(portals.map((p, i) => p.swapExactInput.populateTransaction({
284
+ inputToken: tokenAddress,
285
+ outputToken: ZERO_ADDRESS,
286
+ inputAmount: amountsWei[i],
287
+ minOutputAmount: 0n,
288
+ permitData: '0x'
289
+ })))
194
290
  ]);
195
- // 计算 minOuts
196
- let minOuts;
197
- if (minOutputAmounts && minOutputAmounts.length === wallets.length) {
198
- minOuts = minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseEther(m) : m);
199
- }
200
- else {
201
- minOuts = quotedOutputs.map(quoted => quoted * 95n / 100n);
202
- }
203
- // ✅ 并行构建未签名交易
204
- const unsignedList = await Promise.all(portals.map((p, i) => p.swapExactInput.populateTransaction({
205
- inputToken: tokenAddress,
206
- outputToken: ZERO_ADDRESS,
207
- inputAmount: amountsWei[i],
208
- minOutputAmount: minOuts[i],
209
- permitData: '0x'
210
- })));
211
291
  const extractProfit = shouldExtractProfit(config);
212
292
  const { totalProfit, maxRevenueIndex } = summarizeSellProfits(quotedOutputs, extractProfit, config);
293
+ // ✅ 获取贿赂金额
294
+ const bribeAmount = getBribeAmount(config);
295
+ const needBribeTx = bribeAmount > 0n;
296
+ const needProfitTx = extractProfit && totalProfit > 0n;
297
+ // ✅ 分配 nonces:贿赂(可选) → 卖出 → 利润(可选)
298
+ let payerNonceOffset = 0;
299
+ let bribeNonce;
300
+ if (needBribeTx && maxRevenueIndex >= 0) {
301
+ bribeNonce = initialNonces[maxRevenueIndex];
302
+ payerNonceOffset++;
303
+ }
304
+ const nonces = initialNonces.map((n, i) => {
305
+ if (i === maxRevenueIndex) {
306
+ return n + payerNonceOffset; // payer 的卖出 nonce 需要偏移
307
+ }
308
+ return n;
309
+ });
310
+ const profitNonce = needProfitTx && maxRevenueIndex >= 0
311
+ ? initialNonces[maxRevenueIndex] + payerNonceOffset + 1
312
+ : undefined;
213
313
  const gasLimit = resolveGasLimit(config.gasLimitMultiplier);
214
314
  const gasLimits = new Array(wallets.length).fill(gasLimit);
315
+ const signedTxs = [];
316
+ // ✅ 贿赂交易放在首位
317
+ if (needBribeTx && bribeNonce !== undefined && maxRevenueIndex >= 0) {
318
+ const bribeTx = await wallets[maxRevenueIndex].signTransaction({
319
+ to: BLOCKRAZOR_BUILDER_EOA,
320
+ value: bribeAmount,
321
+ nonce: bribeNonce,
322
+ gasPrice,
323
+ gasLimit: 21000n,
324
+ chainId,
325
+ type: getTxType(config)
326
+ });
327
+ signedTxs.push(bribeTx);
328
+ }
215
329
  // ✅ 并行签名所有卖出交易
216
330
  const signedList = await signBatchTransactions({
217
331
  unsignedList,
218
332
  wallets,
219
- nonces: initialNonces,
333
+ nonces,
220
334
  gasLimits,
221
335
  gasPrice,
222
336
  chainId,
223
337
  config
224
338
  });
225
- const signedTxs = [...signedList];
226
- // 添加利润交易(使用 nonce + 1)
227
- if (extractProfit && totalProfit > 0n && maxRevenueIndex >= 0) {
228
- const profitNonce = initialNonces[maxRevenueIndex] + 1;
339
+ signedTxs.push(...signedList);
340
+ // 利润交易放在末尾
341
+ if (needProfitTx && profitNonce !== undefined && maxRevenueIndex >= 0) {
229
342
  const profitTx = await wallets[maxRevenueIndex].signTransaction({
230
343
  to: getProfitRecipient(),
231
344
  value: totalProfit,
@@ -315,7 +428,7 @@ async function resolveSingleSellOutputs(portal, tokenAddress, amountWei, minOutp
315
428
  });
316
429
  return {
317
430
  quotedOutput,
318
- minOut: quotedOutput * 95n / 100n
431
+ minOut: 0n // 已移除滑点保护:minOut 固定为 0
319
432
  };
320
433
  }
321
434
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.3.99",
3
+ "version": "1.4.2",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",