four-flap-meme-sdk 2.2.17 → 2.2.19

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.
@@ -13,7 +13,7 @@ export { buildPermitPiggybackAuto } from './permit.js';
13
13
  export { uploadTokenMeta, type TokenMetaInput } from './ipfs.js';
14
14
  export { PinataClient, type PinataConfig, pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob, type PinataPinResp } from './pinata.js';
15
15
  export { predictVanityTokenAddressByChain, findSaltEndingByChain } from './vanity.js';
16
- export { buildNewTokenV6Params, normalizeTaxV2Fields, NEW_TOKEN_V6_ABI, getTaxV3LaunchVanityOptions, getV3PermitLaunchVanityOptions, } from './launch-v6.js';
16
+ export { buildNewTokenV6Params, normalizeTaxV2Fields, resolveDividendTokenForQuote, NEW_TOKEN_V6_ABI, getTaxV3LaunchVanityOptions, getV3PermitLaunchVanityOptions, } from './launch-v6.js';
17
17
  export { populateCreateTokenTransaction, normalizeTaxLaunchConfig, resolveCreateTokenLaunchFlags, MAGIC_DIVIDEND_SELF, type PopulateCreateTokenParams, type NormalizedTaxLaunchConfig, } from './portal-create-token.js';
18
18
  export { getFlapMetaByAddress, getFlapMetasByAddresses } from './meta.js';
19
19
  export { parseFlapError, getFlapErrorMessage, getFlapErrorMessageEn, type FlapErrorCode } from './errors.js';
@@ -13,7 +13,7 @@ export { buildPermitPiggybackAuto } from './permit.js';
13
13
  export { uploadTokenMeta } from './ipfs.js';
14
14
  export { PinataClient, pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob } from './pinata.js';
15
15
  export { predictVanityTokenAddressByChain, findSaltEndingByChain } from './vanity.js';
16
- export { buildNewTokenV6Params, normalizeTaxV2Fields, NEW_TOKEN_V6_ABI, getTaxV3LaunchVanityOptions, getV3PermitLaunchVanityOptions, } from './launch-v6.js';
16
+ export { buildNewTokenV6Params, normalizeTaxV2Fields, resolveDividendTokenForQuote, NEW_TOKEN_V6_ABI, getTaxV3LaunchVanityOptions, getV3PermitLaunchVanityOptions, } from './launch-v6.js';
17
17
  export { populateCreateTokenTransaction, normalizeTaxLaunchConfig, resolveCreateTokenLaunchFlags, MAGIC_DIVIDEND_SELF, } from './portal-create-token.js';
18
18
  export { getFlapMetaByAddress, getFlapMetasByAddresses } from './meta.js';
19
19
  export { parseFlapError, getFlapErrorMessage, getFlapErrorMessageEn } from './errors.js';
@@ -58,6 +58,11 @@ export type BuildNewTokenV6FromTaxV2Input = {
58
58
  };
59
59
  /** Portal.newTokenV6 ABI(ethers 简写格式,供 Contract 使用) */
60
60
  export declare const NEW_TOKEN_V6_ABI = "function newTokenV6((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile,uint16 buyTaxRate,uint16 sellTaxRate,uint64 taxDuration,uint64 antiFarmerDuration,uint16 mktBps,uint16 deflationBps,uint16 dividendBps,uint16 lpBps,uint256 minimumShareBalance,address dividendToken,address commissionReceiver,uint8 tokenVersion)) external payable returns (address)";
61
+ /**
62
+ * Portal 要求:quoteToken 为 ERC20 时 dividendToken 不能为 0。
63
+ * 未显式传入时默认与 quoteToken 相同(分红币种 = 报价币)。
64
+ */
65
+ export declare function resolveDividendTokenForQuote(quoteToken?: string, dividendToken?: string): string;
61
66
  export declare function normalizeTaxV2Fields(taxV2: TaxV2Config): (TaxV2Config & {
62
67
  mktBps: number;
63
68
  deflationBps: number;
@@ -7,6 +7,20 @@ import { TokenVersion } from './portal.js';
7
7
  const NONE_EXTENSION_ID = '0x' + '00'.repeat(32);
8
8
  /** Portal.newTokenV6 ABI(ethers 简写格式,供 Contract 使用) */
9
9
  export const NEW_TOKEN_V6_ABI = 'function newTokenV6((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile,uint16 buyTaxRate,uint16 sellTaxRate,uint64 taxDuration,uint64 antiFarmerDuration,uint16 mktBps,uint16 deflationBps,uint16 dividendBps,uint16 lpBps,uint256 minimumShareBalance,address dividendToken,address commissionReceiver,uint8 tokenVersion)) external payable returns (address)';
10
+ /**
11
+ * Portal 要求:quoteToken 为 ERC20 时 dividendToken 不能为 0。
12
+ * 未显式传入时默认与 quoteToken 相同(分红币种 = 报价币)。
13
+ */
14
+ export function resolveDividendTokenForQuote(quoteToken, dividendToken) {
15
+ if (dividendToken && dividendToken !== ZeroAddress) {
16
+ return dividendToken;
17
+ }
18
+ const qt = quoteToken || ZeroAddress;
19
+ if (qt === ZeroAddress) {
20
+ return ZeroAddress;
21
+ }
22
+ return qt;
23
+ }
10
24
  export function normalizeTaxV2Fields(taxV2) {
11
25
  if ('distribution' in taxV2) {
12
26
  return {
@@ -63,7 +77,7 @@ export function buildNewTokenV6Params(input) {
63
77
  dividendBps: tv2.dividendBps & 0xffff,
64
78
  lpBps: tv2.lpBps & 0xffff,
65
79
  minimumShareBalance: BigInt(tv2.minimumShareBalance ?? 10000) * (10n ** 18n),
66
- dividendToken: input.dividendToken ?? ZeroAddress,
80
+ dividendToken: resolveDividendTokenForQuote(input.quoteToken, input.dividendToken),
67
81
  commissionReceiver: input.commissionReceiver ?? ZeroAddress,
68
82
  tokenVersion: TokenVersion.TOKEN_TAXED_V3,
69
83
  };
@@ -94,7 +108,7 @@ export function buildNewTokenV6Params(input) {
94
108
  dividendBps: (p.dividendBps ?? 0) & 0xffff,
95
109
  lpBps: (p.lpBps ?? 0) & 0xffff,
96
110
  minimumShareBalance: p.minimumShareBalance ?? 0n,
97
- dividendToken: p.dividendToken ?? ZeroAddress,
111
+ dividendToken: resolveDividendTokenForQuote(p.quoteToken, p.dividendToken),
98
112
  commissionReceiver: isStandard ? ZeroAddress : (p.commissionReceiver ?? ZeroAddress),
99
113
  tokenVersion: p.tokenVersion ?? TokenVersion.TOKEN_V2_PERMIT,
100
114
  };
@@ -22,7 +22,7 @@
22
22
  import { Contract, AbiCoder, ZeroAddress } from 'ethers';
23
23
  import { TokenVersion } from './portal.js';
24
24
  import { getVanitySuffix } from './constants.js';
25
- import { normalizeTaxV2Fields } from './launch-v6.js';
25
+ import { normalizeTaxV2Fields, resolveDividendTokenForQuote } from './launch-v6.js';
26
26
  /**
27
27
  * 金库类型显示标签
28
28
  */
@@ -313,7 +313,7 @@ export function buildNewTokenV6WithVaultParams(input) {
313
313
  dividendBps: tv2.dividendBps & 0xffff,
314
314
  lpBps: tv2.lpBps & 0xffff,
315
315
  minimumShareBalance: BigInt(tv2.minimumShareBalance ?? 10000) * (10n ** 18n),
316
- dividendToken: ZeroAddress,
316
+ dividendToken: resolveDividendTokenForQuote(input.quoteToken),
317
317
  commissionReceiver: ZeroAddress,
318
318
  tokenVersion: TOKEN_TAXED_V3_VERSION,
319
319
  vaultFactory,
@@ -15,6 +15,7 @@ const V3_PAIR_ABI = [
15
15
  'function slot0() view returns (uint160 sqrtPriceX96,int24 tick,uint16 observationIndex,uint16 observationCardinality,uint16 observationCardinalityNext,uint8 feeProtocol,bool unlocked)',
16
16
  'function token0() view returns (address)',
17
17
  'function token1() view returns (address)',
18
+ 'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)',
18
19
  ];
19
20
  /** BSC:lpFeeProfile → Infinity PoolKey 的 fee / parameters(与链上 Initialize 一致) */
20
21
  const BSC_INFINITY_POOL_KEY_BY_PROFILE = {
@@ -133,6 +134,15 @@ function getCachedRpcProvider(rpcUrl) {
133
134
  }
134
135
  return p;
135
136
  }
137
+ async function getTokenDecimalsSafe(provider, address) {
138
+ try {
139
+ const token = new Contract(address, ERC20_ABI, provider);
140
+ return Number(await token.decimals());
141
+ }
142
+ catch {
143
+ return 18;
144
+ }
145
+ }
136
146
  /**
137
147
  * Infinity CL 池子 WBNB:取多档卖出 quote 的最大值(贴近 GMGN「池内 WBNB」)
138
148
  * 说明:不是 Vault 总 WBNB(全协议),也不是 L*sqrtP 虚拟储备(会高估到 ~5.8)。
@@ -208,39 +218,65 @@ async function getGraduatedV3PairMetrics(params) {
208
218
  const quoteAddr = params.quoteTokenAddress.toLowerCase() === ZERO_ADDRESS
209
219
  ? params.wrappedNativeAddress
210
220
  : params.quoteTokenAddress;
211
- const [t0, t1, slot0] = await Promise.all([
221
+ const [t0, t1] = await Promise.all([
212
222
  pool.token0(),
213
223
  pool.token1(),
214
- pool.slot0(),
215
224
  ]);
216
- const [bal0, bal1] = await Promise.all([
217
- new Contract(t0, ERC20_ABI, provider).balanceOf(params.poolAddress),
218
- new Contract(t1, ERC20_ABI, provider).balanceOf(params.poolAddress),
225
+ let bal0;
226
+ let bal1;
227
+ try {
228
+ [bal0, bal1] = await Promise.all([
229
+ new Contract(t0, ERC20_ABI, provider).balanceOf(params.poolAddress),
230
+ new Contract(t1, ERC20_ABI, provider).balanceOf(params.poolAddress),
231
+ ]);
232
+ }
233
+ catch {
234
+ try {
235
+ const reserves = await pool.getReserves();
236
+ bal0 = BigInt(reserves.reserve0 ?? reserves[0]);
237
+ bal1 = BigInt(reserves.reserve1 ?? reserves[1]);
238
+ }
239
+ catch {
240
+ return null;
241
+ }
242
+ }
243
+ let sqrtPriceX96 = null;
244
+ try {
245
+ const slot0 = await pool.slot0();
246
+ sqrtPriceX96 = BigInt(Array.isArray(slot0) ? slot0[0] : slot0.sqrtPriceX96);
247
+ }
248
+ catch {
249
+ sqrtPriceX96 = null;
250
+ }
251
+ const [dec0, dec1] = await Promise.all([
252
+ getTokenDecimalsSafe(provider, t0),
253
+ getTokenDecimalsSafe(provider, t1),
219
254
  ]);
220
- const sqrtPriceX96 = BigInt(Array.isArray(slot0) ? slot0[0] : slot0.sqrtPriceX96);
221
- const spot = v3SpotPriceQuotePerToken({
222
- sqrtPriceX96,
223
- tokenAddress: params.tokenAddress,
224
- token0: t0,
225
- token1: t1,
226
- quoteTokenAddress: quoteAddr,
227
- });
255
+ const spot = sqrtPriceX96 && sqrtPriceX96 > 0n
256
+ ? v3SpotPriceQuotePerToken({
257
+ sqrtPriceX96,
258
+ tokenAddress: params.tokenAddress,
259
+ token0: t0,
260
+ token1: t1,
261
+ quoteTokenAddress: quoteAddr,
262
+ })
263
+ : null;
228
264
  const tokenIs0 = t0.toLowerCase() === tokenLower;
229
- const poolTokenAmount = formatEther(tokenIs0 ? bal0 : bal1);
230
- const poolBNBAmount = formatEther(tokenIs0 ? bal1 : bal0);
265
+ const poolTokenAmount = formatUnits(tokenIs0 ? bal0 : bal1, tokenIs0 ? dec0 : dec1);
266
+ const poolQuoteAmount = formatUnits(tokenIs0 ? bal1 : bal0, tokenIs0 ? dec1 : dec0);
231
267
  let price = spot;
232
268
  if (!price && parseFloat(poolTokenAmount) > 0) {
233
- price = String(parseFloat(poolBNBAmount) / parseFloat(poolTokenAmount));
269
+ price = String(parseFloat(poolQuoteAmount) / parseFloat(poolTokenAmount));
234
270
  }
235
271
  if (!price) {
236
272
  price = await quotePortalPrice(params.portal, params.tokenAddress, params.quoteTokenAddress, params.wrappedNativeAddress);
237
273
  }
238
- if (!price && poolTokenAmount === '0' && poolBNBAmount === '0')
274
+ if (!price && poolTokenAmount === '0' && poolQuoteAmount === '0')
239
275
  return null;
240
276
  return {
241
277
  price: price ?? '0',
242
278
  progress: '100',
243
- poolBNBAmount,
279
+ poolBNBAmount: poolQuoteAmount,
244
280
  poolTokenAmount,
245
281
  dexKind: 'PANCAKE_V3',
246
282
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "2.2.17",
3
+ "version": "2.2.19",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",