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.
- package/dist/__tests__/subpath-exports.test.js +30 -0
- package/dist/bundle-core/config-helpers.d.ts +5 -5
- package/dist/bundle-core/errors.js +2 -1
- package/dist/chains/bsc/iro.d.ts +5 -0
- package/dist/chains/bsc/iro.js +4 -0
- package/dist/chains/bsc/pancake/bundle-swap-helpers.d.ts +1 -1
- package/dist/chains/bsc/platforms/iro/factory.d.ts +2 -2
- package/dist/chains/eni/bundler/sign.js +1 -2
- package/dist/chains/eni/flat-aliases.d.ts +10 -0
- package/dist/chains/eni/flat-aliases.js +8 -0
- package/dist/chains/eni/index.d.ts +1 -0
- package/dist/chains/eni/index.js +1 -0
- package/dist/chains/eni/platforms/daoaas/meta.js +2 -3
- package/dist/chains/eni/platforms/iro/factory.d.ts +2 -2
- package/dist/chains/xlayer/eip7702/bundle-sell.js +3 -14
- package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
- package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
- package/dist/chains/xlayer/eip7702/index.d.ts +1 -2
- package/dist/chains/xlayer/eip7702/index.js +1 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-helpers.d.ts +1 -1
- package/dist/chains/xlayer/eip7702/multi-hop-transfer.js +13 -14
- package/dist/chains/xlayer/eip7702/volume.js +10 -10
- package/dist/chains/xlayer/index.d.ts +3 -2
- package/dist/chains/xlayer/index.js +4 -7
- package/dist/merkle/index.d.ts +12 -0
- package/dist/merkle/index.js +11 -0
- package/dist/shared/clients/four.d.ts +21 -6
- package/dist/shared/clients/four.js +8 -7
- package/dist/shared/flap/meta.d.ts +7 -1
- package/dist/shared/flap/pinata.d.ts +12 -3
- package/dist/shared/flap/pinata.js +9 -19
- package/dist/shared/flap/portal-bundle-merkle/create-to-dex.d.ts +2 -1
- package/dist/shared/foundation/gas/bundle-gas.d.ts +11 -1
- package/dist/shared/foundation/nonce/nonce-manager.js +4 -1
- package/dist/utils/airdrop-sweep.js +2 -1
- package/dist/utils/swap-helpers.js +1 -1
- package/dist/utils/wallet.js +4 -2
- package/dist/vanity/index.d.ts +5 -0
- package/dist/vanity/index.js +5 -0
- 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?:
|
|
26
|
-
export declare function getProfitRateBps(_config?:
|
|
27
|
-
export declare function getProfitRecipient(_config?:
|
|
28
|
-
export declare function calculateProfit(amount: bigint, _config?:
|
|
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?:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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';
|
package/dist/chains/eni/index.js
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
|
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
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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 &&
|
|
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
|
|
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
|
-
|
|
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<
|
|
128
|
-
getTokenByAddress(address: string, accessToken?: string): Promise<
|
|
129
|
-
getTokensByAddresses(addresses: string[], accessToken?: string): Promise<
|
|
130
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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:
|
|
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 =
|
|
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:
|
|
28
|
+
uploadJSON(obj: PinataJsonUpload, name?: string): Promise<{
|
|
20
29
|
cid: string;
|
|
21
30
|
id: string;
|
|
22
31
|
}>;
|
|
23
|
-
get(cid: string): Promise<
|
|
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.
|
|
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
|
|
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',
|
|
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
|
|
55
|
-
headers: { Authorization: `Bearer ${jwt}`, ...
|
|
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?:
|
|
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
|
|
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
|
|
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);
|
package/dist/utils/wallet.js
CHANGED
|
@@ -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
|
|
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
|
|
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]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "four-flap-meme-sdk",
|
|
3
|
-
"version": "2.1
|
|
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": {
|