four-flap-meme-sdk 2.1.0 → 2.2.1

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.
Files changed (40) hide show
  1. package/dist/__tests__/subpath-exports.test.js +30 -0
  2. package/dist/bundle-core/config-helpers.d.ts +5 -5
  3. package/dist/bundle-core/errors.js +2 -1
  4. package/dist/chains/bsc/iro.d.ts +5 -0
  5. package/dist/chains/bsc/iro.js +4 -0
  6. package/dist/chains/bsc/pancake/bundle-swap-helpers.d.ts +1 -1
  7. package/dist/chains/bsc/platforms/iro/factory.d.ts +2 -2
  8. package/dist/chains/eni/bundler/sign.js +1 -2
  9. package/dist/chains/eni/flat-aliases.d.ts +10 -0
  10. package/dist/chains/eni/flat-aliases.js +8 -0
  11. package/dist/chains/eni/index.d.ts +1 -0
  12. package/dist/chains/eni/index.js +1 -0
  13. package/dist/chains/eni/platforms/daoaas/meta.js +2 -3
  14. package/dist/chains/eni/platforms/iro/factory.d.ts +2 -2
  15. package/dist/chains/xlayer/eip7702/bundle-sell.js +3 -14
  16. package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
  17. package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
  18. package/dist/chains/xlayer/eip7702/index.d.ts +1 -2
  19. package/dist/chains/xlayer/eip7702/index.js +1 -0
  20. package/dist/chains/xlayer/eip7702/multi-hop-transfer-helpers.d.ts +1 -1
  21. package/dist/chains/xlayer/eip7702/multi-hop-transfer.js +13 -14
  22. package/dist/chains/xlayer/eip7702/volume.js +10 -10
  23. package/dist/chains/xlayer/index.d.ts +3 -2
  24. package/dist/chains/xlayer/index.js +4 -7
  25. package/dist/merkle/index.d.ts +12 -0
  26. package/dist/merkle/index.js +11 -0
  27. package/dist/shared/clients/four.d.ts +21 -6
  28. package/dist/shared/clients/four.js +8 -7
  29. package/dist/shared/flap/meta.d.ts +7 -1
  30. package/dist/shared/flap/pinata.d.ts +12 -3
  31. package/dist/shared/flap/pinata.js +9 -19
  32. package/dist/shared/flap/portal-bundle-merkle/create-to-dex.d.ts +2 -1
  33. package/dist/shared/foundation/gas/bundle-gas.d.ts +11 -1
  34. package/dist/shared/foundation/nonce/nonce-manager.js +4 -1
  35. package/dist/utils/airdrop-sweep.js +2 -1
  36. package/dist/utils/swap-helpers.js +1 -1
  37. package/dist/utils/wallet.js +4 -2
  38. package/dist/vanity/index.d.ts +5 -0
  39. package/dist/vanity/index.js +5 -0
  40. package/package.json +29 -2
@@ -31,4 +31,34 @@ describe('subpath exports (package.json exports map)', () => {
31
31
  expect(typeof mod.quoteV2).toBe('function');
32
32
  expect(typeof mod.quoteV3).toBe('function');
33
33
  });
34
+ it('merkle subpath exports Four Merkle swap and disperse', async () => {
35
+ const mod = await import('../merkle/index.js');
36
+ expect(typeof mod.disperseWithBundleMerkle).toBe('function');
37
+ expect(typeof mod.fourBundleSwapMerkle).toBe('function');
38
+ expect(typeof mod.submitBundleToMerkle).toBe('function');
39
+ });
40
+ it('vanity subpath exports findSaltEndingByChain', async () => {
41
+ const mod = await import('../vanity/index.js');
42
+ expect(typeof mod.findSaltEndingByChain).toBe('function');
43
+ expect(typeof mod.getVanitySuffix).toBe('function');
44
+ });
45
+ it('chains/bsc/iro subpath exports bscIroCreateProject', async () => {
46
+ const mod = await import('../chains/bsc/iro.js');
47
+ expect(typeof mod.bscIroCreateProject).toBe('function');
48
+ });
49
+ it('chains/eni flat aliases on eni subpath', async () => {
50
+ const mod = await import('../chains/eni/index.js');
51
+ expect(typeof mod.eniCreatePortalQuery).toBe('function');
52
+ expect(typeof mod.eniDisperseForSubmit).toBe('function');
53
+ });
54
+ it('chains/xlayer/eip7702 flat aliases', async () => {
55
+ const mod = await import('../chains/xlayer/eip7702/index.js');
56
+ expect(typeof mod.xlayerEip7702BundleSwap).toBe('function');
57
+ expect(typeof mod.xlayerEip7702CheckApprovalStatus).toBe('function');
58
+ });
59
+ it('chains/xlayer re-exports eip7702 flat aliases', async () => {
60
+ const mod = await import('../chains/xlayer/index.js');
61
+ expect(typeof mod.xlayerEip7702Disperse).toBe('function');
62
+ expect(mod.XLayer).toBeDefined();
63
+ });
34
64
  });
@@ -22,14 +22,14 @@ export declare function getBundleOptions(config: BundleMerkleConfigInput, blockO
22
22
  maxRetries: number;
23
23
  };
24
24
  export declare function getGasPriceConfig(config: BundleGasConfigInput): GasPriceConfig;
25
- export declare function shouldExtractProfit(_config?: unknown): boolean;
26
- export declare function getProfitRateBps(_config?: unknown): number;
27
- export declare function getProfitRecipient(_config?: unknown): string;
28
- export declare function calculateProfit(amount: bigint, _config?: unknown): {
25
+ export declare function shouldExtractProfit(_config?: BundleMerkleConfigInput): boolean;
26
+ export declare function getProfitRateBps(_config?: BundleMerkleConfigInput): number;
27
+ export declare function getProfitRecipient(_config?: BundleMerkleConfigInput): string;
28
+ export declare function calculateProfit(amount: bigint, _config?: BundleMerkleConfigInput): {
29
29
  profit: bigint;
30
30
  remaining: bigint;
31
31
  };
32
- export declare function calculateBatchProfit(amounts: bigint[], _config?: unknown): {
32
+ export declare function calculateBatchProfit(amounts: bigint[], _config?: BundleMerkleConfigInput): {
33
33
  totalProfit: bigint;
34
34
  remainingAmounts: bigint[];
35
35
  };
@@ -26,7 +26,8 @@ export function getBundleErrorMessage(key, ...args) {
26
26
  const lang = (process.env.LANG || process.env.LANGUAGE || 'en').toLowerCase().includes('zh') ? 'zh' : 'en';
27
27
  const message = BUNDLE_ERRORS[key][lang];
28
28
  if (typeof message === 'function') {
29
- return message(...args);
29
+ const [a, b] = args;
30
+ return message(a, b);
30
31
  }
31
32
  return message;
32
33
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * BSC IRO 平台子路径(与包根 `bscIro*` 扁平别名一致)
3
+ */
4
+ export { IroFactoryQuery as BscIroFactoryQuery, createProject as bscIroCreateProject, encodeCreateProjectCall as bscIroEncodeCreateProjectCall, parseCreateProjectEvent as bscIroParseCreateProjectEvent, IroTokenQuery as BscIroTokenQuery, subscribe as bscIroSubscribe, pledge as bscIroPledge, batchSubscribe as bscIroBatchSubscribe, batchSubscribeForSubmit as bscIroBatchSubscribeForSubmit, IroPoolQuery as BscIroPoolQuery, poolRemovePledge as bscIroPoolRemovePledge, poolExtract as bscIroPoolExtract, poolTransferAwards as bscIroPoolTransferAwards, batchExtract as bscIroBatchExtract, IRO_FACTORY_ADDRESS as BSC_IRO_FACTORY_ADDRESS, IRO_FACTORY_ABI as BSC_IRO_FACTORY_ABI, IRO_TOKEN_ABI as BSC_IRO_TOKEN_ABI, IRO_POOL_ABI as BSC_IRO_POOL_ABI, IRO_PLATFORM_URL as BSC_IRO_PLATFORM_URL, IRO_TESTNET_PLATFORM_URL as BSC_IRO_TESTNET_PLATFORM_URL, setIroApiBase as setBscIroApiBase, setIroTestApiBase as setBscIroTestApiBase, iroApiCreateProject as bscIroApiCreateProject, iroApiUploadImage as bscIroApiUploadImage, } from './platforms/iro/index.js';
5
+ export type { WhiteListQuota as BscIroWhiteListQuota, IroCreateProjectParams as BscIroCreateProjectParams, IroFactoryTokenInfo as BscIroFactoryTokenInfo, IroSubscribeParams as BscIroSubscribeParams, IroPledgeParams as BscIroPledgeParams, IroTokenPrice as BscIroTokenPrice, IroPoolRemovePledgeParams as BscIroPoolRemovePledgeParams, IroPoolExtractParams as BscIroPoolExtractParams, IroPoolTransferAwardsParams as BscIroPoolTransferAwardsParams, IroTokenInfo as BscIroTokenInfo, IroTxResult as BscIroTxResult, IroCreateProjectResult as BscIroCreateProjectResult, IroQueryConfig as BscIroQueryConfig, IroCreateParams as BscIroCreateParams, IroApiCreateProjectRequest as BscIroApiCreateProjectRequest, IroBatchSubscribeForSubmitParams as BscIroBatchSubscribeForSubmitParams, IroBatchSubscribeForSubmitResult as BscIroBatchSubscribeForSubmitResult, } from './platforms/iro/index.js';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * BSC IRO 平台子路径(与包根 `bscIro*` 扁平别名一致)
3
+ */
4
+ export { IroFactoryQuery as BscIroFactoryQuery, createProject as bscIroCreateProject, encodeCreateProjectCall as bscIroEncodeCreateProjectCall, parseCreateProjectEvent as bscIroParseCreateProjectEvent, IroTokenQuery as BscIroTokenQuery, subscribe as bscIroSubscribe, pledge as bscIroPledge, batchSubscribe as bscIroBatchSubscribe, batchSubscribeForSubmit as bscIroBatchSubscribeForSubmit, IroPoolQuery as BscIroPoolQuery, poolRemovePledge as bscIroPoolRemovePledge, poolExtract as bscIroPoolExtract, poolTransferAwards as bscIroPoolTransferAwards, batchExtract as bscIroBatchExtract, IRO_FACTORY_ADDRESS as BSC_IRO_FACTORY_ADDRESS, IRO_FACTORY_ABI as BSC_IRO_FACTORY_ABI, IRO_TOKEN_ABI as BSC_IRO_TOKEN_ABI, IRO_POOL_ABI as BSC_IRO_POOL_ABI, IRO_PLATFORM_URL as BSC_IRO_PLATFORM_URL, IRO_TESTNET_PLATFORM_URL as BSC_IRO_TESTNET_PLATFORM_URL, setIroApiBase as setBscIroApiBase, setIroTestApiBase as setBscIroTestApiBase, iroApiCreateProject as bscIroApiCreateProject, iroApiUploadImage as bscIroApiUploadImage, } from './platforms/iro/index.js';
@@ -101,7 +101,7 @@ export type BalanceValidationParams = {
101
101
  buyerAddress?: string;
102
102
  };
103
103
  export declare function validateFinalBalances({ sameAddress, buyerBalance, buyAmountBNB, reserveGas, gasLimit, gasPrice, useNativeToken, quoteTokenDecimals, provider, buyerAddress, }: BalanceValidationParams): Promise<void>;
104
- export declare function countTruthy(values: unknown[]): number;
104
+ export declare function countTruthy(values: Array<string | number | bigint | boolean | null | undefined>): number;
105
105
  /**
106
106
  * PancakeSwap V2/V3 通用捆绑换手(Merkle Bundle)
107
107
  *
@@ -6,7 +6,7 @@
6
6
  * - 查询: 通过 projectId / token 地址获取信息
7
7
  */
8
8
  import { JsonRpcProvider } from 'ethers';
9
- import type { IroCreateParams, IroCreateProjectResult, IroQueryConfig, IroFactoryTokenInfo } from './types.js';
9
+ import type { IroCreateParams, IroCreateProjectResult, IroQueryConfig, IroFactoryTokenInfo, IroCreateProjectParams } from './types.js';
10
10
  export declare class IroFactoryQuery {
11
11
  private provider;
12
12
  private factory;
@@ -31,7 +31,7 @@ export declare class IroFactoryQuery {
31
31
  /**
32
32
  * 编码 createProject calldata
33
33
  */
34
- export declare function encodeCreateProjectCall(params: import('./types.js').IroCreateProjectParams): string;
34
+ export declare function encodeCreateProjectCall(params: IroCreateProjectParams): string;
35
35
  /**
36
36
  * 创建 IRO 项目 — 签名交易
37
37
  *
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 各钱包离线签署操作意图,主钱包收集后统一提交。
5
5
  */
6
- import { Wallet, JsonRpcProvider } from 'ethers';
6
+ import { Wallet, JsonRpcProvider, Interface } from 'ethers';
7
7
  import { ENI_CHAIN_ID, ENI_RPC_URL } from '../constants.js';
8
8
  import { ENI_BUNDLER_ABI, EIP712_DOMAIN, SIGNED_OP_TYPE, TOKEN_PULL_TYPE } from './constants.js';
9
9
  const DEFAULT_DEADLINE_SEC = 300;
@@ -19,7 +19,6 @@ function buildDomain(bundlerAddress, chainId = Number(ENI_CHAIN_ID)) {
19
19
  */
20
20
  export async function getBundlerNonce(params) {
21
21
  const provider = new JsonRpcProvider(params.rpcUrl ?? ENI_RPC_URL, ENI_CHAIN_ID, { staticNetwork: true });
22
- const { Interface } = await import('ethers');
23
22
  const iface = new Interface(ENI_BUNDLER_ABI);
24
23
  const data = iface.encodeFunctionData('nonces', [params.signer]);
25
24
  const result = await provider.call({ to: params.bundlerAddress, data });
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ENI 包根扁平别名(子路径 `four-flap-meme-sdk/chains/eni` 可直接 import)
3
+ *
4
+ * 与 `root-eni-and-bsc-iro.ts` 中 `eni*` / `Eni*` 命名对齐,避免为 ENI 拉包根。
5
+ */
6
+ export { DaoaasPortalQuery as EniPortalQuery, createPortalQuery as eniCreatePortalQuery, encodeBuyCall as eniEncodeBuyCall, encodeSellCall as eniEncodeSellCall, encodeCreateCall as eniEncodeCreateCall, applySlippage as eniApplySlippage, formatEgas as eniFormatEgas, parseEgas as eniParseEgas, directBuy as eniDirectBuy, directSell as eniDirectSell, directBatchBuy as eniDirectBatchBuy, directBatchSell as eniDirectBatchSell, directBuyForSubmit as eniDirectBuyForSubmit, directSellForSubmit as eniDirectSellForSubmit, directBatchBuyForSubmit as eniDirectBatchBuyForSubmit, directBatchSellForSubmit as eniDirectBatchSellForSubmit, directQuickSwap as eniDirectQuickSwap, directQuickSwapForSubmit as eniDirectQuickSwapForSubmit, buildProfitTransfer as eniBuildProfitTransfer, createToken as eniCreateToken, createTokenForSubmit as eniCreateTokenForSubmit, getGraduationInfo as eniGetGraduationInfo, batchGetGraduationInfo as eniBatchGetGraduationInfo, getTokenMeta as eniGetTokenMeta, getFairLaunchTokenMeta as eniGetFairLaunchTokenMeta, getTokenMetasBatch as eniGetTokenMetasBatch, DaoaasTokenStatus as EniDaoaasTokenStatus, } from './platforms/daoaas/index.js';
7
+ export type { DaoaasTokenState as EniDaoaasTokenState, DaoaasBuyParams as EniDaoaasBuyParams, DaoaasSellParams as EniDaoaasSellParams, DaoaasCreateParams as EniDaoaasCreateParams, PortalQueryConfig as EniPortalQueryConfig, GraduationInfo as EniGraduationInfo, DaoaasTokenMeta as EniDaoaasTokenMeta, } from './platforms/daoaas/index.js';
8
+ export { eniDisperseForSubmit, eniSweepForSubmit, batchTransferEgas, batchSweepEgas, batchSweepToken, } from './batch-router/index.js';
9
+ export type { EniDisperseParams, EniDisperseResult, EniSweepParams, EniSweepResult } from './batch-router/index.js';
10
+ export * as EniBatchRouter from './batch-router/index.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * ENI 包根扁平别名(子路径 `four-flap-meme-sdk/chains/eni` 可直接 import)
3
+ *
4
+ * 与 `root-eni-and-bsc-iro.ts` 中 `eni*` / `Eni*` 命名对齐,避免为 ENI 拉包根。
5
+ */
6
+ export { DaoaasPortalQuery as EniPortalQuery, createPortalQuery as eniCreatePortalQuery, encodeBuyCall as eniEncodeBuyCall, encodeSellCall as eniEncodeSellCall, encodeCreateCall as eniEncodeCreateCall, applySlippage as eniApplySlippage, formatEgas as eniFormatEgas, parseEgas as eniParseEgas, directBuy as eniDirectBuy, directSell as eniDirectSell, directBatchBuy as eniDirectBatchBuy, directBatchSell as eniDirectBatchSell, directBuyForSubmit as eniDirectBuyForSubmit, directSellForSubmit as eniDirectSellForSubmit, directBatchBuyForSubmit as eniDirectBatchBuyForSubmit, directBatchSellForSubmit as eniDirectBatchSellForSubmit, directQuickSwap as eniDirectQuickSwap, directQuickSwapForSubmit as eniDirectQuickSwapForSubmit, buildProfitTransfer as eniBuildProfitTransfer, createToken as eniCreateToken, createTokenForSubmit as eniCreateTokenForSubmit, getGraduationInfo as eniGetGraduationInfo, batchGetGraduationInfo as eniBatchGetGraduationInfo, getTokenMeta as eniGetTokenMeta, getFairLaunchTokenMeta as eniGetFairLaunchTokenMeta, getTokenMetasBatch as eniGetTokenMetasBatch, DaoaasTokenStatus as EniDaoaasTokenStatus, } from './platforms/daoaas/index.js';
7
+ export { eniDisperseForSubmit, eniSweepForSubmit, batchTransferEgas, batchSweepEgas, batchSweepToken, } from './batch-router/index.js';
8
+ export * as EniBatchRouter from './batch-router/index.js';
@@ -20,3 +20,4 @@ export { getLPPairInfo, batchGetLPPairInfo, getPairAddress, addLiquidityETHForSu
20
20
  export type { LPPairInfo, GetLPInfoParams, BatchGetLPInfoParams, AddLiquidityETHParams, RemoveLiquidityETHParams, AddLiquidityParams, RemoveLiquidityParams, LiquidityTxResult, LiquidityForSubmitResult, } from './platforms/dswap/index.js';
21
21
  export { IroFactoryQuery as EniIroFactoryQuery, encodeCreateProjectCall as eniIroEncodeCreateProjectCall, createProject as eniIroCreateProject, parseCreateProjectEvent as eniIroParseCreateProjectEvent, IroTokenQuery as EniIroTokenQuery, subscribe as eniIroSubscribe, pledge as eniIroPledge, batchSubscribe as eniIroBatchSubscribe, batchSubscribeForSubmit as eniIroBatchSubscribeForSubmit, IroPoolQuery as EniIroPoolQuery, poolRemovePledge as eniIroPoolRemovePledge, poolExtract as eniIroPoolExtract, poolTransferAwards as eniIroPoolTransferAwards, batchExtract as eniIroBatchExtract, ENI_IRO_FACTORY_ADDRESS, ENI_IRO_OWNER_ADDRESS, ENI_IRO_SELL_FEE_CONTRACT, ENI_IROSWAP_V2_ROUTER, ENI_IROSWAP_V2_FACTORY, IRO_FACTORY_ABI as ENI_IRO_FACTORY_ABI, IRO_TOKEN_ABI as ENI_IRO_TOKEN_ABI, IRO_POOL_ABI as ENI_IRO_POOL_ABI, CREATE_PROJECT_GAS_LIMIT as ENI_CREATE_PROJECT_GAS_LIMIT, ENI_IRO_PLATFORM_URL, setIroApiBase as setEniIroApiBase, iroApiCreateProject as eniIroApiCreateProject, iroApiUploadImage as eniIroApiUploadImage, getTokenWhiteList as eniIroGetTokenWhiteList, addTokenWhiteListForSubmit as eniIroAddTokenWhiteListForSubmit, batchAddTokenWhiteListForSubmit as eniIroBatchAddTokenWhiteListForSubmit, removeTokenWhiteListForSubmit as eniIroRemoveTokenWhiteListForSubmit, IRO_OWNER_WHITELIST_ABI as ENI_IRO_OWNER_WHITELIST_ABI, } from './platforms/iro/index.js';
22
22
  export type { WhiteListQuota as EniWhiteListQuota, IroCreateProjectParams as EniIroCreateProjectParams, IroSubscribeParams as EniIroSubscribeParams, IroPledgeParams as EniIroPledgeParams, IroTokenInfo as EniIroTokenInfo, IroTxResult as EniIroTxResult, IroCreateProjectResult as EniIroCreateProjectResult, IroQueryConfig as EniIroQueryConfig, IroCreateParams as EniIroCreateParams, IroBatchSubscribeForSubmitParams as EniIroBatchSubscribeForSubmitParams, IroBatchSubscribeForSubmitResult as EniIroBatchSubscribeForSubmitResult, WhitelistManageConfig as EniWhitelistManageConfig, AddWhitelistParams as EniAddWhitelistParams, BatchAddWhitelistParams as EniBatchAddWhitelistParams, RemoveWhitelistParams as EniRemoveWhitelistParams, GetWhitelistParams as EniGetWhitelistParams, } from './platforms/iro/index.js';
23
+ export * from './flat-aliases.js';
@@ -31,3 +31,4 @@ export { getLPPairInfo, batchGetLPPairInfo, getPairAddress, addLiquidityETHForSu
31
31
  // 快捷导出 - IRO (Initial Rights Offering)
32
32
  // ============================================================================
33
33
  export { IroFactoryQuery as EniIroFactoryQuery, encodeCreateProjectCall as eniIroEncodeCreateProjectCall, createProject as eniIroCreateProject, parseCreateProjectEvent as eniIroParseCreateProjectEvent, IroTokenQuery as EniIroTokenQuery, subscribe as eniIroSubscribe, pledge as eniIroPledge, batchSubscribe as eniIroBatchSubscribe, batchSubscribeForSubmit as eniIroBatchSubscribeForSubmit, IroPoolQuery as EniIroPoolQuery, poolRemovePledge as eniIroPoolRemovePledge, poolExtract as eniIroPoolExtract, poolTransferAwards as eniIroPoolTransferAwards, batchExtract as eniIroBatchExtract, ENI_IRO_FACTORY_ADDRESS, ENI_IRO_OWNER_ADDRESS, ENI_IRO_SELL_FEE_CONTRACT, ENI_IROSWAP_V2_ROUTER, ENI_IROSWAP_V2_FACTORY, IRO_FACTORY_ABI as ENI_IRO_FACTORY_ABI, IRO_TOKEN_ABI as ENI_IRO_TOKEN_ABI, IRO_POOL_ABI as ENI_IRO_POOL_ABI, CREATE_PROJECT_GAS_LIMIT as ENI_CREATE_PROJECT_GAS_LIMIT, ENI_IRO_PLATFORM_URL, setIroApiBase as setEniIroApiBase, iroApiCreateProject as eniIroApiCreateProject, iroApiUploadImage as eniIroApiUploadImage, getTokenWhiteList as eniIroGetTokenWhiteList, addTokenWhiteListForSubmit as eniIroAddTokenWhiteListForSubmit, batchAddTokenWhiteListForSubmit as eniIroBatchAddTokenWhiteListForSubmit, removeTokenWhiteListForSubmit as eniIroRemoveTokenWhiteListForSubmit, IRO_OWNER_WHITELIST_ABI as ENI_IRO_OWNER_WHITELIST_ABI, } from './platforms/iro/index.js';
34
+ export * from './flat-aliases.js';
@@ -5,7 +5,8 @@
5
5
  * 提供代币 Logo、社交链接、描述等元信息查询
6
6
  */
7
7
  import { Contract, JsonRpcProvider } from 'ethers';
8
- import { ENI_CHAIN_ID, ENI_RPC_URL } from '../../constants.js';
8
+ import { ENI_CHAIN_ID, ENI_RPC_URL, LP_FAIR_LAUNCHER_ABI } from '../../constants.js';
9
+ import { LP_FAIR_LAUNCHER_ADDRESS } from '../fair-launch/constants.js';
9
10
  import { ERC20_ABI } from '../../../../abis/common.js';
10
11
  /**
11
12
  * 从 ERC20 合约获取 DAOaaS Portal 代币基本元数据
@@ -41,8 +42,6 @@ export async function getTokenMeta(token, rpcUrl = ENI_RPC_URL) {
41
42
  * FairLaunch 代币的 logo 和 metadata 存储在 LaunchParams 中
42
43
  */
43
44
  export async function getFairLaunchTokenMeta(token, rpcUrl = ENI_RPC_URL) {
44
- const { LP_FAIR_LAUNCHER_ABI } = await import('../../constants.js');
45
- const { LP_FAIR_LAUNCHER_ADDRESS } = await import('../fair-launch/constants.js');
46
45
  const provider = new JsonRpcProvider(rpcUrl, ENI_CHAIN_ID, { staticNetwork: true });
47
46
  const launcher = new Contract(LP_FAIR_LAUNCHER_ADDRESS, LP_FAIR_LAUNCHER_ABI, provider);
48
47
  const info = await launcher.getTokenInfoByToken(token);
@@ -4,7 +4,7 @@
4
4
  * ENI 使用 EIP-1559 (type 2) 交易,与 BSC (type 0) 不同
5
5
  */
6
6
  import { JsonRpcProvider } from 'ethers';
7
- import type { IroCreateParams, IroCreateProjectResult, IroQueryConfig, IroFactoryTokenInfo } from './types.js';
7
+ import type { IroCreateParams, IroCreateProjectResult, IroQueryConfig, IroFactoryTokenInfo, IroCreateProjectParams } from './types.js';
8
8
  export declare class IroFactoryQuery {
9
9
  private provider;
10
10
  private factory;
@@ -20,7 +20,7 @@ export declare class IroFactoryQuery {
20
20
  }>;
21
21
  get providerInstance(): JsonRpcProvider;
22
22
  }
23
- export declare function encodeCreateProjectCall(params: import('./types.js').IroCreateProjectParams): string;
23
+ export declare function encodeCreateProjectCall(params: IroCreateProjectParams): string;
24
24
  export declare function createProject(params: IroCreateParams): Promise<IroCreateProjectResult>;
25
25
  export declare function parseCreateProjectEvent(receipt: {
26
26
  logs: Array<{
@@ -237,23 +237,12 @@ export async function bundleSell(params) {
237
237
  // 判断是否需要查询代币余额
238
238
  const needBalanceQuery = !sellAmounts || sellAmounts.length !== wallets.length;
239
239
  // 构建并行请求
240
- const parallelPromises = [
241
- // 1. 批量获取授权钱包的 nonce
240
+ const [walletNonces, mainNonce, feeData, tokenBalances] = await Promise.all([
242
241
  batchGetNonces(allAddresses, provider),
243
- // 2. 获取主钱包的交易 nonce
244
242
  provider.getTransactionCount(mainWallet.address, 'pending'),
245
- // 3. 获取 gas 费用数据
246
243
  provider.getFeeData(),
247
- ];
248
- // 4. 如果需要查询余额,并行获取
249
- if (needBalanceQuery) {
250
- parallelPromises.push(getTokenBalances(wallets, tokenAddress));
251
- }
252
- const results = await Promise.all(parallelPromises);
253
- const walletNonces = results[0];
254
- const mainNonce = results[1];
255
- const feeData = results[2];
256
- const tokenBalances = needBalanceQuery ? results[3] : null;
244
+ needBalanceQuery ? getTokenBalances(wallets, tokenAddress) : Promise.resolve(null),
245
+ ]);
257
246
  // ========================================
258
247
  // 同步计算卖出数量
259
248
  // ========================================
@@ -0,0 +1,13 @@
1
+ /**
2
+ * EIP-7702 包根扁平别名(与 `root-swap-dex-and-xlayer.ts` 对齐)
3
+ */
4
+ export { bundleBuy as xlayerEip7702BundleBuy } from './bundle-buy.js';
5
+ export { bundleSell as xlayerEip7702BundleSell } from './bundle-sell.js';
6
+ export { bundleApprove as xlayerEip7702BundleApprove, bundleApproveMultiSpenders as xlayerEip7702BundleApproveMultiSpenders, checkApprovalStatus as xlayerEip7702CheckApprovalStatus, } from './bundle-approve.js';
7
+ export { bundleSwap as xlayerEip7702BundleSwap, bundleBatchSwap as xlayerEip7702BundleBatchSwap, bundleMultiSwap as xlayerEip7702BundleMultiSwap, } from './bundle-swap.js';
8
+ export { disperse as xlayerEip7702Disperse, sweep as xlayerEip7702Sweep, pairwiseTransfer as xlayerEip7702PairwiseTransfer, disperseWithHops as xlayerEip7702DisperseWithHops, sweepWithHops as xlayerEip7702SweepWithHops, } from './multi-hop-transfer.js';
9
+ export { washVolume as xlayerEip7702WashVolume, bundleVolume as xlayerEip7702BundleVolume, singleRoundVolume as xlayerEip7702SingleRoundVolume, makeVolume as xlayerEip7702MakeVolume, makeVolumeWithSwap as xlayerEip7702MakeVolumeWithSwap, } from './volume.js';
10
+ export { bundleCreateBuy as xlayerEip7702BundleCreateBuy, bundleCreateToDex as xlayerEip7702BundleCreateToDex, bundleGraduateBuy as xlayerEip7702BundleGraduateBuy, } from './bundle-create.js';
11
+ export type { TradeType as XLayerEip7702TradeType, BundleBuyParams as XLayerEip7702BundleBuyParams, BundleSellParams as XLayerEip7702BundleSellParams, BundleSwapParams as XLayerEip7702BundleSwapParams, BundleMultiSwapParams as XLayerEip7702BundleMultiSwapParams, DisperseParams as XLayerEip7702DisperseParams, SweepParams as XLayerEip7702SweepParams, EIP7702Config as XLayerEip7702Config, } from './types.js';
12
+ export type { PairwiseTransferParams as XLayerEip7702PairwiseTransferParams } from './multi-hop-transfer.js';
13
+ export type { WashVolumeParams as XLayerEip7702WashVolumeParams, BundleVolumeParams as XLayerEip7702BundleVolumeParams, } from './volume.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * EIP-7702 包根扁平别名(与 `root-swap-dex-and-xlayer.ts` 对齐)
3
+ */
4
+ export { bundleBuy as xlayerEip7702BundleBuy } from './bundle-buy.js';
5
+ export { bundleSell as xlayerEip7702BundleSell } from './bundle-sell.js';
6
+ export { bundleApprove as xlayerEip7702BundleApprove, bundleApproveMultiSpenders as xlayerEip7702BundleApproveMultiSpenders, checkApprovalStatus as xlayerEip7702CheckApprovalStatus, } from './bundle-approve.js';
7
+ export { bundleSwap as xlayerEip7702BundleSwap, bundleBatchSwap as xlayerEip7702BundleBatchSwap, bundleMultiSwap as xlayerEip7702BundleMultiSwap, } from './bundle-swap.js';
8
+ export { disperse as xlayerEip7702Disperse, sweep as xlayerEip7702Sweep, pairwiseTransfer as xlayerEip7702PairwiseTransfer, disperseWithHops as xlayerEip7702DisperseWithHops, sweepWithHops as xlayerEip7702SweepWithHops, } from './multi-hop-transfer.js';
9
+ export { washVolume as xlayerEip7702WashVolume, bundleVolume as xlayerEip7702BundleVolume, singleRoundVolume as xlayerEip7702SingleRoundVolume, makeVolume as xlayerEip7702MakeVolume, makeVolumeWithSwap as xlayerEip7702MakeVolumeWithSwap, } from './volume.js';
10
+ export { bundleCreateBuy as xlayerEip7702BundleCreateBuy, bundleCreateToDex as xlayerEip7702BundleCreateToDex, bundleGraduateBuy as xlayerEip7702BundleGraduateBuy, } from './bundle-create.js';
@@ -15,8 +15,7 @@
15
15
  */
16
16
  export * from './constants.js';
17
17
  export * from './types.js';
18
- /** 与包根 `XLayerEip7702TradeType` 别名一致,便于子路径引用 */
19
- export type { TradeType as XLayerEip7702TradeType } from './types.js';
18
+ export * from './flat-aliases.js';
20
19
  export { bigintToBytes, addressToBytes, hexToBytes, trimLeadingZeros, getCachedProvider, clearProviderCache, createWallet, generateRandomWallet, generateRandomWallets, signAuthorization, signAuthorizationWithNonce, signAuthorizationsBatch, buildEIP7702Transaction, estimateGasLimit, estimateGasLimitSimple, calculateProfitAmount, calculateProfitAmountByUserType, calculateProfitAmountByTxCount, getProfitRateBps, getProfitRateBpsDouble, getProfitRecipient, getDeadline, delay, type UserType, type OperationType, } from './utils.js';
21
20
  export { bundleBuy } from './bundle-buy.js';
22
21
  export { bundleSell } from './bundle-sell.js';
@@ -21,6 +21,7 @@ export * from './constants.js';
21
21
  // 类型
22
22
  // ============================================================================
23
23
  export * from './types.js';
24
+ export * from './flat-aliases.js';
24
25
  // ============================================================================
25
26
  // 工具函数
26
27
  // ============================================================================
@@ -18,7 +18,7 @@ import { UserType } from './utils.js';
18
18
  export interface TransferResult {
19
19
  signedTransaction: string;
20
20
  hopWallets?: GeneratedWallet[];
21
- metadata: Record<string, unknown>;
21
+ metadata: Record<string, string | number | boolean | bigint | null | undefined>;
22
22
  }
23
23
  export interface DisperseParams {
24
24
  /** 资金来源钱包私钥(Token/OKB 从这个钱包转出) */
@@ -210,22 +210,21 @@ export async function sweep(params) {
210
210
  // ========================================
211
211
  const sourceAddresses = sourceWallets.map((w) => w.address);
212
212
  const addressesToGetNonces = payerWallet ? [payerWallet.address, ...sourceAddresses] : sourceAddresses;
213
- const parallelPromises = [batchGetNonces(addressesToGetNonces, provider), provider.getFeeData()];
214
- if (isNative) {
215
- parallelPromises.push(Promise.all(sourceWallets.map((w) => provider.getBalance(w.address))));
216
- }
217
- else {
218
- if (!tokenAddress)
219
- throw new Error('tokenAddress is required for ERC20 sweep');
220
- const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
221
- parallelPromises.push(Promise.all(sourceWallets.map((w) => tokenContract.balanceOf(w.address))));
222
- }
223
- const results = await Promise.all(parallelPromises);
224
- const allNoncesResult = results[0];
213
+ const [allNoncesResult, feeData, balancesRaw] = await Promise.all([
214
+ batchGetNonces(addressesToGetNonces, provider),
215
+ provider.getFeeData(),
216
+ isNative
217
+ ? Promise.all(sourceWallets.map((w) => provider.getBalance(w.address)))
218
+ : Promise.all(sourceWallets.map((w) => {
219
+ if (!tokenAddress)
220
+ throw new Error('tokenAddress is required for ERC20 sweep');
221
+ const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
222
+ return tokenContract.balanceOf(w.address);
223
+ })),
224
+ ]);
225
225
  const payerNonce = payerWallet ? allNoncesResult[0] : allNoncesResult[0];
226
226
  const nonces = payerWallet ? allNoncesResult.slice(1) : allNoncesResult;
227
- const feeData = results[1];
228
- const balances = results[2].map((b) => typeof b === 'bigint' ? b : BigInt(b.toString()));
227
+ const balances = balancesRaw;
229
228
  // 计算转账金额
230
229
  // ✅ 修复:当 percent=100 时,不预留 gas,归集全部余额
231
230
  const isFullSweep = percent >= 100;
@@ -7,6 +7,7 @@ import { UNIFIED_DELEGATE_ADDRESS, UNIFIED_DELEGATE_ABI, FLAP_PORTAL_ABI, FLAP_P
7
7
  import { bundleBuy } from './bundle-buy.js';
8
8
  import { bundleSell } from './bundle-sell.js';
9
9
  import { bundleSwap } from './bundle-swap.js';
10
+ import { quoteV2, quoteV3 } from '../../../utils/quote-helpers.js';
10
11
  import { truncateDecimals, } from './volume-helpers.js';
11
12
  export async function washVolume(params) {
12
13
  const { mainPrivateKey, privateKeys, tokenAddress, tokenDecimals = 18, buyAmountPerWallet, sellPercent = 100, poolType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', // ✅ 用户类型(影响利润率)
@@ -108,7 +109,6 @@ export async function washVolume(params) {
108
109
  else if (poolType === 'V2' || poolType === 'V3') {
109
110
  // ✅ V2/V3 外盘模式:通过报价获取预估代币数量,确保买卖对等
110
111
  try {
111
- const { quoteV2, quoteV3 } = await import('../../../utils/quote-helpers.js');
112
112
  let totalTokenAmount = 0n;
113
113
  if (poolType === 'V3') {
114
114
  const result = await quoteV3(provider, WOKB_ADDRESS, tokenAddress, totalBuyWei, 'XLAYER', fee);
@@ -258,21 +258,21 @@ export async function bundleVolume(params) {
258
258
  const allAddresses = allWallets.map((w) => w.address);
259
259
  // 获取卖出钱包的代币余额(如果需要)
260
260
  const needBalanceQuery = !sellAmounts || sellAmounts.length !== sellerWallets.length;
261
- const parallelPromises = [batchGetNonces(allAddresses, provider), provider.getFeeData()];
262
- if (needBalanceQuery && sellerWallets.length > 0) {
263
- const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
264
- parallelPromises.push(Promise.all(sellerWallets.map((w) => tokenContract.balanceOf(w.address))));
265
- }
266
- const results = await Promise.all(parallelPromises);
267
- const nonces = results[0];
268
- const feeData = results[1];
261
+ const tokenContract = needBalanceQuery && sellerWallets.length > 0 ? new ethers.Contract(tokenAddress, ERC20_ABI, provider) : null;
262
+ const [nonces, feeData, sellerBalancesRaw] = await Promise.all([
263
+ batchGetNonces(allAddresses, provider),
264
+ provider.getFeeData(),
265
+ needBalanceQuery && sellerWallets.length > 0 && tokenContract
266
+ ? Promise.all(sellerWallets.map((w) => tokenContract.balanceOf(w.address)))
267
+ : Promise.resolve(null),
268
+ ]);
269
269
  // 计算卖出金额
270
270
  let sellAmountsWei;
271
271
  if (sellAmounts && sellAmounts.length === sellerWallets.length) {
272
272
  // ✅ 如果有指定卖出金额,直接使用
273
273
  sellAmountsWei = sellAmounts.map((amt) => ethers.parseUnits(truncateDecimals(amt, tokenDecimals), tokenDecimals));
274
274
  }
275
- else if (needBalanceQuery && results[2]) {
275
+ else if (needBalanceQuery && sellerBalancesRaw) {
276
276
  // ✅ 根据 poolType 预估买入能获得的代币数量
277
277
  let estimatedTokenAmount = 0n;
278
278
  try {
@@ -10,5 +10,6 @@ export * as eoa from './eoa/index.js';
10
10
  export * as eip7702 from './eip7702/index.js';
11
11
  export { PortalQuery, createPortalQuery, xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle, xlayerPureCrossSwapMerkle, signEoaWashBuyTransactions, signEoaWashSellTransactions, signEoaWashVolumeTransactions, } from './eoa/index.js';
12
12
  export type { BundleSwapParams, BundleSwapSignParams, BundleSwapResult, BundleSwapSignResult, BundleBatchSwapParams, BundleBatchSwapSignParams, BundleBatchSwapResult, BundleBatchSwapSignResult, BuyFirstParams, BuyFirstResult, BuyParams, SellParams, } from './eoa/types.js';
13
- export { bundleBuy as xlayerEip7702BundleBuy, bundleSell as xlayerEip7702BundleSell, bundleSwap as xlayerEip7702BundleSwap, bundleApprove as xlayerEip7702BundleApprove, bundleCreateBuy as xlayerEip7702BundleCreate, washVolume as xlayerEip7702WashVolume, bundleVolume as xlayerEip7702BundleVolume, } from './eip7702/index.js';
14
- export { default as xlayer } from './eoa/index.js';
13
+ export * from './eip7702/flat-aliases.js';
14
+ export { default as xlayer, default as XLayer } from './eoa/index.js';
15
+ export { lpFeeProfileToV3Fee } from './eoa/portal-ops.js';
@@ -22,12 +22,9 @@ xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle, xlayerPureCrossSwapMerkle,
22
22
  // EOA 刷量
23
23
  signEoaWashBuyTransactions, signEoaWashSellTransactions, signEoaWashVolumeTransactions, } from './eoa/index.js';
24
24
  // ============================================================================
25
- // 快捷导出 - EIP-7702 模式(使用实际名称)
25
+ // 快捷导出 - EIP-7702 模式(与包根 `xlayerEip7702*` 别名一致,见 flat-aliases)
26
26
  // ============================================================================
27
- export {
28
- // Bundle 操作
29
- bundleBuy as xlayerEip7702BundleBuy, bundleSell as xlayerEip7702BundleSell, bundleSwap as xlayerEip7702BundleSwap, bundleApprove as xlayerEip7702BundleApprove, bundleCreateBuy as xlayerEip7702BundleCreate,
30
- // 刷量
31
- washVolume as xlayerEip7702WashVolume, bundleVolume as xlayerEip7702BundleVolume, } from './eip7702/index.js';
27
+ export * from './eip7702/flat-aliases.js';
32
28
  // 导出旧模块的默认对象(向后兼容)
33
- export { default as xlayer } from './eoa/index.js';
29
+ export { default as xlayer, default as XLayer } from './eoa/index.js';
30
+ export { lpFeeProfileToV3Fee } from './eoa/portal-ops.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * BSC Four.meme Merkle Bundle 横向入口
3
+ *
4
+ * memeweb 分发 / 换手 / 提交可统一走 `four-flap-meme-sdk/merkle`,避免拉包根。
5
+ */
6
+ export { disperseWithBundleMerkle } from '../bundle-core/four-meme/utils-disperse.js';
7
+ export { sweepWithBundleMerkle } from '../bundle-core/four-meme/utils-sweep.js';
8
+ export { pairwiseTransferWithBundleMerkle } from '../bundle-core/four-meme/utils-pairwise.js';
9
+ export { fourBundleSwapMerkle, fourBatchSwapMerkle, fourQuickBatchSwapMerkle } from '../bundle-core/four-meme/swap.js';
10
+ export { fourBundleBuyFirstMerkle } from '../bundle-core/four-meme/swap-buy-first.js';
11
+ export { submitBundleToMerkle, submitBundleToBlockRazor, submitDirectToRpc, submitDirectToRpcSmart, type MerkleSubmitConfig, type SubmitBundleResult, type BlockRazorSubmitConfig, type DirectSubmitConfig, } from '../bundle-core/submit.js';
12
+ export type { DisperseSignParams, DisperseMerkleResult, SweepSignParams, SweepMerkleResult, FourBundleSwapSignParams, FourSwapResult, FourBatchSwapSignParams, FourBatchSwapResult, FourQuickBatchSwapSignParams, FourQuickBatchSwapResult, PairwiseTransferSignParams, PairwiseTransferMerkleResult, } from '../bundle-core/four-meme/types.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * BSC Four.meme Merkle Bundle 横向入口
3
+ *
4
+ * memeweb 分发 / 换手 / 提交可统一走 `four-flap-meme-sdk/merkle`,避免拉包根。
5
+ */
6
+ export { disperseWithBundleMerkle } from '../bundle-core/four-meme/utils-disperse.js';
7
+ export { sweepWithBundleMerkle } from '../bundle-core/four-meme/utils-sweep.js';
8
+ export { pairwiseTransferWithBundleMerkle } from '../bundle-core/four-meme/utils-pairwise.js';
9
+ export { fourBundleSwapMerkle, fourBatchSwapMerkle, fourQuickBatchSwapMerkle } from '../bundle-core/four-meme/swap.js';
10
+ export { fourBundleBuyFirstMerkle } from '../bundle-core/four-meme/swap-buy-first.js';
11
+ export { submitBundleToMerkle, submitBundleToBlockRazor, submitDirectToRpc, submitDirectToRpcSmart, } from '../bundle-core/submit.js';
@@ -87,14 +87,26 @@ export type CreateTokenReq = {
87
87
  funGroup: false;
88
88
  clickFun: false;
89
89
  };
90
+ export type FourJsonValue = string | number | boolean | null | FourJsonValue[] | {
91
+ [key: string]: FourJsonValue;
92
+ };
93
+ export type FourPublicConfig = {
94
+ [key: string]: FourJsonValue;
95
+ };
96
+ export type FourTokenDetail = {
97
+ [key: string]: FourJsonValue;
98
+ } & {
99
+ address?: string;
100
+ name?: string;
101
+ symbol?: string;
102
+ };
90
103
  export type CreateTokenResp = {
91
104
  createArg: string;
92
105
  signature: string;
93
106
  tokenAddr?: string;
94
107
  address?: string;
95
108
  token?: string;
96
- [key: string]: unknown;
97
- };
109
+ } & Record<string, string | undefined>;
98
110
  export declare class FourClient {
99
111
  private baseUrl;
100
112
  private uploadUrls;
@@ -124,9 +136,12 @@ export declare class FourClient {
124
136
  private isCorsOrNetworkError;
125
137
  private getFilenameFromBlob;
126
138
  createToken(accessToken: string, req: CreateTokenReq): Promise<CreateTokenResp>;
127
- getPublicConfig(): Promise<unknown>;
128
- getTokenByAddress(address: string, accessToken?: string): Promise<unknown>;
129
- getTokensByAddresses(addresses: string[], accessToken?: string): Promise<unknown[]>;
130
- getTokenById(id: string | number, accessToken?: string): Promise<unknown>;
139
+ getPublicConfig(): Promise<FourPublicConfig>;
140
+ getTokenByAddress(address: string, accessToken?: string): Promise<FourTokenDetail>;
141
+ getTokensByAddresses(addresses: string[], accessToken?: string): Promise<(FourTokenDetail | {
142
+ address: string;
143
+ error: string;
144
+ })[]>;
145
+ getTokenById(id: string | number, accessToken?: string): Promise<FourTokenDetail>;
131
146
  }
132
147
  export declare function buildLoginMessage(nonce: string): string;
@@ -155,16 +155,17 @@ export class FourClient {
155
155
  return imgUrl;
156
156
  }
157
157
  catch (e) {
158
- lastError = e;
158
+ const err = e instanceof Error ? e : new Error(getErrorMessageFromUnknown(e));
159
+ lastError = err;
159
160
  const canRetry = i < this.uploadUrls.length - 1;
160
- if (this.isRateLimitError(e) && canRetry) {
161
+ if (this.isRateLimitError(err) && canRetry) {
161
162
  // IP 限流 → 切下一个端点
162
163
  const nextUrl = this.uploadUrls[i + 1];
163
164
  const nextLabel = nextUrl === FOUR_MEME_OFFICIAL_API ? '官方直连' : `备用端点 #${i + 2}`;
164
165
  console.warn(`[FourClient] 端点 ${baseUrl} 触发 IP 限流(100次/天),切换到${nextLabel}...`);
165
166
  continue;
166
167
  }
167
- if (this.isCorsOrNetworkError(e) && canRetry) {
168
+ if (this.isCorsOrNetworkError(err) && canRetry) {
168
169
  // CORS/网络错误(常见于浏览器直连官方 API)→ 跳过,继续尝试下一个
169
170
  console.warn(`[FourClient] 端点 ${baseUrl} 请求失败(${isOfficial ? 'CORS限制' : '网络错误'}),跳过`);
170
171
  continue;
@@ -251,7 +252,7 @@ export class FourClient {
251
252
  }
252
253
  async getPublicConfig() {
253
254
  const r = await fetch(`${this.baseUrl}/v1/public/config`);
254
- return await r.json();
255
+ return (await r.json());
255
256
  }
256
257
  async getTokenByAddress(address, accessToken) {
257
258
  const r = await fetch(`${this.baseUrl}/v1/private/token/get?address=${address}`, {
@@ -261,12 +262,12 @@ export class FourClient {
261
262
  if (j.code && j.code !== '0' && j.code !== 0) {
262
263
  throw new Error(`getTokenByAddress failed: ${JSON.stringify(j)}`);
263
264
  }
264
- return j.data ?? j;
265
+ return (j.data ?? j);
265
266
  }
266
267
  async getTokensByAddresses(addresses, accessToken) {
267
268
  if (!Array.isArray(addresses) || addresses.length === 0)
268
269
  return [];
269
- const tasks = addresses.map((addr) => this.getTokenByAddress(addr, accessToken).catch((e) => ({ address: addr, error: String(e) })));
270
+ const tasks = addresses.map((addr) => this.getTokenByAddress(addr, accessToken).catch((e) => ({ address: addr, error: getErrorMessageFromUnknown(e) })));
270
271
  return await Promise.all(tasks);
271
272
  }
272
273
  async getTokenById(id, accessToken) {
@@ -277,7 +278,7 @@ export class FourClient {
277
278
  if (j.code && j.code !== '0' && j.code !== 0) {
278
279
  throw new Error(`getTokenById failed: ${JSON.stringify(j)}`);
279
280
  }
280
- return j.data ?? j;
281
+ return (j.data ?? j);
281
282
  }
282
283
  }
283
284
  export function buildLoginMessage(nonce) {
@@ -1,7 +1,13 @@
1
1
  import { JsonRpcProvider } from 'ethers';
2
2
  export type FlapChain = 'BSC' | 'BASE' | 'XLAYER' | 'MORPH';
3
+ /** JSON 可序列化值(递归) */
4
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
5
+ [key: string]: JsonValue;
6
+ };
3
7
  /** IPFS 元数据 JSON(字段因项目而异) */
4
- export type FlapTokenMetaJson = Record<string, unknown>;
8
+ export type FlapTokenMetaJson = {
9
+ [key: string]: JsonValue;
10
+ };
5
11
  export type FlapMetaByAddressResult = {
6
12
  cid: string;
7
13
  data?: FlapTokenMetaJson;
@@ -2,25 +2,34 @@ export type PinataConfig = {
2
2
  jwt: string;
3
3
  gateway?: string;
4
4
  };
5
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
6
+ [key: string]: JsonValue;
7
+ };
8
+ /** Pinata gateway JSON 响应(结构因 CID 内容而异) */
9
+ export type PinataGatewayJson = {
10
+ [key: string]: JsonValue;
11
+ };
5
12
  type PinataPinApiResponse = {
6
13
  IpfsHash?: string;
7
14
  cid?: string;
8
15
  PinSize?: number;
9
16
  Timestamp?: string;
10
17
  };
18
+ export type PinataJsonUpload = {
19
+ [key: string]: JsonValue;
20
+ };
11
21
  export declare class PinataClient {
12
22
  private client;
13
- private ready;
14
23
  constructor(cfg: PinataConfig);
15
24
  uploadFile(file: File): Promise<{
16
25
  cid: string;
17
26
  id: string;
18
27
  }>;
19
- uploadJSON(obj: unknown, name?: string): Promise<{
28
+ uploadJSON(obj: PinataJsonUpload, name?: string): Promise<{
20
29
  cid: string;
21
30
  id: string;
22
31
  }>;
23
- get(cid: string): Promise<unknown>;
32
+ get(cid: string): Promise<PinataGatewayJson>;
24
33
  url(cid: string): Promise<string>;
25
34
  }
26
35
  export type PinataPinResp = {
@@ -1,14 +1,13 @@
1
+ import { createReadStream } from 'node:fs';
2
+ import axios from 'axios';
3
+ import NodeFormData from 'form-data';
4
+ import { PinataSDK } from 'pinata';
1
5
  export class PinataClient {
2
6
  client;
3
- ready;
4
7
  constructor(cfg) {
5
- this.ready = (async () => {
6
- const mod = (await import('pinata'));
7
- this.client = new mod.PinataSDK({ pinataJwt: cfg.jwt, pinataGateway: cfg.gateway });
8
- })();
8
+ this.client = new PinataSDK({ pinataJwt: cfg.jwt, pinataGateway: cfg.gateway });
9
9
  }
10
10
  async uploadFile(file) {
11
- await this.ready;
12
11
  const r = await this.client.upload.file(file);
13
12
  return { cid: r.cid, id: r.id ?? '' };
14
13
  }
@@ -18,11 +17,9 @@ export class PinataClient {
18
17
  return await this.uploadFile(file);
19
18
  }
20
19
  async get(cid) {
21
- await this.ready;
22
20
  return await this.client.gateways.public.get(cid);
23
21
  }
24
22
  async url(cid) {
25
- await this.ready;
26
23
  return await this.client.gateways.convert(cid);
27
24
  }
28
25
  }
@@ -34,16 +31,9 @@ export class PinataClient {
34
31
  * @param fileName 可选:内存数据的文件名
35
32
  */
36
33
  export async function pinFileToIPFSWithJWT(jwt, filePath, data, fileName) {
37
- const axiosMod = await import('axios');
38
- const FormDataMod = (await import('form-data'));
39
- const fsMod = await import('node:fs');
40
- const FormDataCtor = FormDataMod.default;
41
- if (!FormDataCtor) {
42
- throw new Error('pinFileToIPFSWithJWT: form-data module unavailable');
43
- }
44
- const form = new FormDataCtor();
34
+ const form = new NodeFormData();
45
35
  if (filePath && filePath.length > 0) {
46
- form.append('file', fsMod.createReadStream(filePath));
36
+ form.append('file', createReadStream(filePath));
47
37
  }
48
38
  else if (data) {
49
39
  form.append('file', data, { filename: fileName || 'upload.bin' });
@@ -51,8 +41,8 @@ export async function pinFileToIPFSWithJWT(jwt, filePath, data, fileName) {
51
41
  else {
52
42
  throw new Error('pinFileToIPFSWithJWT: either filePath or data must be provided');
53
43
  }
54
- const resp = await axiosMod.default.post('https://api.pinata.cloud/pinning/pinFileToIPFS', form, {
55
- headers: { Authorization: `Bearer ${jwt}`, ...(form.getHeaders ? form.getHeaders() : {}) },
44
+ const resp = await axios.post('https://api.pinata.cloud/pinning/pinFileToIPFS', form, {
45
+ headers: { Authorization: `Bearer ${jwt}`, ...form.getHeaders() },
56
46
  maxContentLength: Infinity,
57
47
  maxBodyLength: Infinity,
58
48
  });
@@ -7,6 +7,7 @@
7
7
  * 3. 买到毕业(代币上 DEX)
8
8
  * 4. 多个钱包在 PancakeSwap(外盘)继续买入
9
9
  */
10
+ import { type TaxVaultConfig } from '../vault.js';
10
11
  import { type FlapSignConfig } from './config.js';
11
12
  import type { MerkleSignedResult } from './types.js';
12
13
  export type CreateToDexChain = 'bsc' | 'xlayer' | 'base';
@@ -85,7 +86,7 @@ export interface FlapCreateToDexParams {
85
86
  lpBps: number;
86
87
  minimumShareBalance?: number;
87
88
  /** ✅ Tax Vault 金库配置(可选) */
88
- vaultConfig?: import('../vault.js').TaxVaultConfig;
89
+ vaultConfig?: TaxVaultConfig;
89
90
  };
90
91
  /** V3 扩展 ID */
91
92
  extensionID?: string;
@@ -36,4 +36,14 @@ export interface CommonBundleConfig {
36
36
  export declare function getGasLimit(config: CommonBundleConfig, defaultGas?: number): bigint;
37
37
  export declare function getGasPriceConfig(config: CommonBundleConfig): GasPriceConfig;
38
38
  export declare function getTxType(config: CommonBundleConfig): 0 | 2;
39
- export declare function buildGasFields(txType: number, gasPrice: bigint): Record<string, unknown>;
39
+ export type LegacyGasFields = {
40
+ type: 0;
41
+ gasPrice: bigint;
42
+ };
43
+ export type Eip1559GasFields = {
44
+ type: 2;
45
+ maxFeePerGas: bigint;
46
+ maxPriorityFeePerGas: bigint;
47
+ };
48
+ export type TxGasFields = LegacyGasFields | Eip1559GasFields;
49
+ export declare function buildGasFields(txType: number, gasPrice: bigint): TxGasFields;
@@ -1,5 +1,8 @@
1
1
  import '../tx/wallet-sign-patch.js';
2
2
  import { CHAINS } from '../../constants/index.js';
3
+ function asBatchSendProvider(provider) {
4
+ return provider;
5
+ }
3
6
  const GLOBAL_NONCE_TTL_MS = 60 * 1000;
4
7
  const globalNonceCursorByChain = new Map();
5
8
  function isFlakyNonceChain(chainId) {
@@ -145,7 +148,7 @@ export class NonceManager {
145
148
  id: idx + 1,
146
149
  jsonrpc: '2.0',
147
150
  }));
148
- const rawResults = await this.provider._send(batchRequests);
151
+ const rawResults = await asBatchSendProvider(this.provider)._send(batchRequests);
149
152
  queryResults = rawResults.map((r) => {
150
153
  if (r.result) {
151
154
  return parseInt(r.result, 16);
@@ -146,7 +146,8 @@ export async function sweepWithBundle(params) {
146
146
  try {
147
147
  const balData = iface.encodeFunctionData('balanceOf', [w.address]);
148
148
  const balRaw = await provider.call({ to: tokenAddress, data: balData });
149
- const [bal] = iface.decodeFunctionResult('balanceOf', balRaw);
149
+ const decoded = iface.decodeFunctionResult('balanceOf', balRaw);
150
+ const bal = decoded[0];
150
151
  return bal;
151
152
  }
152
153
  catch {
@@ -4,6 +4,7 @@
4
4
  import { ethers, Contract } from 'ethers';
5
5
  import { batchCheckAllowances } from './erc20.js';
6
6
  import { ERC20_ABI } from '../abis/common.js';
7
+ import { NonceManager, getOptimizedGasPrice } from './bundle-helpers.js';
7
8
  const APPROVAL_THRESHOLD = ethers.MaxUint256 / 2n;
8
9
  /**
9
10
  * 获取 Gas Limit(授权专用)
@@ -35,7 +36,6 @@ export async function ensureTokenApproval(provider, merkle, wallet, tokenAddress
35
36
  return;
36
37
  }
37
38
  // ✅ 使用 NonceManager(与 pancake-proxy.ts 一致)
38
- const { NonceManager, getOptimizedGasPrice } = await import('./bundle-helpers.js');
39
39
  const nonceManager = new NonceManager(provider);
40
40
  // 构建授权交易
41
41
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, wallet);
@@ -120,7 +120,8 @@ async function _queryMultiTokenBalancesSingle(provider, multicallAddress, tokenA
120
120
  // ✅ 单次 multicall 获取所有数据
121
121
  const callData = multiIface.encodeFunctionData('aggregate', [calls]);
122
122
  const result = await provider.call({ to: multicallAddress, data: callData });
123
- const [, returnData] = multiIface.decodeFunctionResult('aggregate', result);
123
+ const decoded = multiIface.decodeFunctionResult('aggregate', result);
124
+ const returnData = decoded[1];
124
125
  // ✅ 并行解码结果
125
126
  const outputs = holders.map((addr) => ({
126
127
  address: addr,
@@ -213,7 +214,8 @@ async function _querySingleTokenBalancesSingle(provider, multicallAddress, token
213
214
  }));
214
215
  const callData = multiIface.encodeFunctionData('aggregate', [calls]);
215
216
  const result = await provider.call({ to: multicallAddress, data: callData });
216
- const [, returnData] = multiIface.decodeFunctionResult('aggregate', result);
217
+ const decoded = multiIface.decodeFunctionResult('aggregate', result);
218
+ const returnData = decoded[1];
217
219
  return holders.map((addr, i) => {
218
220
  try {
219
221
  const decoded = erc20Iface.decodeFunctionResult('balanceOf', returnData[i]);
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Flap vanity / CREATE2 子路径
3
+ */
4
+ export { findSaltEndingByChain, predictVanityTokenAddress, predictVanityTokenAddressByChain, } from '../shared/flap/vanity.js';
5
+ export { getVanitySuffix } from '../shared/flap/constants.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Flap vanity / CREATE2 子路径
3
+ */
4
+ export { findSaltEndingByChain, predictVanityTokenAddress, predictVanityTokenAddressByChain, } from '../shared/flap/vanity.js';
5
+ export { getVanitySuffix } from '../shared/flap/constants.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -121,6 +121,31 @@
121
121
  "import": "./dist/utils/quote-helpers.js",
122
122
  "default": "./dist/utils/quote-helpers.js"
123
123
  },
124
+ "./merkle": {
125
+ "types": "./dist/merkle/index.d.ts",
126
+ "import": "./dist/merkle/index.js",
127
+ "default": "./dist/merkle/index.js"
128
+ },
129
+ "./vanity": {
130
+ "types": "./dist/vanity/index.d.ts",
131
+ "import": "./dist/vanity/index.js",
132
+ "default": "./dist/vanity/index.js"
133
+ },
134
+ "./shared/flap": {
135
+ "types": "./dist/shared/flap/index.d.ts",
136
+ "import": "./dist/shared/flap/index.js",
137
+ "default": "./dist/shared/flap/index.js"
138
+ },
139
+ "./chains/bsc/iro": {
140
+ "types": "./dist/chains/bsc/iro.d.ts",
141
+ "import": "./dist/chains/bsc/iro.js",
142
+ "default": "./dist/chains/bsc/iro.js"
143
+ },
144
+ "./chains/eni/batch-router": {
145
+ "types": "./dist/chains/eni/batch-router/index.d.ts",
146
+ "import": "./dist/chains/eni/batch-router/index.js",
147
+ "default": "./dist/chains/eni/batch-router/index.js"
148
+ },
124
149
  "./package.json": "./package.json"
125
150
  },
126
151
  "files": [
@@ -136,7 +161,8 @@
136
161
  "format": "prettier --check src/",
137
162
  "format:fix": "prettier --write src/",
138
163
  "test": "vitest run",
139
- "test:watch": "vitest"
164
+ "test:watch": "vitest",
165
+ "build:analyze": "node scripts/build-analyze.mjs"
140
166
  },
141
167
  "keywords": [
142
168
  "flap",
@@ -156,6 +182,7 @@
156
182
  "@ethereumjs/rlp": "^10.1.0",
157
183
  "axios": "^1.12.2",
158
184
  "ethers": "^6.16.0",
185
+ "form-data": "^4.0.2",
159
186
  "pinata": "^1.10.1"
160
187
  },
161
188
  "devDependencies": {