four-flap-meme-sdk 1.2.1 → 1.2.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.
@@ -5,6 +5,7 @@ import { ADDRESSES } from '../../utils/constants.js';
5
5
  import { FourClient, buildLoginMessage } from '../../clients/four.js';
6
6
  import { getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit } from './config.js';
7
7
  import { batchCheckAllowances } from '../../utils/erc20.js';
8
+ import { trySell } from '../tm.js';
8
9
  // ==================== TokenManager2 ABI(仅需要的方法)====================
9
10
  const TM2_ABI = [
10
11
  'function createToken(bytes args, bytes signature) payable',
@@ -322,24 +323,34 @@ export async function batchSellWithBundleMerkle(params) {
322
323
  const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
323
324
  const sellers = privateKeys.map((k) => new Wallet(k, provider));
324
325
  const amountsWei = sellAmounts.map((a) => ethers.parseUnits(a, 18));
325
- // ⚠️ Four.meme 内盘代币通过 TokenManager bonding curve 定价,不在 PancakeSwap 上
326
+ // ⚠️ Four.meme 内盘代币通过 TokenManager bonding curve 定价
327
+ // ✅ 优先使用用户提供的 minOutputAmounts,否则自动调用 trySell 获取
326
328
  let minOuts;
327
329
  let quotedOutputs = [];
328
330
  if (minOutputAmounts && minOutputAmounts.length === sellers.length) {
329
331
  // 用户提供了 minOutputAmounts,用于滑点保护和利润计算
330
332
  minOuts = minOutputAmounts.map(m => typeof m === 'string' ? ethers.parseEther(m) : m);
331
- // 反推实际收益(假设 minOut 是 95% 的收益)
332
333
  quotedOutputs = minOuts.map(m => m * 100n / 95n);
333
334
  }
334
335
  else {
335
- // 默认 minOutputAmount = 0(不限制最小输出,不提取利润)
336
- minOuts = new Array(sellers.length).fill(0n);
337
- quotedOutputs = new Array(sellers.length).fill(0n);
338
- // ⚠️ 友好提示
339
- if (shouldExtractProfit(config)) {
340
- console.log('\n⚠️ 提示:未传入 minOutputAmounts,将无法提取利润');
341
- console.log(' 请在 four.meme 网站查看预期收益,然后传入 minOutputAmounts 参数\n');
342
- }
336
+ // 自动调用 trySell 获取每个钱包的预期收益
337
+ console.log('💰 自动获取卖出报价...');
338
+ const rpcUrl = config.customRpcUrl;
339
+ quotedOutputs = await Promise.all(amountsWei.map(async (amount, i) => {
340
+ try {
341
+ const result = await trySell('BSC', rpcUrl, tokenAddress, amount);
342
+ const quoted = result.funds; // 预期收益
343
+ console.log(` 钱包 ${i}: 卖出 ${ethers.formatUnits(amount, 18)} 代币 → 预期收益 ${ethers.formatEther(quoted)} BNB`);
344
+ return quoted;
345
+ }
346
+ catch (error) {
347
+ console.log(` ⚠️ 钱包 ${i}: 报价失败,使用 minOut = 0`);
348
+ return 0n;
349
+ }
350
+ }));
351
+ // minOuts 设为预期收益的 95%(作为滑点保护)
352
+ minOuts = quotedOutputs.map(q => q * 95n / 100n);
353
+ console.log('');
343
354
  }
344
355
  // ✅ Step 1: 检查代币余额和授权状态
345
356
  const ERC20_ABI = [
@@ -4,6 +4,7 @@ import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.j
4
4
  import { ADDRESSES } from '../../utils/constants.js';
5
5
  import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, calculateBatchProfit } from './config.js';
6
6
  import { batchCheckAllowances } from '../../utils/erc20.js';
7
+ import { trySell } from '../tm.js';
7
8
  // ==================== TokenManager2 ABI(仅需要的方法)====================
8
9
  const TM2_ABI = [
9
10
  'function buyTokenAMAP(uint256 origin, address token, address to, uint256 funds, uint256 minAmount) payable',
@@ -229,16 +230,6 @@ export async function fourBatchPrivateSellMerkle(params) {
229
230
  if (privateKeys.length !== amounts.length) {
230
231
  throw new Error('privateKeys and amounts length mismatch');
231
232
  }
232
- // ⚠️ 友好提示:利润提取需要 minFundsEach
233
- if (!minFundsEach && shouldExtractProfit(config)) {
234
- console.log('\n⚠️ 重要提示:未传入 minFundsEach 参数,将无法提取利润!');
235
- console.log(' Four.meme 内盘代币无法自动报价,需要手动估算预期收益');
236
- console.log(' 建议步骤:');
237
- console.log(' 1. 在 four.meme 网站查看卖出预期收益');
238
- console.log(' 2. 传入 minFundsEach 参数');
239
- console.log(' 示例: minFundsEach: 0.1 (预计每个钱包收到 0.1 BNB)');
240
- console.log(' 如果只是测试卖出,可以忽略此提示\n');
241
- }
242
233
  const merkle = new MerkleClient({
243
234
  apiKey: config.apiKey,
244
235
  chainId: 56,
@@ -248,12 +239,40 @@ export async function fourBatchPrivateSellMerkle(params) {
248
239
  const tmAddr = ADDRESSES.BSC.TokenManagerOriginal;
249
240
  const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
250
241
  const gasMultiplier = config.gasLimitMultiplier ?? 1.0;
251
- const minOut = minFundsEach ?? 0n;
252
242
  const sellGasLimit = BigInt(Math.ceil(800000 * gasMultiplier));
253
243
  const signedTxs = [];
254
244
  const nonceManager = new NonceManager(provider);
255
245
  const wallets = privateKeys.map((k) => new Wallet(k, provider));
256
246
  const amountsWei = amounts.map((a) => ethers.parseUnits(a, 18));
247
+ // ✅ 自动获取每个钱包的预期收益(用于利润计算和滑点保护)
248
+ let quotedOutputs;
249
+ let minOuts;
250
+ if (minFundsEach !== undefined) {
251
+ // 用户提供了 minFundsEach,所有钱包使用相同的 minOut
252
+ const minOutWei = typeof minFundsEach === 'string' ? ethers.parseEther(minFundsEach) : minFundsEach;
253
+ minOuts = new Array(wallets.length).fill(minOutWei);
254
+ quotedOutputs = minOuts.map(m => m * 100n / 95n);
255
+ }
256
+ else {
257
+ // ✅ 自动调用 trySell 获取每个钱包的预期收益
258
+ console.log('💰 自动获取卖出报价...');
259
+ const rpcUrl = config.customRpcUrl;
260
+ quotedOutputs = await Promise.all(amountsWei.map(async (amount, i) => {
261
+ try {
262
+ const result = await trySell('BSC', rpcUrl, tokenAddress, amount);
263
+ const quoted = result.funds;
264
+ console.log(` 钱包 ${i}: 卖出 ${ethers.formatUnits(amount, 18)} 代币 → 预期收益 ${ethers.formatEther(quoted)} BNB`);
265
+ return quoted;
266
+ }
267
+ catch (error) {
268
+ console.log(` ⚠️ 钱包 ${i}: 报价失败,使用 minOut = 0`);
269
+ return 0n;
270
+ }
271
+ }));
272
+ // minOuts 设为预期收益的 95%(作为滑点保护)
273
+ minOuts = quotedOutputs.map(q => q * 95n / 100n);
274
+ console.log('');
275
+ }
257
276
  // ✅ Step 0: 检查代币余额
258
277
  const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
259
278
  const balances = await Promise.all(wallets.map(w => tokenContract.balanceOf(w.address)));
@@ -288,7 +307,7 @@ export async function fourBatchPrivateSellMerkle(params) {
288
307
  }
289
308
  // ✅ Step 3: 构建卖出交易
290
309
  const tm2Contracts = wallets.map((w) => new ethers.Contract(tmAddr, TM2_ABI, w));
291
- const sellUnsigned = await Promise.all(tm2Contracts.map((c, i) => c.sellToken.populateTransaction(0n, tokenAddress, amountsWei[i], minOut)));
310
+ const sellUnsigned = await Promise.all(tm2Contracts.map((c, i) => c.sellToken.populateTransaction(0n, tokenAddress, amountsWei[i], minOuts[i])));
292
311
  const sellGasLimits = new Array(wallets.length).fill(sellGasLimit);
293
312
  const sellNonces = await Promise.all(wallets.map((w) => nonceManager.getNextNonce(w)));
294
313
  const signedSells = await Promise.all(sellUnsigned.map((unsigned, i) => wallets[i].signTransaction({
@@ -301,22 +320,26 @@ export async function fourBatchPrivateSellMerkle(params) {
301
320
  type: getTxType(config)
302
321
  })));
303
322
  signedTxs.push(...signedSells);
304
- // ✅ 提取利润
323
+ // ✅ 提取利润(基于每个钱包的预期收益)
305
324
  const extractProfit = shouldExtractProfit(config);
306
- if (extractProfit && minOut > 0n) {
307
- const { profit } = calculateProfit(minOut, config);
308
- if (profit > 0n) {
309
- const profitNonces = await Promise.all(wallets.map(w => nonceManager.getNextNonce(w)));
310
- const profitTxs = await Promise.all(wallets.map((wallet, i) => wallet.signTransaction({
311
- to: config.profitRecipient,
312
- value: profit,
313
- nonce: profitNonces[i],
314
- gasPrice,
315
- gasLimit: 21000n,
316
- chainId: 56,
317
- type: getTxType(config)
318
- })));
319
- signedTxs.push(...profitTxs);
325
+ if (extractProfit) {
326
+ for (let i = 0; i < wallets.length; i++) {
327
+ if (quotedOutputs[i] > 0n) {
328
+ const { profit } = calculateProfit(quotedOutputs[i], config);
329
+ if (profit > 0n) {
330
+ const profitNonce = await nonceManager.getNextNonce(wallets[i]);
331
+ const profitTx = await wallets[i].signTransaction({
332
+ to: config.profitRecipient,
333
+ value: profit,
334
+ nonce: profitNonce,
335
+ gasPrice,
336
+ gasLimit: 21000n,
337
+ chainId: 56,
338
+ type: getTxType(config)
339
+ });
340
+ signedTxs.push(profitTx);
341
+ }
342
+ }
320
343
  }
321
344
  }
322
345
  nonceManager.clearTemp();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.2.01",
3
+ "version": "1.2.2",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",