four-flap-meme-sdk 4.0.2 → 4.0.4
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/abis/openfour.d.ts +94 -0
- package/dist/abis/openfour.js +63 -0
- package/dist/bundle/four-meme/core/constants.js +1 -0
- package/dist/bundle/four-meme/core/create-openfour.d.ts +23 -0
- package/dist/bundle/four-meme/core/create-openfour.js +118 -0
- package/dist/bundle/four-meme/core/create-token-quote.d.ts +24 -0
- package/dist/bundle/four-meme/core/create-token-quote.js +53 -0
- package/dist/bundle/four-meme/core/create-token.js +28 -39
- package/dist/bundle/four-meme/core/index.d.ts +2 -0
- package/dist/bundle/four-meme/core/index.js +1 -0
- package/dist/bundle/four-meme/private/buy-quote.d.ts +35 -0
- package/dist/bundle/four-meme/private/buy-quote.js +70 -0
- package/dist/bundle/four-meme/private/buy.js +82 -87
- package/dist/bundle/four-meme/private/index.d.ts +2 -0
- package/dist/bundle/four-meme/private/index.js +1 -0
- package/dist/bundle/four-meme/private/openfour-buy.d.ts +10 -0
- package/dist/bundle/four-meme/private/openfour-buy.js +65 -0
- package/dist/bundle/four-meme/types/index.d.ts +13 -0
- package/dist/chains/bsc/constants.d.ts +1 -0
- package/dist/core/clients/four.d.ts +25 -17
- package/dist/core/clients/four.js +128 -3
- package/dist/core/clients/index.d.ts +1 -1
- package/dist/core/clients/index.js +1 -1
- package/dist/core/constants/addresses.d.ts +2 -0
- package/dist/core/constants/addresses.js +2 -0
- package/dist/domains/flows/create.d.ts +1 -0
- package/dist/domains/flows/create.js +13 -12
- package/dist/domains/four/contracts/tm-bundle-create.js +42 -11
- package/dist/domains/four/contracts/tm-bundle-helpers.d.ts +6 -0
- package/dist/domains/four/index.d.ts +1 -0
- package/dist/domains/four/index.js +1 -0
- package/dist/domains/four/raised-token.d.ts +38 -0
- package/dist/domains/four/raised-token.js +75 -0
- package/dist/domains/four/raised-token.test.d.ts +1 -0
- package/dist/domains/four/raised-token.test.js +43 -0
- package/dist/domains/four/tax-token.d.ts +2 -0
- package/dist/domains/four/tax-token.js +13 -4
- package/dist/domains/four/tax-token.test.d.ts +1 -0
- package/dist/domains/four/tax-token.test.js +89 -0
- package/dist/domains/openfour/create-arg.d.ts +13 -0
- package/dist/domains/openfour/create-arg.js +78 -0
- package/dist/domains/openfour/index.d.ts +4 -0
- package/dist/domains/openfour/index.js +3 -0
- package/dist/domains/openfour/registry.d.ts +4 -0
- package/dist/domains/openfour/registry.js +44 -0
- package/dist/domains/openfour/schema.d.ts +20 -0
- package/dist/domains/openfour/schema.js +88 -0
- package/dist/domains/openfour/types.d.ts +76 -0
- package/dist/domains/openfour/types.js +1 -0
- package/dist/exports/root-bundle-and-tooling.d.ts +4 -2
- package/dist/exports/root-bundle-and-tooling.js +2 -2
- package/dist/exports/root-foundations.d.ts +3 -1
- package/dist/exports/root-foundations.js +3 -1
- package/package.json +1 -1
|
@@ -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
|
+
];
|
|
@@ -10,6 +10,7 @@ export const MULTICALL3_ADDRESS = ADDRESSES.BSC.Multicall3;
|
|
|
10
10
|
export const TM2_ABI = [
|
|
11
11
|
..._TM2_ABI,
|
|
12
12
|
'function createToken(bytes args, bytes signature) payable',
|
|
13
|
+
'function _launchFee() view returns (uint256)',
|
|
13
14
|
'event TokenCreate(address indexed creator, address indexed token, uint256 timestamp)',
|
|
14
15
|
];
|
|
15
16
|
export const PLATFORM_CREATE_FEE = ethers.parseEther('0.01');
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
preSale?: string;
|
|
15
|
+
feePlan?: boolean;
|
|
16
|
+
templateId: number | string;
|
|
17
|
+
quoteSymbol: string;
|
|
18
|
+
templateConfig: OpenFourTemplateConfig;
|
|
19
|
+
initParams: OpenFourInitParams;
|
|
20
|
+
};
|
|
21
|
+
config: FourSignConfig;
|
|
22
|
+
};
|
|
23
|
+
export declare function createOpenFourTokenMerkle(params: OpenFourCreateSignParams): Promise<FourCreateWithBundleBuyMerkleResult>;
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
presaleQuote: preSale,
|
|
61
|
+
feePlan: Boolean(tokenInfo.feePlan),
|
|
62
|
+
initParams: tokenInfo.initParams,
|
|
63
|
+
saleAmount: cfg.saleAmount,
|
|
64
|
+
totalSupply: cfg.totalSupply,
|
|
65
|
+
raisedAmount: cfg.raisedAmount,
|
|
66
|
+
};
|
|
67
|
+
const createResp = await fourClient.createOpenFourToken(accessToken, body);
|
|
68
|
+
const addrs = await loadOpenFourAddresses(provider);
|
|
69
|
+
const decoded = decodeOpenFourCreateArg(createResp.createArg);
|
|
70
|
+
const valueWei = computeOpenFourCreateValueWei(decoded, addrs.wrappedNative);
|
|
71
|
+
const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
|
|
72
|
+
const nonceManager = new NonceManager(provider);
|
|
73
|
+
const txType = getTxType(config);
|
|
74
|
+
const signedTxs = [];
|
|
75
|
+
const bribeAmount = getBribeAmount(config);
|
|
76
|
+
if (bribeAmount > 0n) {
|
|
77
|
+
const bribeNonce = await nonceManager.getNextNonce(devWallet);
|
|
78
|
+
signedTxs.push(await signBribeTransaction(devWallet, bribeAmount, bribeNonce, gasPrice, chainId, txType));
|
|
79
|
+
}
|
|
80
|
+
const nativePresale = isOpenFourPresaleNative({
|
|
81
|
+
presaleQuote: decoded.presaleQuote,
|
|
82
|
+
quoteAsset: decoded.quoteAsset,
|
|
83
|
+
wrappedNative: addrs.wrappedNative,
|
|
84
|
+
});
|
|
85
|
+
if (!nativePresale && decoded.presaleQuote > 0n) {
|
|
86
|
+
const approveTx = await signQuoteApproveIfNeeded({
|
|
87
|
+
raisedToken: toRaisedToken(cfg),
|
|
88
|
+
preSale,
|
|
89
|
+
wallet: devWallet,
|
|
90
|
+
spender: addrs.core,
|
|
91
|
+
getNonce: () => nonceManager.getNextNonce(devWallet),
|
|
92
|
+
gasPrice,
|
|
93
|
+
chainId,
|
|
94
|
+
txType,
|
|
95
|
+
});
|
|
96
|
+
if (approveTx)
|
|
97
|
+
signedTxs.push(approveTx);
|
|
98
|
+
}
|
|
99
|
+
const core = new Contract(addrs.core, OPENFOUR_CORE_ABI, devWallet);
|
|
100
|
+
const unsigned = await core.createToken.populateTransaction(createResp.createArg, createResp.signature, {
|
|
101
|
+
value: valueWei,
|
|
102
|
+
});
|
|
103
|
+
signedTxs.push(await devWallet.signTransaction({
|
|
104
|
+
...unsigned,
|
|
105
|
+
from: devWallet.address,
|
|
106
|
+
nonce: await nonceManager.getNextNonce(devWallet),
|
|
107
|
+
gasLimit: getGasLimit(config, 2_000_000),
|
|
108
|
+
gasPrice,
|
|
109
|
+
chainId,
|
|
110
|
+
type: txType,
|
|
111
|
+
value: valueWei,
|
|
112
|
+
}));
|
|
113
|
+
nonceManager.clearTemp();
|
|
114
|
+
return {
|
|
115
|
+
signedTransactions: signedTxs,
|
|
116
|
+
tokenAddress: ZERO_ADDRESS,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Four.meme 发币:计价币、create value、ERC20 预购授权
|
|
3
|
+
*/
|
|
4
|
+
import { ethers, Wallet } from 'ethers';
|
|
5
|
+
import { FourClient, buildCreateTokenReq, type CreateTokenCustom } from '../../../core/clients/four.js';
|
|
6
|
+
import { type FourRaisedToken } from '../../../domains/four/raised-token.js';
|
|
7
|
+
export type FourLaunchQuoteInfo = {
|
|
8
|
+
quoteSymbol?: string;
|
|
9
|
+
raisedToken?: FourRaisedToken;
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveCreateRaisedToken(fourClient: FourClient, tokenInfo: FourLaunchQuoteInfo): Promise<FourRaisedToken>;
|
|
12
|
+
export declare function readLaunchFeeWei(tm: ethers.Contract): Promise<bigint>;
|
|
13
|
+
export declare function fourCreateValueWei(raisedToken: FourRaisedToken, preSale: string, launchFeeWei: bigint): bigint;
|
|
14
|
+
export declare function signQuoteApproveIfNeeded(params: {
|
|
15
|
+
raisedToken: FourRaisedToken;
|
|
16
|
+
preSale: string;
|
|
17
|
+
wallet: Wallet;
|
|
18
|
+
spender: string;
|
|
19
|
+
getNonce: () => Promise<number>;
|
|
20
|
+
gasPrice: bigint;
|
|
21
|
+
chainId: number;
|
|
22
|
+
txType: number;
|
|
23
|
+
}): Promise<string | undefined>;
|
|
24
|
+
export declare function fourCreateApiBody(custom: CreateTokenCustom, raisedToken: FourRaisedToken): ReturnType<typeof buildCreateTokenReq>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Four.meme 发币:计价币、create value、ERC20 预购授权
|
|
3
|
+
*/
|
|
4
|
+
import { ethers } from 'ethers';
|
|
5
|
+
import { ERC20_ABI } from '../../../abis/common.js';
|
|
6
|
+
import { buildCreateTokenReq } from '../../../core/clients/four.js';
|
|
7
|
+
import { computeFourCreateValueWei, isNativeRaisedToken, } from '../../../domains/four/raised-token.js';
|
|
8
|
+
import { PLATFORM_CREATE_FEE } from './constants.js';
|
|
9
|
+
export async function resolveCreateRaisedToken(fourClient, tokenInfo) {
|
|
10
|
+
if (tokenInfo.raisedToken)
|
|
11
|
+
return tokenInfo.raisedToken;
|
|
12
|
+
return fourClient.resolveRaisedToken(tokenInfo.quoteSymbol);
|
|
13
|
+
}
|
|
14
|
+
export async function readLaunchFeeWei(tm) {
|
|
15
|
+
try {
|
|
16
|
+
const fee = await tm._launchFee();
|
|
17
|
+
if (typeof fee === 'bigint' && fee > 0n)
|
|
18
|
+
return fee;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// 合约未暴露或 RPC 失败时用官网当前档 0.01 BNB
|
|
22
|
+
}
|
|
23
|
+
return PLATFORM_CREATE_FEE;
|
|
24
|
+
}
|
|
25
|
+
export function fourCreateValueWei(raisedToken, preSale, launchFeeWei) {
|
|
26
|
+
return computeFourCreateValueWei({ raisedToken, preSale, launchFeeWei });
|
|
27
|
+
}
|
|
28
|
+
export async function signQuoteApproveIfNeeded(params) {
|
|
29
|
+
if (isNativeRaisedToken(params.raisedToken))
|
|
30
|
+
return undefined;
|
|
31
|
+
const preSale = String(params.preSale || '').trim() || '0';
|
|
32
|
+
if (preSale === '0')
|
|
33
|
+
return undefined;
|
|
34
|
+
const token = new ethers.Contract(params.raisedToken.symbolAddress, ERC20_ABI, params.wallet);
|
|
35
|
+
const decimals = Number(await token.decimals());
|
|
36
|
+
const amount = ethers.parseUnits(preSale, decimals);
|
|
37
|
+
const allowance = await token.allowance(params.wallet.address, params.spender);
|
|
38
|
+
if (allowance >= amount)
|
|
39
|
+
return undefined;
|
|
40
|
+
const unsigned = await token.approve.populateTransaction(params.spender, amount);
|
|
41
|
+
return params.wallet.signTransaction({
|
|
42
|
+
...unsigned,
|
|
43
|
+
from: params.wallet.address,
|
|
44
|
+
nonce: await params.getNonce(),
|
|
45
|
+
gasLimit: 80000n,
|
|
46
|
+
gasPrice: params.gasPrice,
|
|
47
|
+
chainId: params.chainId,
|
|
48
|
+
type: params.txType,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function fourCreateApiBody(custom, raisedToken) {
|
|
52
|
+
return buildCreateTokenReq(custom, raisedToken);
|
|
53
|
+
}
|
|
@@ -9,10 +9,11 @@ import { FourClient } from '../../../core/clients/four.js';
|
|
|
9
9
|
import { getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount, } from '../../config-helpers.js';
|
|
10
10
|
import { signBribeTransaction } from '../../../core/sign-context-helpers.js';
|
|
11
11
|
import { createChainContext, loginFourClient, resolveTokenImage } from '../core-helpers.js';
|
|
12
|
-
import { TM2_ABI
|
|
12
|
+
import { TM2_ABI } from './constants.js';
|
|
13
|
+
import { fourCreateApiBody, fourCreateValueWei, readLaunchFeeWei, resolveCreateRaisedToken, signQuoteApproveIfNeeded, } from './create-token-quote.js';
|
|
14
|
+
import { isNativeRaisedToken } from '../../../domains/four/raised-token.js';
|
|
13
15
|
export async function createTokenWithBundleBuyMerkle(params) {
|
|
14
16
|
const { privateKeys, buyAmounts, tokenInfo, config } = params;
|
|
15
|
-
// ⚠️ 限制: 只支持创建者买入,不支持其他钱包
|
|
16
17
|
if (privateKeys.length !== 1) {
|
|
17
18
|
throw new Error('只支持创建者买入,privateKeys 只能有1个元素');
|
|
18
19
|
}
|
|
@@ -20,20 +21,17 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
20
21
|
throw new Error('只支持买入一次,buyAmounts 只能有1个元素');
|
|
21
22
|
}
|
|
22
23
|
const creatorKey = privateKeys[0];
|
|
23
|
-
// ✅ 使用公共 BSC RPC 节点(支持浏览器 CORS)
|
|
24
|
-
// 48.club 的 RPC 不支持浏览器跨域访问,所以使用公共节点进行余额查询和 gas 估算
|
|
25
24
|
const rpcUrl = config.rpcUrl || 'https://bsc-dataseed.binance.org';
|
|
26
25
|
const { provider, chainId } = createChainContext(rpcUrl);
|
|
27
26
|
const devWallet = new Wallet(creatorKey, provider);
|
|
28
27
|
const fourClient = new FourClient({ baseUrl: config.fourApiUrl });
|
|
29
28
|
const accessToken = await loginFourClient(devWallet, fourClient);
|
|
30
29
|
const imgUrl = await resolveTokenImage(fourClient, tokenInfo, accessToken);
|
|
31
|
-
// ✅ 兼容:历史调用可能把 Dev 首买金额塞在 buyAmounts[0],而不是 tokenInfo.preSale
|
|
32
|
-
// Four 官方 API/链上 createArg 使用 preSale 表达“创建者预购金额”
|
|
33
30
|
const effectivePreSaleStr = tokenInfo.preSale && String(tokenInfo.preSale).trim().length > 0
|
|
34
31
|
? String(tokenInfo.preSale)
|
|
35
32
|
: String(buyAmounts[0] ?? '0');
|
|
36
|
-
const
|
|
33
|
+
const raisedToken = await resolveCreateRaisedToken(fourClient, tokenInfo);
|
|
34
|
+
const createResp = await fourClient.createToken(accessToken, fourCreateApiBody({
|
|
37
35
|
name: tokenInfo.name,
|
|
38
36
|
shortName: tokenInfo.symbol,
|
|
39
37
|
desc: tokenInfo.description,
|
|
@@ -45,49 +43,43 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
45
43
|
telegramUrl: tokenInfo.telegramUrl,
|
|
46
44
|
preSale: effectivePreSaleStr || '0',
|
|
47
45
|
onlyMPC: false,
|
|
48
|
-
// ✅ AntiSniperFeeMode(开盘高税模式)
|
|
49
46
|
...(tokenInfo.feePlan ? { feePlan: true } : {}),
|
|
50
|
-
// ✅ 税币配置(Tax Token, creatorType=5)
|
|
51
47
|
...(tokenInfo.tokenTaxInfo ? { tokenTaxInfo: tokenInfo.tokenTaxInfo } : {}),
|
|
52
|
-
|
|
53
|
-
symbol: 'BNB',
|
|
54
|
-
totalSupply: 1000000000,
|
|
55
|
-
raisedAmount: 24,
|
|
56
|
-
saleRate: 0.8,
|
|
57
|
-
reserveRate: 0,
|
|
58
|
-
funGroup: false,
|
|
59
|
-
clickFun: false,
|
|
60
|
-
});
|
|
48
|
+
}, raisedToken));
|
|
61
49
|
const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
|
|
62
50
|
const nonceManager = new NonceManager(provider);
|
|
63
51
|
const txType = getTxType(config);
|
|
64
52
|
const signedTxs = [];
|
|
65
53
|
const tmCreateAddr = ADDRESSES.BSC.TokenManagerOriginal;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const originalBuyAmount = ethers.parseEther(effectivePreSaleStr || '0');
|
|
54
|
+
const extractProfit = shouldExtractProfit() && isNativeRaisedToken(raisedToken);
|
|
55
|
+
const originalBuyAmount = isNativeRaisedToken(raisedToken)
|
|
56
|
+
? ethers.parseEther(effectivePreSaleStr || '0')
|
|
57
|
+
: 0n;
|
|
71
58
|
const profitAmount = extractProfit ? calculateProfit(originalBuyAmount).profit : 0n;
|
|
72
|
-
// ✅ 获取贿赂金额
|
|
73
59
|
const bribeAmount = getBribeAmount(config);
|
|
74
60
|
const needBribeTx = bribeAmount > 0n;
|
|
75
|
-
const b0AmountWei = ethers.parseEther(params.b0Amount ?? '0');
|
|
76
|
-
const preSaleWei = effectivePreSaleStr ? ethers.parseEther(effectivePreSaleStr) : 0n;
|
|
77
|
-
// ✅ 关键修复:
|
|
78
|
-
// createToken 的预购金额由 createArg.preSale 决定;因此这里只需要支付:创建费 + b0Amount + preSale
|
|
79
|
-
// 不要把“其它买入金额”额外塞进 msg.value,否则会被合约退回,造成“看起来没买到”的误解。
|
|
80
|
-
const valueWei = PLATFORM_CREATE_FEE + b0AmountWei + preSaleWei;
|
|
81
61
|
const tmCreate = new ethers.Contract(tmCreateAddr, TM2_ABI, devWallet);
|
|
62
|
+
const launchFeeWei = await readLaunchFeeWei(tmCreate);
|
|
63
|
+
const valueWei = fourCreateValueWei(raisedToken, effectivePreSaleStr || '0', launchFeeWei);
|
|
82
64
|
const createTxUnsigned = await tmCreate.createToken.populateTransaction(createResp.createArg, createResp.signature, {
|
|
83
65
|
value: valueWei,
|
|
84
66
|
});
|
|
85
|
-
// ✅ 贿赂交易放在首位(由 devWallet 发送)
|
|
86
|
-
let bribeNonce;
|
|
87
67
|
if (needBribeTx) {
|
|
88
|
-
bribeNonce = await nonceManager.getNextNonce(devWallet);
|
|
68
|
+
const bribeNonce = await nonceManager.getNextNonce(devWallet);
|
|
89
69
|
signedTxs.push(await signBribeTransaction(devWallet, bribeAmount, bribeNonce, gasPrice, chainId, txType));
|
|
90
70
|
}
|
|
71
|
+
const approveTx = await signQuoteApproveIfNeeded({
|
|
72
|
+
raisedToken,
|
|
73
|
+
preSale: effectivePreSaleStr || '0',
|
|
74
|
+
wallet: devWallet,
|
|
75
|
+
spender: tmCreateAddr,
|
|
76
|
+
getNonce: () => nonceManager.getNextNonce(devWallet),
|
|
77
|
+
gasPrice,
|
|
78
|
+
chainId,
|
|
79
|
+
txType,
|
|
80
|
+
});
|
|
81
|
+
if (approveTx)
|
|
82
|
+
signedTxs.push(approveTx);
|
|
91
83
|
const createTxRequest = {
|
|
92
84
|
...createTxUnsigned,
|
|
93
85
|
from: devWallet.address,
|
|
@@ -99,7 +91,6 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
99
91
|
value: valueWei,
|
|
100
92
|
};
|
|
101
93
|
signedTxs.push(await devWallet.signTransaction(createTxRequest));
|
|
102
|
-
// ✅ 利润多跳转账(强制 2 跳中转)
|
|
103
94
|
let profitHopWallets;
|
|
104
95
|
if (extractProfit && profitAmount > 0n) {
|
|
105
96
|
const profitNonce = await nonceManager.getNextNonce(devWallet);
|
|
@@ -115,11 +106,9 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
115
106
|
startNonce: profitNonce,
|
|
116
107
|
});
|
|
117
108
|
signedTxs.push(...profitHopResult.signedTransactions);
|
|
118
|
-
profitHopWallets = profitHopResult.hopWallets;
|
|
109
|
+
profitHopWallets = profitHopResult.hopWallets;
|
|
119
110
|
}
|
|
120
111
|
nonceManager.clearTemp();
|
|
121
|
-
// ⚠️ 只返回签名交易,不提交
|
|
122
|
-
// 构建元数据
|
|
123
112
|
const metadata = extractProfit && profitAmount > 0n
|
|
124
113
|
? {
|
|
125
114
|
totalBuyAmount: ethers.formatEther(originalBuyAmount),
|
|
@@ -130,8 +119,8 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
130
119
|
: undefined;
|
|
131
120
|
return {
|
|
132
121
|
signedTransactions: signedTxs,
|
|
133
|
-
tokenAddress: ZERO_ADDRESS,
|
|
134
|
-
profitHopWallets,
|
|
122
|
+
tokenAddress: ZERO_ADDRESS,
|
|
123
|
+
profitHopWallets,
|
|
135
124
|
metadata,
|
|
136
125
|
};
|
|
137
126
|
}
|
|
@@ -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
|
+
}
|