four-flap-meme-sdk 4.0.3 → 4.0.5

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 (47) hide show
  1. package/README.en.md +17 -2
  2. package/README.zh-CN.md +17 -2
  3. package/dist/abis/openfour.d.ts +94 -0
  4. package/dist/abis/openfour.js +63 -0
  5. package/dist/bundle/four-meme/core/create-openfour.d.ts +26 -0
  6. package/dist/bundle/four-meme/core/create-openfour.js +121 -0
  7. package/dist/bundle/four-meme/core/create-token.js +3 -0
  8. package/dist/bundle/four-meme/core/index.d.ts +2 -0
  9. package/dist/bundle/four-meme/core/index.js +1 -0
  10. package/dist/bundle/four-meme/private/buy-quote.d.ts +35 -0
  11. package/dist/bundle/four-meme/private/buy-quote.js +70 -0
  12. package/dist/bundle/four-meme/private/buy.js +82 -87
  13. package/dist/bundle/four-meme/private/index.d.ts +2 -0
  14. package/dist/bundle/four-meme/private/index.js +1 -0
  15. package/dist/bundle/four-meme/private/openfour-buy.d.ts +10 -0
  16. package/dist/bundle/four-meme/private/openfour-buy.js +65 -0
  17. package/dist/bundle/four-meme/types/index.d.ts +13 -0
  18. package/dist/chains/bsc/constants.d.ts +1 -0
  19. package/dist/core/clients/four.d.ts +13 -1
  20. package/dist/core/clients/four.js +69 -0
  21. package/dist/core/constants/addresses.d.ts +2 -0
  22. package/dist/core/constants/addresses.js +2 -0
  23. package/dist/domains/flap/ipfs.d.ts +3 -0
  24. package/dist/domains/flap/ipfs.js +20 -1
  25. package/dist/domains/flows/create.d.ts +3 -0
  26. package/dist/domains/flows/create.js +3 -0
  27. package/dist/domains/four/contracts/tm-bundle-create.js +3 -0
  28. package/dist/domains/four/contracts/tm-bundle-helpers.d.ts +3 -0
  29. package/dist/domains/four/tax-token.d.ts +2 -0
  30. package/dist/domains/four/tax-token.js +13 -4
  31. package/dist/domains/four/tax-token.test.d.ts +1 -0
  32. package/dist/domains/four/tax-token.test.js +89 -0
  33. package/dist/domains/openfour/create-arg.d.ts +13 -0
  34. package/dist/domains/openfour/create-arg.js +78 -0
  35. package/dist/domains/openfour/index.d.ts +4 -0
  36. package/dist/domains/openfour/index.js +3 -0
  37. package/dist/domains/openfour/registry.d.ts +4 -0
  38. package/dist/domains/openfour/registry.js +44 -0
  39. package/dist/domains/openfour/schema.d.ts +20 -0
  40. package/dist/domains/openfour/schema.js +88 -0
  41. package/dist/domains/openfour/types.d.ts +79 -0
  42. package/dist/domains/openfour/types.js +1 -0
  43. package/dist/exports/root-bundle-and-tooling.d.ts +4 -2
  44. package/dist/exports/root-bundle-and-tooling.js +2 -2
  45. package/dist/exports/root-foundations.d.ts +1 -0
  46. package/dist/exports/root-foundations.js +1 -0
  47. package/package.json +1 -1
package/README.en.md CHANGED
@@ -410,6 +410,9 @@ const result = await createTokenFlow({
410
410
  webUrl: 'https://example.com',
411
411
  twitterUrl: 'https://twitter.com/...',
412
412
  telegramUrl: 'https://t.me/...',
413
+ githubUrl: 'https://github.com/...',
414
+ youtubeUrl: 'https://youtube.com/...',
415
+ deboxUrl: 'https://debox.pro/...',
413
416
  }
414
417
  });
415
418
 
@@ -443,6 +446,9 @@ console.log('Your address:', result.accountAddress);
443
446
  | `webUrl` | string | ❌ | Project website |
444
447
  | `twitterUrl` | string | ❌ | Twitter/X profile |
445
448
  | `telegramUrl` | string | ❌ | Telegram group/channel |
449
+ | `githubUrl` | string | ❌ | GitHub |
450
+ | `youtubeUrl` | string | ❌ | YouTube |
451
+ | `deboxUrl` | string | ❌ | DeBox |
446
452
 
447
453
  ### Return Value:
448
454
 
@@ -537,6 +543,9 @@ const { createArg, signature } = await four.createToken(accessToken, {
537
543
  webUrl: 'https://...',
538
544
  twitterUrl: 'https://...',
539
545
  telegramUrl: 'https://...',
546
+ githubUrl: 'https://...',
547
+ youtubeUrl: 'https://...',
548
+ deboxUrl: 'https://...',
540
549
  });
541
550
  ```
542
551
 
@@ -1035,7 +1044,10 @@ const { createArg, signature } = await four.createToken(
1035
1044
  onlyMPC?: boolean, // MPC-exclusive flag
1036
1045
  webUrl?: string, // Optional website
1037
1046
  twitterUrl?: string, // Optional Twitter
1038
- telegramUrl?: string // Optional Telegram
1047
+ telegramUrl?: string, // Optional Telegram
1048
+ githubUrl?: string, // Optional GitHub
1049
+ youtubeUrl?: string, // Optional YouTube
1050
+ deboxUrl?: string // Optional DeBox
1039
1051
  }
1040
1052
  );
1041
1053
  ```
@@ -2139,7 +2151,10 @@ const cid = await uploadTokenMeta(
2139
2151
  creator: walletAddress,
2140
2152
  website: 'https://example.com',
2141
2153
  twitter: 'https://x.com/mytoken',
2142
- telegram: 'https://t.me/mytoken'
2154
+ telegram: 'https://t.me/mytoken',
2155
+ github: 'https://github.com/mytoken',
2156
+ youtube: 'https://youtube.com/@mytoken',
2157
+ debox: 'https://debox.pro/mytoken',
2143
2158
  },
2144
2159
  'https://your-ipfs-graphql.example'
2145
2160
  );
package/README.zh-CN.md CHANGED
@@ -425,6 +425,9 @@ const result = await createTokenFlow({
425
425
  webUrl: 'https://example.com',
426
426
  twitterUrl: 'https://twitter.com/...',
427
427
  telegramUrl: 'https://t.me/...',
428
+ githubUrl: 'https://github.com/...',
429
+ youtubeUrl: 'https://youtube.com/...',
430
+ deboxUrl: 'https://debox.pro/...',
428
431
  }
429
432
  });
430
433
 
@@ -460,6 +463,9 @@ console.log('你的地址:', result.accountAddress);
460
463
  | `webUrl` | string | ❌ | 项目网站 |
461
464
  | `twitterUrl` | string | ❌ | Twitter/X 账号 |
462
465
  | `telegramUrl` | string | ❌ | Telegram 群组/频道 |
466
+ | `githubUrl` | string | ❌ | GitHub |
467
+ | `youtubeUrl` | string | ❌ | YouTube |
468
+ | `deboxUrl` | string | ❌ | DeBox |
463
469
 
464
470
  ### 返回值:
465
471
 
@@ -555,6 +561,9 @@ const { createArg, signature } = await four.createToken(accessToken, {
555
561
  webUrl: 'https://...',
556
562
  twitterUrl: 'https://...',
557
563
  telegramUrl: 'https://...',
564
+ githubUrl: 'https://...',
565
+ youtubeUrl: 'https://...',
566
+ deboxUrl: 'https://...',
558
567
  });
559
568
  ```
560
569
 
@@ -1035,7 +1044,10 @@ const { createArg, signature } = await four.createToken(
1035
1044
  onlyMPC?: boolean, // MPC 专属标志
1036
1045
  webUrl?: string, // 可选网站
1037
1046
  twitterUrl?: string, // 可选 Twitter
1038
- telegramUrl?: string // 可选 Telegram
1047
+ telegramUrl?: string, // 可选 Telegram
1048
+ githubUrl?: string, // 可选 GitHub
1049
+ youtubeUrl?: string, // 可选 YouTube
1050
+ deboxUrl?: string // 可选 DeBox
1039
1051
  }
1040
1052
  );
1041
1053
  ```
@@ -2505,7 +2517,10 @@ const cid = await uploadTokenMeta(imageFile as File, {
2505
2517
  creator: yourAddress,
2506
2518
  website: 'https://example.com',
2507
2519
  twitter: 'https://x.com/mytoken',
2508
- telegram: 'https://t.me/mytoken'
2520
+ telegram: 'https://t.me/mytoken',
2521
+ github: 'https://github.com/mytoken',
2522
+ youtube: 'https://youtube.com/@mytoken',
2523
+ debox: 'https://debox.pro/mytoken',
2509
2524
  }, 'https://your-ipfs-graphql.example');
2510
2525
  ```
2511
2526
 
@@ -0,0 +1,94 @@
1
+ /**
2
+ * OpenFour 最小 ABI:Registry 发现、schema 读取、createToken / buyByBudget
3
+ */
4
+ export declare const OPENFOUR_REGISTRY_ABI: string[];
5
+ export declare const OPENFOUR_CORE_ABI: string[];
6
+ export declare const OPENFOUR_TOOLS_ABI: ({
7
+ type: string;
8
+ name: string;
9
+ stateMutability: string;
10
+ inputs: never[];
11
+ outputs: {
12
+ name: string;
13
+ type: string;
14
+ components: readonly [{
15
+ readonly name: "name";
16
+ readonly type: "string";
17
+ }, {
18
+ readonly name: "abiType";
19
+ readonly type: "string";
20
+ }, {
21
+ readonly name: "decimals";
22
+ readonly type: "uint8";
23
+ }, {
24
+ readonly name: "optional";
25
+ readonly type: "bool";
26
+ }, {
27
+ readonly name: "title";
28
+ readonly type: "string";
29
+ }, {
30
+ readonly name: "defaultValue";
31
+ readonly type: "string";
32
+ }, {
33
+ readonly name: "hint";
34
+ readonly type: "string";
35
+ }, {
36
+ readonly name: "minValue";
37
+ readonly type: "string";
38
+ }, {
39
+ readonly name: "maxValue";
40
+ readonly type: "string";
41
+ }];
42
+ }[];
43
+ } | {
44
+ type: string;
45
+ name: string;
46
+ stateMutability: string;
47
+ inputs: {
48
+ name: string;
49
+ type: string;
50
+ }[];
51
+ outputs: {
52
+ name: string;
53
+ type: string;
54
+ components: readonly [{
55
+ readonly name: "kind";
56
+ readonly type: "string";
57
+ }, {
58
+ readonly name: "version";
59
+ readonly type: "uint8";
60
+ }, {
61
+ readonly name: "params";
62
+ readonly type: "tuple[]";
63
+ readonly components: readonly [{
64
+ readonly name: "name";
65
+ readonly type: "string";
66
+ }, {
67
+ readonly name: "abiType";
68
+ readonly type: "string";
69
+ }, {
70
+ readonly name: "decimals";
71
+ readonly type: "uint8";
72
+ }, {
73
+ readonly name: "optional";
74
+ readonly type: "bool";
75
+ }, {
76
+ readonly name: "title";
77
+ readonly type: "string";
78
+ }, {
79
+ readonly name: "defaultValue";
80
+ readonly type: "string";
81
+ }, {
82
+ readonly name: "hint";
83
+ readonly type: "string";
84
+ }, {
85
+ readonly name: "minValue";
86
+ readonly type: "string";
87
+ }, {
88
+ readonly name: "maxValue";
89
+ readonly type: "string";
90
+ }];
91
+ }];
92
+ }[];
93
+ })[];
94
+ export declare const OPENFOUR_WETH_ABI: string[];
@@ -0,0 +1,63 @@
1
+ /**
2
+ * OpenFour 最小 ABI:Registry 发现、schema 读取、createToken / buyByBudget
3
+ */
4
+ const PARAM_COMPONENTS = [
5
+ { name: 'name', type: 'string' },
6
+ { name: 'abiType', type: 'string' },
7
+ { name: 'decimals', type: 'uint8' },
8
+ { name: 'optional', type: 'bool' },
9
+ { name: 'title', type: 'string' },
10
+ { name: 'defaultValue', type: 'string' },
11
+ { name: 'hint', type: 'string' },
12
+ { name: 'minValue', type: 'string' },
13
+ { name: 'maxValue', type: 'string' },
14
+ ];
15
+ const MODULE_SCHEMA_COMPONENTS = [
16
+ { name: 'kind', type: 'string' },
17
+ { name: 'version', type: 'uint8' },
18
+ { name: 'params', type: 'tuple[]', components: PARAM_COMPONENTS },
19
+ ];
20
+ export const OPENFOUR_REGISTRY_ABI = [
21
+ 'function openFourCore() view returns (address)',
22
+ 'function openFourTool() view returns (address)',
23
+ 'function isPresetActive(uint256 presetId) view returns (bool)',
24
+ 'function isPresetCreateEnabled(uint256 presetId) view returns (bool)',
25
+ ];
26
+ export const OPENFOUR_CORE_ABI = [
27
+ 'function createToken(bytes createArgs, bytes signature) payable returns (address token)',
28
+ 'function wrappedNative() view returns (address)',
29
+ 'function feeRouter() view returns (address)',
30
+ 'function zapRouter() view returns (address)',
31
+ 'function buyByBudget(address token, uint256 maxPayAmount, uint256 minAmountOut, uint256 options, bytes proof) payable',
32
+ 'function buy(address token, uint256 amount, uint256 maxPayAmount, uint256 options, bytes proof) payable',
33
+ 'event TokenCreated(address indexed token, address indexed creator, uint256 indexed presetId)',
34
+ ];
35
+ export const OPENFOUR_TOOLS_ABI = [
36
+ {
37
+ type: 'function',
38
+ name: 'getTokenBaseSchema',
39
+ stateMutability: 'pure',
40
+ inputs: [],
41
+ outputs: [{ name: '', type: 'tuple[]', components: PARAM_COMPONENTS }],
42
+ },
43
+ {
44
+ type: 'function',
45
+ name: 'getPresetEncodeSchemas',
46
+ stateMutability: 'view',
47
+ inputs: [{ name: 'presetId', type: 'uint256' }],
48
+ outputs: [
49
+ { name: 'tokenSchema', type: 'tuple', components: MODULE_SCHEMA_COMPONENTS },
50
+ { name: 'vaultSchema', type: 'tuple', components: MODULE_SCHEMA_COMPONENTS },
51
+ { name: 'curveSchema', type: 'tuple', components: MODULE_SCHEMA_COMPONENTS },
52
+ { name: 'tradeSchema', type: 'tuple', components: MODULE_SCHEMA_COMPONENTS },
53
+ { name: 'migrateSchema', type: 'tuple', components: MODULE_SCHEMA_COMPONENTS },
54
+ { name: 'customDataSchema', type: 'tuple', components: MODULE_SCHEMA_COMPONENTS },
55
+ ],
56
+ },
57
+ ];
58
+ export const OPENFOUR_WETH_ABI = [
59
+ 'function deposit() payable',
60
+ 'function approve(address spender, uint256 amount) returns (bool)',
61
+ 'function allowance(address owner, address spender) view returns (uint256)',
62
+ 'function decimals() view returns (uint8)',
63
+ ];
@@ -0,0 +1,26 @@
1
+ import type { FourCreateWithBundleBuyMerkleResult, FourSignConfig } from '../types/index.js';
2
+ import { type OpenFourInitParams, type OpenFourTemplateConfig } from '../../../domains/openfour/index.js';
3
+ export type OpenFourCreateSignParams = {
4
+ privateKeys: string[];
5
+ tokenInfo: {
6
+ name: string;
7
+ symbol: string;
8
+ description: string;
9
+ imageUrl?: string;
10
+ imageFile?: Blob;
11
+ webUrl?: string;
12
+ twitterUrl?: string;
13
+ telegramUrl?: string;
14
+ githubUrl?: string;
15
+ youtubeUrl?: string;
16
+ deboxUrl?: string;
17
+ preSale?: string;
18
+ feePlan?: boolean;
19
+ templateId: number | string;
20
+ quoteSymbol: string;
21
+ templateConfig: OpenFourTemplateConfig;
22
+ initParams: OpenFourInitParams;
23
+ };
24
+ config: FourSignConfig;
25
+ };
26
+ export declare function createOpenFourTokenMerkle(params: OpenFourCreateSignParams): Promise<FourCreateWithBundleBuyMerkleResult>;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * OpenFour 发币:业务 API 拿 createArg + signature,再签 OpenFourCore.createToken
3
+ */
4
+ import { Contract, Wallet } from 'ethers';
5
+ import { getGasLimit } from '../../../core/gas/bundle-gas.js';
6
+ import { NonceManager, getOptimizedGasPrice } from '../../../utils/bundle-helpers.js';
7
+ import { ZERO_ADDRESS } from '../../../core/constants/index.js';
8
+ import { FourClient } from '../../../core/clients/four.js';
9
+ import { getTxType, getGasPriceConfig, getBribeAmount } from '../../config-helpers.js';
10
+ import { signBribeTransaction } from '../../../core/sign-context-helpers.js';
11
+ import { createChainContext, loginFourClient, resolveTokenImage } from '../core-helpers.js';
12
+ import { OPENFOUR_CORE_ABI } from '../../../abis/openfour.js';
13
+ import { computeOpenFourCreateValueWei, decodeOpenFourCreateArg, isOpenFourPresaleNative, loadOpenFourAddresses, } from '../../../domains/openfour/index.js';
14
+ import { signQuoteApproveIfNeeded } from './create-token-quote.js';
15
+ function toRaisedToken(cfg) {
16
+ return {
17
+ symbol: cfg.symbol,
18
+ nativeSymbol: cfg.symbol,
19
+ symbolAddress: cfg.symbolAddress,
20
+ deployCost: cfg.createFee || '0',
21
+ buyFee: '0',
22
+ sellFee: '0',
23
+ minTradeFee: '0',
24
+ b0Amount: '0',
25
+ totalBAmount: cfg.raisedAmount,
26
+ totalAmount: cfg.totalSupply,
27
+ logoUrl: '',
28
+ tradeLevel: [],
29
+ status: 'PUBLISH',
30
+ buyTokenLink: '',
31
+ reservedNumber: 0,
32
+ saleRate: '0.8',
33
+ networkCode: 'BSC',
34
+ platform: 'MEME',
35
+ };
36
+ }
37
+ export async function createOpenFourTokenMerkle(params) {
38
+ const { privateKeys, tokenInfo, config } = params;
39
+ if (privateKeys.length !== 1) {
40
+ throw new Error('OpenFour 发币只支持 1 个 Dev 钱包');
41
+ }
42
+ const rpcUrl = config.rpcUrl || 'https://bsc-dataseed.binance.org';
43
+ const { provider, chainId } = createChainContext(rpcUrl);
44
+ const devWallet = new Wallet(privateKeys[0], provider);
45
+ const fourClient = new FourClient({ baseUrl: config.fourApiUrl });
46
+ const accessToken = await loginFourClient(devWallet, fourClient);
47
+ const imgUrl = await resolveTokenImage(fourClient, tokenInfo, accessToken);
48
+ const preSale = String(tokenInfo.preSale || '0').trim() || '0';
49
+ const cfg = tokenInfo.templateConfig;
50
+ const body = {
51
+ templateId: tokenInfo.templateId,
52
+ name: tokenInfo.name,
53
+ shortName: tokenInfo.symbol,
54
+ symbol: cfg.symbol,
55
+ desc: tokenInfo.description,
56
+ imgUrl,
57
+ webUrl: tokenInfo.webUrl,
58
+ twitterUrl: tokenInfo.twitterUrl,
59
+ telegramUrl: tokenInfo.telegramUrl,
60
+ githubUrl: tokenInfo.githubUrl,
61
+ youtubeUrl: tokenInfo.youtubeUrl,
62
+ deboxUrl: tokenInfo.deboxUrl,
63
+ presaleQuote: preSale,
64
+ feePlan: Boolean(tokenInfo.feePlan),
65
+ initParams: tokenInfo.initParams,
66
+ saleAmount: cfg.saleAmount,
67
+ totalSupply: cfg.totalSupply,
68
+ raisedAmount: cfg.raisedAmount,
69
+ };
70
+ const createResp = await fourClient.createOpenFourToken(accessToken, body);
71
+ const addrs = await loadOpenFourAddresses(provider);
72
+ const decoded = decodeOpenFourCreateArg(createResp.createArg);
73
+ const valueWei = computeOpenFourCreateValueWei(decoded, addrs.wrappedNative);
74
+ const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
75
+ const nonceManager = new NonceManager(provider);
76
+ const txType = getTxType(config);
77
+ const signedTxs = [];
78
+ const bribeAmount = getBribeAmount(config);
79
+ if (bribeAmount > 0n) {
80
+ const bribeNonce = await nonceManager.getNextNonce(devWallet);
81
+ signedTxs.push(await signBribeTransaction(devWallet, bribeAmount, bribeNonce, gasPrice, chainId, txType));
82
+ }
83
+ const nativePresale = isOpenFourPresaleNative({
84
+ presaleQuote: decoded.presaleQuote,
85
+ quoteAsset: decoded.quoteAsset,
86
+ wrappedNative: addrs.wrappedNative,
87
+ });
88
+ if (!nativePresale && decoded.presaleQuote > 0n) {
89
+ const approveTx = await signQuoteApproveIfNeeded({
90
+ raisedToken: toRaisedToken(cfg),
91
+ preSale,
92
+ wallet: devWallet,
93
+ spender: addrs.core,
94
+ getNonce: () => nonceManager.getNextNonce(devWallet),
95
+ gasPrice,
96
+ chainId,
97
+ txType,
98
+ });
99
+ if (approveTx)
100
+ signedTxs.push(approveTx);
101
+ }
102
+ const core = new Contract(addrs.core, OPENFOUR_CORE_ABI, devWallet);
103
+ const unsigned = await core.createToken.populateTransaction(createResp.createArg, createResp.signature, {
104
+ value: valueWei,
105
+ });
106
+ signedTxs.push(await devWallet.signTransaction({
107
+ ...unsigned,
108
+ from: devWallet.address,
109
+ nonce: await nonceManager.getNextNonce(devWallet),
110
+ gasLimit: getGasLimit(config, 2_000_000),
111
+ gasPrice,
112
+ chainId,
113
+ type: txType,
114
+ value: valueWei,
115
+ }));
116
+ nonceManager.clearTemp();
117
+ return {
118
+ signedTransactions: signedTxs,
119
+ tokenAddress: ZERO_ADDRESS,
120
+ };
121
+ }
@@ -41,6 +41,9 @@ export async function createTokenWithBundleBuyMerkle(params) {
41
41
  webUrl: tokenInfo.webUrl,
42
42
  twitterUrl: tokenInfo.twitterUrl,
43
43
  telegramUrl: tokenInfo.telegramUrl,
44
+ githubUrl: tokenInfo.githubUrl,
45
+ youtubeUrl: tokenInfo.youtubeUrl,
46
+ deboxUrl: tokenInfo.deboxUrl,
44
47
  preSale: effectivePreSaleStr || '0',
45
48
  onlyMPC: false,
46
49
  ...(tokenInfo.feePlan ? { feePlan: true } : {}),
@@ -10,5 +10,7 @@
10
10
  * 对外 export 符号与路径保持不变。
11
11
  */
12
12
  export { createTokenWithBundleBuyMerkle } from './create-token.js';
13
+ export { createOpenFourTokenMerkle } from './create-openfour.js';
14
+ export type { OpenFourCreateSignParams } from './create-openfour.js';
13
15
  export { batchBuyWithBundleMerkle } from './buy-flow.js';
14
16
  export { batchSellWithBundleMerkle } from './sell-flow.js';
@@ -10,5 +10,6 @@
10
10
  * 对外 export 符号与路径保持不变。
11
11
  */
12
12
  export { createTokenWithBundleBuyMerkle } from './create-token.js';
13
+ export { createOpenFourTokenMerkle } from './create-openfour.js';
13
14
  export { batchBuyWithBundleMerkle } from './buy-flow.js';
14
15
  export { batchSellWithBundleMerkle } from './sell-flow.js';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Four TokenManager 买入付款:BNB 走 msg.value;ERC20 计价走 approve + funds
3
+ */
4
+ import { Wallet, type JsonRpcProvider } from 'ethers';
5
+ import { NonceManager } from '../../../utils/bundle-helpers.js';
6
+ export type FourBuyQuoteInput = {
7
+ /** ERC20 计价地址;不传则按 BNB */
8
+ quoteTokenAddress?: string;
9
+ quoteDecimals?: number;
10
+ };
11
+ export type FourBuyPayment = {
12
+ fundsWei: bigint;
13
+ valueWei: bigint;
14
+ quoteAddress?: string;
15
+ approvalWei: bigint;
16
+ };
17
+ export declare function isFourErc20BuyQuote(quoteTokenAddress?: string): boolean;
18
+ export declare function resolveQuoteDecimals(provider: JsonRpcProvider, quote: FourBuyQuoteInput): Promise<number>;
19
+ export declare function resolveFourBuyPayment(params: {
20
+ provider: JsonRpcProvider;
21
+ tokenAddress: string;
22
+ funds: string;
23
+ quote?: FourBuyQuoteInput;
24
+ }): Promise<FourBuyPayment>;
25
+ export declare function signQuoteApproveTxs(params: {
26
+ wallets: Wallet[];
27
+ quoteAddress: string;
28
+ spender: string;
29
+ amounts: bigint[];
30
+ nonceManager: NonceManager;
31
+ gasPrice: bigint;
32
+ chainId: number;
33
+ txType: number;
34
+ provider: JsonRpcProvider;
35
+ }): Promise<string[]>;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Four TokenManager 买入付款:BNB 走 msg.value;ERC20 计价走 approve + funds
3
+ */
4
+ import { Contract, parseEther, parseUnits } from 'ethers';
5
+ import { ADDRESSES, ZERO_ADDRESS } from '../../../core/constants/index.js';
6
+ import { ERC20_ABI } from '../../../abis/common.js';
7
+ import { batchCheckAllowances } from '../../../core/erc20/index.js';
8
+ const HELPER_TRY_BUY_ABI = [
9
+ 'function tryBuy(address token, uint256 amount, uint256 funds) view returns (address tokenManager, address quote, uint256 estimatedAmount, uint256 estimatedCost, uint256 estimatedFee, uint256 amountMsgValue, uint256 amountApproval, uint256 amountFunds)',
10
+ ];
11
+ export function isFourErc20BuyQuote(quoteTokenAddress) {
12
+ if (!quoteTokenAddress)
13
+ return false;
14
+ return quoteTokenAddress.toLowerCase() !== ZERO_ADDRESS.toLowerCase();
15
+ }
16
+ export async function resolveQuoteDecimals(provider, quote) {
17
+ if (quote.quoteDecimals != null)
18
+ return quote.quoteDecimals;
19
+ if (!isFourErc20BuyQuote(quote.quoteTokenAddress))
20
+ return 18;
21
+ const token = new Contract(quote.quoteTokenAddress, ERC20_ABI, provider);
22
+ return Number(await token.decimals());
23
+ }
24
+ export async function resolveFourBuyPayment(params) {
25
+ const quote = params.quote ?? {};
26
+ if (!isFourErc20BuyQuote(quote.quoteTokenAddress)) {
27
+ const fundsWei = parseEther(params.funds);
28
+ return { fundsWei, valueWei: fundsWei, approvalWei: 0n };
29
+ }
30
+ const decimals = await resolveQuoteDecimals(params.provider, quote);
31
+ const fundsWei = parseUnits(params.funds, decimals);
32
+ const quoteAddress = quote.quoteTokenAddress;
33
+ try {
34
+ const helper = new Contract(ADDRESSES.BSC.TokenManagerHelper3, HELPER_TRY_BUY_ABI, params.provider);
35
+ const preview = await helper.tryBuy(params.tokenAddress, 0n, fundsWei);
36
+ const amountFunds = preview.amountFunds > 0n ? preview.amountFunds : fundsWei;
37
+ return {
38
+ fundsWei: amountFunds,
39
+ valueWei: preview.amountMsgValue,
40
+ quoteAddress: preview.quote || quoteAddress,
41
+ approvalWei: preview.amountApproval,
42
+ };
43
+ }
44
+ catch {
45
+ return { fundsWei, valueWei: 0n, quoteAddress, approvalWei: fundsWei };
46
+ }
47
+ }
48
+ export async function signQuoteApproveTxs(params) {
49
+ const { wallets, quoteAddress, spender, amounts, nonceManager, gasPrice, chainId, txType, provider } = params;
50
+ if (wallets.length === 0)
51
+ return [];
52
+ const allowances = await batchCheckAllowances(provider, quoteAddress, wallets.map((w) => w.address), spender);
53
+ const signed = [];
54
+ for (let i = 0; i < wallets.length; i++) {
55
+ if (allowances[i] >= amounts[i])
56
+ continue;
57
+ const token = new Contract(quoteAddress, ERC20_ABI, wallets[i]);
58
+ const unsigned = await token.approve.populateTransaction(spender, amounts[i]);
59
+ signed.push(await wallets[i].signTransaction({
60
+ ...unsigned,
61
+ from: wallets[i].address,
62
+ nonce: await nonceManager.getNextNonce(wallets[i]),
63
+ gasLimit: 80000n,
64
+ gasPrice,
65
+ chainId,
66
+ type: txType,
67
+ }));
68
+ }
69
+ return signed;
70
+ }