four-flap-meme-sdk 1.1.90 → 1.1.91

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.
@@ -0,0 +1,21 @@
1
+ export type ApproveFourTokenManagerBatchParams = {
2
+ privateKeys: string[];
3
+ tokenAddress: string;
4
+ amounts: string[];
5
+ config: {
6
+ apiKey: string;
7
+ customRpcUrl?: string;
8
+ gasLimit?: number | bigint;
9
+ gasLimitMultiplier?: number;
10
+ txType?: 0 | 2;
11
+ };
12
+ };
13
+ export type ApproveFourTokenManagerBatchResult = {
14
+ signedTransactions: string[];
15
+ };
16
+ /**
17
+ * 批量授权代币给 TokenManager(用于 Private Buy/Sell)
18
+ * ✅ 专门用于授权给 TokenManagerOriginal 合约
19
+ * ✅ 用于 fourBatchPrivateSell 和 fourBatchSellWithBundleMerkle
20
+ */
21
+ export declare function approveFourTokenManagerBatch(params: ApproveFourTokenManagerBatchParams): Promise<ApproveFourTokenManagerBatchResult>;
@@ -0,0 +1,77 @@
1
+ import { ethers, Wallet } from 'ethers';
2
+ import { MerkleClient } from '../../clients/merkle.js';
3
+ import { NonceManager, getOptimizedGasPrice } from '../../utils/bundle-helpers.js';
4
+ import { ADDRESSES } from '../../utils/constants.js';
5
+ import { getTxType, getGasPriceConfig } from './config.js';
6
+ // ==================== ERC20 ABI ====================
7
+ const ERC20_ABI = [
8
+ 'function approve(address spender, uint256 amount) returns (bool)',
9
+ 'function allowance(address owner, address spender) view returns (uint256)',
10
+ 'function decimals() view returns (uint8)'
11
+ ];
12
+ /**
13
+ * 批量授权代币给 TokenManager(用于 Private Buy/Sell)
14
+ * ✅ 专门用于授权给 TokenManagerOriginal 合约
15
+ * ✅ 用于 fourBatchPrivateSell 和 fourBatchSellWithBundleMerkle
16
+ */
17
+ export async function approveFourTokenManagerBatch(params) {
18
+ const { privateKeys, tokenAddress, amounts, config } = params;
19
+ if (privateKeys.length === 0 || amounts.length !== privateKeys.length) {
20
+ throw new Error('Private key count and amount count must match');
21
+ }
22
+ const tmAddr = ADDRESSES.BSC.TokenManagerOriginal;
23
+ const merkle = new MerkleClient({
24
+ apiKey: config.apiKey,
25
+ chainId: 56,
26
+ customRpcUrl: config.customRpcUrl
27
+ });
28
+ const provider = merkle.getProvider();
29
+ const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
30
+ // 查询 decimals
31
+ const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
32
+ const decimals = await tokenContract.decimals();
33
+ const wallets = privateKeys.map(k => new Wallet(k, provider));
34
+ const amountsBigInt = amounts.map(a => a === 'max' ? ethers.MaxUint256 : ethers.parseUnits(a, decimals));
35
+ // 检查现有授权,过滤掉已经足够的
36
+ const { batchCheckAllowances } = await import('../../utils/erc20.js');
37
+ const allowances = await batchCheckAllowances(provider, tokenAddress, wallets.map(w => w.address), tmAddr);
38
+ // 只授权不足的
39
+ const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
40
+ const needApproval = wallets.filter((_, i) => allowances[i] < APPROVAL_THRESHOLD);
41
+ const needApprovalAmounts = amountsBigInt.filter((_, i) => allowances[i] < APPROVAL_THRESHOLD);
42
+ console.log(`🔍 TokenManager 授权检查:`);
43
+ console.log(` - 总钱包数: ${wallets.length}`);
44
+ console.log(` - 需要授权: ${needApproval.length}`);
45
+ console.log(` - 已有授权: ${wallets.length - needApproval.length}`);
46
+ if (needApproval.length === 0) {
47
+ // 全部已授权,直接返回
48
+ console.log(`✅ 所有钱包已授权给 TokenManager`);
49
+ return {
50
+ signedTransactions: []
51
+ };
52
+ }
53
+ // 构建授权交易
54
+ const needApprovalTokens = needApproval.map(w => new ethers.Contract(tokenAddress, ERC20_ABI, w));
55
+ const unsignedApprovals = await Promise.all(needApprovalTokens.map((token, i) => token.approve.populateTransaction(tmAddr, needApprovalAmounts[i])));
56
+ // ✅ 使用前端传入的 gasLimit,否则使用默认值
57
+ const gasMultiplier = config.gasLimitMultiplier ?? 1.0;
58
+ const finalGasLimit = config.gasLimit ?? BigInt(Math.ceil(50000 * gasMultiplier));
59
+ // ✅ 直接签名交易(不提交到Merkle)
60
+ const nonceManager = new NonceManager(provider);
61
+ const nonces = await Promise.all(needApproval.map(w => nonceManager.getNextNonce(w)));
62
+ const signedTxs = await Promise.all(unsignedApprovals.map((unsigned, i) => needApproval[i].signTransaction({
63
+ ...unsigned,
64
+ from: needApproval[i].address,
65
+ nonce: nonces[i],
66
+ gasLimit: finalGasLimit,
67
+ gasPrice,
68
+ chainId: 56,
69
+ type: getTxType(config)
70
+ })));
71
+ nonceManager.clearTemp();
72
+ console.log(`✅ 已生成 ${signedTxs.length} 个授权交易签名`);
73
+ // ✅ 简化返回:只返回签名交易
74
+ return {
75
+ signedTransactions: signedTxs
76
+ };
77
+ }
@@ -8,4 +8,5 @@ export { createTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle, batchSellWith
8
8
  export { fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle } from './private.js';
9
9
  export { disperseWithBundleMerkle, sweepWithBundleMerkle } from './utils.js';
10
10
  export { fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch } from './pancake-proxy.js';
11
+ export { approveFourTokenManagerBatch, type ApproveFourTokenManagerBatchParams, type ApproveFourTokenManagerBatchResult } from './approve-tokenmanager.js';
11
12
  export { submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type SubmitBundleResult } from './submit.js';
@@ -13,5 +13,7 @@ export { fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle,
13
13
  export { disperseWithBundleMerkle, sweepWithBundleMerkle } from './utils.js';
14
14
  // PancakeSwapProxy 代理交易方法
15
15
  export { fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch } from './pancake-proxy.js';
16
+ // TokenManager 授权方法
17
+ export { approveFourTokenManagerBatch } from './approve-tokenmanager.js';
16
18
  // Bundle提交方法(服务器端使用)
17
19
  export { submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel } from './submit.js';
@@ -8,6 +8,12 @@ const TM2_ABI = [
8
8
  'function buyTokenAMAP(uint256 origin, address token, address to, uint256 funds, uint256 minAmount) payable',
9
9
  'function sellToken(uint256 origin, address token, uint256 amount, uint256 minFunds)'
10
10
  ];
11
+ // ==================== ERC20 ABI ====================
12
+ const ERC20_ABI = [
13
+ 'function approve(address spender, uint256 amount) returns (bool)',
14
+ 'function allowance(address owner, address spender) view returns (uint256)',
15
+ 'function decimals() view returns (uint8)'
16
+ ];
11
17
  /**
12
18
  * 私有购买(单笔)(Merkle 版本)
13
19
  */
@@ -91,10 +97,6 @@ export async function fourPrivateSellMerkle(params) {
91
97
  const amountWei = ethers.parseUnits(amount, 18);
92
98
  const minOut = minFunds ?? 0n;
93
99
  // ✅ Step 1: 检查授权状态
94
- const ERC20_ABI = [
95
- 'function approve(address spender, uint256 amount) returns (bool)',
96
- 'function allowance(address owner, address spender) view returns (uint256)'
97
- ];
98
100
  const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
99
101
  const currentAllowance = await tokenContract.allowance(wallet.address, tmAddr);
100
102
  // 使用 MaxUint256 的一半作为阈值,确保能处理超大供应量代币
@@ -241,7 +243,6 @@ export async function fourBatchPrivateSellMerkle(params) {
241
243
  const wallets = privateKeys.map((k) => new Wallet(k, provider));
242
244
  const amountsWei = amounts.map((a) => ethers.parseUnits(a, 18));
243
245
  // ✅ Step 1: 使用 Multicall3 批量检查授权状态
244
- const ERC20_ABI = ['function approve(address spender, uint256 amount) returns (bool)'];
245
246
  console.log('🔍 使用 Multicall3 批量检查授权状态...');
246
247
  const { batchCheckAllowances } = await import('../../utils/erc20.js');
247
248
  const allowances = await batchCheckAllowances(provider, tokenAddress, wallets.map(w => w.address), tmAddr);
@@ -282,7 +282,7 @@ export async function batchSellWithBundleMerkle(params) {
282
282
  // ✅ 自动获取报价以计算预期收益和利润
283
283
  const portal = new ethers.Contract(portalAddr, PORTAL_ABI, provider);
284
284
  // 并行获取所有报价
285
- const quotedOutputs = await Promise.all(amountsWei.map(async (amount, index) => {
285
+ const quotedOutputs = await Promise.all(amountsWei.map(async (amount) => {
286
286
  try {
287
287
  // ✅ 使用 staticCall 调用 view 函数
288
288
  const quoted = await portal.quoteExactInput.staticCall({
@@ -290,11 +290,9 @@ export async function batchSellWithBundleMerkle(params) {
290
290
  outputToken: '0x0000000000000000000000000000000000000000',
291
291
  inputAmount: amount
292
292
  });
293
- console.log(`📊 卖出报价 [${index}]: ${ethers.formatEther(amount)} 代币 → ${ethers.formatEther(quoted)} BNB`);
294
293
  return quoted;
295
294
  }
296
295
  catch (error) {
297
- console.warn(`⚠️ 报价失败 [${index}]:`, error);
298
296
  return 0n;
299
297
  }
300
298
  }));
@@ -332,15 +330,11 @@ export async function batchSellWithBundleMerkle(params) {
332
330
  signedTxs.push(...signedList);
333
331
  // ✅ 基于报价金额为每个钱包添加利润转账
334
332
  const extractProfit = shouldExtractProfit(config);
335
- console.log(`\n💰 利润提取配置: extractProfit=${extractProfit}, profitRecipient=${config.profitRecipient}, quotedOutputs.length=${quotedOutputs.length}`);
336
333
  if (extractProfit && quotedOutputs.length > 0) {
337
- let totalProfitAdded = 0;
338
334
  // 为每个钱包添加利润转账(基于完整报价金额,而非 minOut)
339
335
  for (let i = 0; i < wallets.length; i++) {
340
- console.log(`\n🔍 钱包 [${i}]: quotedOutput=${ethers.formatEther(quotedOutputs[i])} BNB`);
341
336
  if (quotedOutputs[i] > 0n) { // 只对报价成功的交易提取利润
342
337
  const { profit } = calculateProfit(quotedOutputs[i], config);
343
- console.log(` 💵 计算利润: ${ethers.formatEther(profit)} BNB (${config.profitRateBps || 30} bps)`);
344
338
  if (profit > 0n) {
345
339
  const profitNonce = await nonceManager.getNextNonce(wallets[i]);
346
340
  const profitTx = await wallets[i].signTransaction({
@@ -353,19 +347,8 @@ export async function batchSellWithBundleMerkle(params) {
353
347
  type: getTxType(config)
354
348
  });
355
349
  signedTxs.push(profitTx);
356
- totalProfitAdded++;
357
- console.log(` ✅ 已添加利润转账 (nonce: ${profitNonce})`);
358
350
  }
359
351
  }
360
- else {
361
- console.log(` ⚠️ 跳过:报价为 0`);
362
- }
363
- }
364
- console.log(`\n📊 总共添加了 ${totalProfitAdded} 个利润转账\n`);
365
- }
366
- else {
367
- if (!extractProfit) {
368
- console.log(`⚠️ 未提取利润:profitRecipient=${config.profitRecipient}, profitRateBps=${config.profitRateBps}\n`);
369
352
  }
370
353
  }
371
354
  // ✅ 清理临时 nonce 缓存
package/dist/index.d.ts CHANGED
@@ -26,7 +26,7 @@ export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithB
26
26
  export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell, type FourPrivateBuyParams, type FourPrivateSellParams, type FourBatchPrivateBuyParams, type FourBatchPrivateSellParams } from './contracts/tm-bundle.js';
27
27
  export { flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell, type FlapPrivateBuyParams, type FlapPrivateSellParams, type FlapBatchPrivateBuyParams, type FlapBatchPrivateSellParams, type FlapBatchPrivateSellResult } from './flap/portal-bundle.js';
28
28
  export { createTokenWithBundleBuyMerkle as flapCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as flapBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as flapBatchSellWithBundleMerkle, flapPrivateBuyMerkle, flapPrivateSellMerkle, flapBatchPrivateBuyMerkle, flapBatchPrivateSellMerkle, pancakeProxyBatchBuyMerkle, pancakeProxyBatchSellMerkle, approvePancakeProxy, approvePancakeProxyBatch, type FlapBundleMerkleConfig, type FlapChainForMerkleBundle, type FlapCreateWithBundleBuyMerkleParams, type FlapCreateWithBundleBuyMerkleResult, type FlapBatchBuyMerkleParams, type FlapBatchBuyMerkleResult, type FlapBatchSellMerkleParams, type FlapBatchSellMerkleResult, type MerkleTransactionStatus, type MerkleBundleStatus, type FlapPrivateBuyMerkleParams, type FlapPrivateSellMerkleParams, type FlapBatchPrivateBuyMerkleParams, type FlapBatchPrivateSellMerkleParams, type FlapBatchPrivateMerkleResult, type FlapPrivateTransactionResult, type PancakeProxyBatchBuyParams, type PancakeProxyBatchBuyResult, type PancakeProxyBatchSellParams, type PancakeProxyBatchSellResult, type PancakeProxyApprovalParams, type PancakeProxyApprovalBatchParams, type PancakeProxyApprovalBatchResult } from './flap/portal-bundle-merkle/index.js';
29
- export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type SubmitBundleResult, type FourBundleMerkleConfig, type FourCreateWithBundleBuyMerkleParams, type FourCreateWithBundleBuyMerkleResult, type FourBatchBuyMerkleParams, type FourBatchBuyMerkleResult, type FourBatchSellMerkleParams, type FourBatchSellMerkleResult, type FourPrivateBuyMerkleParams, type FourPrivateSellMerkleParams, type FourBatchPrivateBuyMerkleParams, type FourBatchPrivateSellMerkleParams, type FourBatchPrivateMerkleResult, type FourPrivateTransactionResult, type DisperseMerkleParams, type DisperseMerkleResult, type SweepMerkleParams, type SweepMerkleResult, type FourPancakeProxyBatchBuyParams, type FourPancakeProxyBatchBuyResult, type FourPancakeProxyBatchSellParams, type FourPancakeProxyBatchSellResult, type FourPancakeProxyApprovalParams, type FourPancakeProxyApprovalBatchParams, type FourPancakeProxyApprovalBatchResult } from './contracts/tm-bundle-merkle/index.js';
29
+ export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, approveFourTokenManagerBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel, type SubmitBundleResult, type FourBundleMerkleConfig, type FourCreateWithBundleBuyMerkleParams, type FourCreateWithBundleBuyMerkleResult, type FourBatchBuyMerkleParams, type FourBatchBuyMerkleResult, type FourBatchSellMerkleParams, type FourBatchSellMerkleResult, type FourPrivateBuyMerkleParams, type FourPrivateSellMerkleParams, type FourBatchPrivateBuyMerkleParams, type FourBatchPrivateSellMerkleParams, type FourBatchPrivateMerkleResult, type FourPrivateTransactionResult, type DisperseMerkleParams, type DisperseMerkleResult, type SweepMerkleParams, type SweepMerkleResult, type FourPancakeProxyBatchBuyParams, type FourPancakeProxyBatchBuyResult, type FourPancakeProxyBatchSellParams, type FourPancakeProxyBatchSellResult, type FourPancakeProxyApprovalParams, type FourPancakeProxyApprovalBatchParams, type FourPancakeProxyApprovalBatchResult, type ApproveFourTokenManagerBatchParams, type ApproveFourTokenManagerBatchResult } from './contracts/tm-bundle-merkle/index.js';
30
30
  export { PinataClient, type PinataConfig } from './flap/pinata.js';
31
31
  export { pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob, type PinataPinResp } from './flap/pinata.js';
32
32
  export { generateWallets, type GeneratedWallet } from './utils/wallet.js';
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ export { createTokenWithBundleBuy as flapCreateTokenWithBundleBuy, batchBuyWithB
34
34
  export { fourPrivateBuy, fourPrivateSell, fourBatchPrivateBuy, fourBatchPrivateSell } from './contracts/tm-bundle.js';
35
35
  export { flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell } from './flap/portal-bundle.js';
36
36
  export { createTokenWithBundleBuyMerkle as flapCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as flapBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as flapBatchSellWithBundleMerkle, flapPrivateBuyMerkle, flapPrivateSellMerkle, flapBatchPrivateBuyMerkle, flapBatchPrivateSellMerkle, pancakeProxyBatchBuyMerkle, pancakeProxyBatchSellMerkle, approvePancakeProxy, approvePancakeProxyBatch } from './flap/portal-bundle-merkle/index.js';
37
- export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel } from './contracts/tm-bundle-merkle/index.js';
37
+ export { createTokenWithBundleBuyMerkle as fourCreateTokenWithBundleBuyMerkle, batchBuyWithBundleMerkle as fourBatchBuyWithBundleMerkle, batchSellWithBundleMerkle as fourBatchSellWithBundleMerkle, fourPrivateBuyMerkle, fourPrivateSellMerkle, fourBatchPrivateBuyMerkle, fourBatchPrivateSellMerkle, disperseWithBundleMerkle, sweepWithBundleMerkle, fourPancakeProxyBatchBuyMerkle, fourPancakeProxyBatchSellMerkle, approveFourPancakeProxy, approveFourPancakeProxyBatch, approveFourTokenManagerBatch, submitBundleToMerkle, submitMultipleBundles, submitMultipleBundlesParallel } from './contracts/tm-bundle-merkle/index.js';
38
38
  export { PinataClient } from './flap/pinata.js';
39
39
  export { pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob } from './flap/pinata.js';
40
40
  export { generateWallets } from './utils/wallet.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.1.90",
3
+ "version": "1.1.91",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",