four-flap-meme-sdk 2.0.0 → 2.1.0
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 +34 -0
- package/dist/chains/index.d.ts +13 -0
- package/dist/chains/index.js +13 -0
- package/dist/chains/xlayer/eip7702/index.d.ts +2 -0
- package/dist/flap/index.d.ts +10 -0
- package/dist/flap/index.js +8 -0
- package/dist/shared/constants/index.d.ts +2 -0
- package/dist/shared/index.d.ts +2 -0
- package/package.json +66 -1
- package/dist/chains/bsc/four/disperse.d.ts +0 -12
- package/dist/chains/bsc/four/disperse.js +0 -470
- package/dist/chains/bsc/four/pairwise.d.ts +0 -7
- package/dist/chains/bsc/four/pairwise.js +0 -308
- package/dist/chains/bsc/four/submit/blockrazor.d.ts +0 -18
- package/dist/chains/bsc/four/submit/blockrazor.js +0 -86
- package/dist/chains/bsc/four/submit/direct.d.ts +0 -66
- package/dist/chains/bsc/four/submit/direct.js +0 -452
- package/dist/chains/bsc/four/submit/helpers.d.ts +0 -18
- package/dist/chains/bsc/four/submit/helpers.js +0 -57
- package/dist/chains/bsc/four/submit/index.d.ts +0 -12
- package/dist/chains/bsc/four/submit/index.js +0 -11
- package/dist/chains/bsc/four/submit/merkle.d.ts +0 -18
- package/dist/chains/bsc/four/submit/merkle.js +0 -74
- package/dist/chains/bsc/four/submit/types.d.ts +0 -143
- package/dist/chains/bsc/four/swap/index.d.ts +0 -32
- package/dist/chains/bsc/four/swap/index.js +0 -829
- package/dist/chains/bsc/four/swap/types.d.ts +0 -70
- package/dist/chains/bsc/four/swap/types.js +0 -1
- package/dist/chains/bsc/four/sweep.d.ts +0 -13
- package/dist/chains/bsc/four/sweep.js +0 -788
- package/dist/chains/bsc/four/utils/index.d.ts +0 -20
- package/dist/chains/bsc/four/utils/index.js +0 -1558
- package/dist/chains/bsc/four/utils/types.d.ts +0 -1
- package/dist/chains/bsc/four/utils/types.js +0 -1
- package/dist/chains/bsc/pancake/bundle-buy-first/index.d.ts +0 -8
- package/dist/chains/bsc/pancake/bundle-buy-first/index.js +0 -907
- package/dist/chains/bsc/pancake/bundle-buy-first/types.d.ts +0 -73
- package/dist/chains/bsc/pancake/bundle-buy-first/types.js +0 -1
- package/dist/chains/bsc/pancake/bundle-swap/helpers.d.ts +0 -102
- package/dist/chains/bsc/pancake/bundle-swap/helpers.js +0 -572
- package/dist/chains/bsc/pancake/bundle-swap/index.d.ts +0 -50
- package/dist/chains/bsc/pancake/bundle-swap/index.js +0 -1066
- package/dist/chains/bsc/pancake/bundle-swap/types.d.ts +0 -202
- package/dist/chains/bsc/pancake/bundle-swap/types.js +0 -3
- package/dist/chains/xlayer/eip7702/bundle-swap/index.d.ts +0 -72
- package/dist/chains/xlayer/eip7702/bundle-swap/index.js +0 -921
- package/dist/chains/xlayer/eip7702/bundle-swap/types.d.ts +0 -65
- package/dist/chains/xlayer/eip7702/bundle-swap/types.js +0 -1
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.d.ts +0 -128
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.js +0 -857
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.d.ts +0 -85
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.js +0 -1
- package/dist/chains/xlayer/eip7702/volume/index.d.ts +0 -96
- package/dist/chains/xlayer/eip7702/volume/index.js +0 -793
- package/dist/chains/xlayer/eip7702/volume/types.d.ts +0 -124
- package/dist/chains/xlayer/eip7702/volume/types.js +0 -1
- package/dist/chains/xlayer/eoa/types-core.d.ts +0 -363
- package/dist/chains/xlayer/eoa/types-core.js +0 -53
- package/dist/chains/xlayer/eoa/types-create.d.ts +0 -413
- package/dist/chains/xlayer/eoa/types-create.js +0 -9
- package/dist/chains/xlayer/eoa/types-volume.d.ts +0 -209
- package/dist/chains/xlayer/eoa/types-volume.js +0 -13
- package/dist/dex/direct-router/index.d.ts +0 -70
- package/dist/dex/direct-router/index.js +0 -1410
- package/dist/dex/direct-router/types.d.ts +0 -81
- package/dist/dex/direct-router/types.js +0 -1
- package/dist/shared/abis/TaxToken.json +0 -969
- package/dist/shared/abis/TokenManager.json +0 -836
- package/dist/shared/abis/TokenManager2.json +0 -136
- package/dist/shared/abis/TokenManagerHelper3.json +0 -993
- package/dist/shared/abis 2/TaxToken.json +0 -105
- package/dist/shared/abis 2/TokenManager.json +0 -836
- package/dist/shared/abis 2/TokenManager2.json +0 -60
- package/dist/shared/abis 2/TokenManagerHelper3.json +0 -993
- package/dist/shared/abis 2/common.d.ts +0 -85
- package/dist/shared/abis 2/common.js +0 -254
- package/dist/shared/abis 2/index.d.ts +0 -8
- package/dist/shared/abis 2/index.js +0 -8
- package/dist/shared/clients 2/blockrazor.d.ts +0 -314
- package/dist/shared/clients 2/blockrazor.js +0 -596
- package/dist/shared/clients 2/club48.d.ts +0 -154
- package/dist/shared/clients 2/club48.js +0 -331
- package/dist/shared/clients 2/emitservice.d.ts +0 -47
- package/dist/shared/clients 2/emitservice.js +0 -44
- package/dist/shared/clients 2/four.d.ts +0 -132
- package/dist/shared/clients 2/four.js +0 -281
- package/dist/shared/clients 2/merkle.d.ts +0 -210
- package/dist/shared/clients 2/merkle.js +0 -400
- package/dist/shared/flap/__tests__/curve.test.d.ts +0 -1
- package/dist/shared/flap/__tests__/curve.test.js +0 -85
- package/dist/shared/flap/portal/index.d.ts +0 -12
- package/dist/shared/flap/portal/index.js +0 -11
- package/dist/shared/flap/portal/portal.d.ts +0 -47
- package/dist/shared/flap/portal/portal.js +0 -218
- package/dist/shared/flap/portal/types.d.ts +0 -227
- package/dist/shared/flap/portal/types.js +0 -80
- package/dist/shared/flap/portal/writer.d.ts +0 -121
- package/dist/shared/flap/portal/writer.js +0 -265
- package/dist/shared/flap/portal-bundle-merkle/core/index.d.ts +0 -18
- package/dist/shared/flap/portal-bundle-merkle/core/index.js +0 -938
- package/dist/shared/flap/portal-bundle-merkle/core/types.d.ts +0 -1
- package/dist/shared/flap/portal-bundle-merkle/core/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/swap/index.d.ts +0 -42
- package/dist/shared/flap/portal-bundle-merkle/swap/index.js +0 -1448
- package/dist/shared/flap/portal-bundle-merkle/swap/types.d.ts +0 -84
- package/dist/shared/flap/portal-bundle-merkle/swap/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/utils/index.d.ts +0 -17
- package/dist/shared/flap/portal-bundle-merkle/utils/index.js +0 -1024
- package/dist/shared/flap/portal-bundle-merkle/utils/types.d.ts +0 -16
- package/dist/shared/flap/portal-bundle-merkle/utils/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/utils-helpers.d.ts +0 -100
- package/dist/shared/flap/portal-bundle-merkle/utils-helpers.js +0 -133
- package/dist/shared/flap 2/__tests__/curve.test.d.ts +0 -1
- package/dist/shared/flap 2/__tests__/curve.test.js +0 -85
- package/dist/shared/flap 2/abi.d.ts +0 -4
- package/dist/shared/flap 2/abi.js +0 -4
- package/dist/shared/flap 2/constants.d.ts +0 -128
- package/dist/shared/flap 2/constants.js +0 -143
- package/dist/shared/flap 2/curve.d.ts +0 -33
- package/dist/shared/flap 2/curve.js +0 -84
- package/dist/shared/flap 2/errors.d.ts +0 -37
- package/dist/shared/flap 2/errors.js +0 -114
- package/dist/shared/flap 2/index.d.ts +0 -22
- package/dist/shared/flap 2/index.js +0 -33
- package/dist/shared/flap 2/ipfs.d.ts +0 -21
- package/dist/shared/flap 2/ipfs.js +0 -38
- package/dist/shared/flap 2/meta.d.ts +0 -30
- package/dist/shared/flap 2/meta.js +0 -195
- package/dist/shared/flap 2/permit.d.ts +0 -16
- package/dist/shared/flap 2/permit.js +0 -67
- package/dist/shared/flap 2/pinata.d.ts +0 -40
- package/dist/shared/flap 2/pinata.js +0 -106
- package/dist/shared/flap 2/portal-bundle-merkle/config.d.ts +0 -79
- package/dist/shared/flap 2/portal-bundle-merkle/config.js +0 -133
- package/dist/shared/flap 2/portal-bundle-merkle/core.d.ts +0 -18
- package/dist/shared/flap 2/portal-bundle-merkle/core.js +0 -938
- package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.d.ts +0 -125
- package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.js +0 -665
- package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.d.ts +0 -88
- package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.js +0 -446
- package/dist/shared/flap 2/portal-bundle-merkle/index.d.ts +0 -14
- package/dist/shared/flap 2/portal-bundle-merkle/index.js +0 -26
- package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.d.ts +0 -28
- package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.js +0 -701
- package/dist/shared/flap 2/portal-bundle-merkle/private.d.ts +0 -17
- package/dist/shared/flap 2/portal-bundle-merkle/private.js +0 -549
- package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.d.ts +0 -65
- package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.js +0 -831
- package/dist/shared/flap 2/portal-bundle-merkle/swap.d.ts +0 -201
- package/dist/shared/flap 2/portal-bundle-merkle/swap.js +0 -1359
- package/dist/shared/flap 2/portal-bundle-merkle/types.d.ts +0 -358
- package/dist/shared/flap 2/portal-bundle-merkle/types.js +0 -1
- package/dist/shared/flap 2/portal-bundle-merkle/utils.d.ts +0 -89
- package/dist/shared/flap 2/portal-bundle-merkle/utils.js +0 -963
- package/dist/shared/flap 2/portal-bundle.d.ts +0 -119
- package/dist/shared/flap 2/portal-bundle.js +0 -584
- package/dist/shared/flap 2/portal.d.ts +0 -392
- package/dist/shared/flap 2/portal.js +0 -559
- package/dist/shared/flap 2/vanity.d.ts +0 -48
- package/dist/shared/flap 2/vanity.js +0 -110
- package/dist/shared/flap 2/vault.d.ts +0 -240
- package/dist/shared/flap 2/vault.js +0 -366
- package/dist/shared/four 2/index.d.ts +0 -7
- package/dist/shared/four 2/index.js +0 -22
- package/dist/shared/four 2/tax-token.d.ts +0 -176
- package/dist/shared/four 2/tax-token.js +0 -302
- package/dist/shared/index 2.js +0 -10
- package/dist/shared/index.d 2.ts +0 -10
- package/dist/types/distribute.d.ts +0 -72
- package/dist/types/distribute.js +0 -1
- package/dist/types 2/errors.d.ts +0 -27
- package/dist/types 2/errors.js +0 -34
- package/dist/utils/__tests__/errors.test.d.ts +0 -1
- package/dist/utils/__tests__/errors.test.js +0 -76
- package/dist/utils/airdrop-sweep-types.d.ts +0 -1
- package/dist/utils/airdrop-sweep-types.js +0 -1
- package/dist/utils/erc20/index.d.ts +0 -242
- package/dist/utils/erc20/index.js +0 -645
- package/dist/utils/erc20/types.d.ts +0 -77
- package/dist/utils/erc20/types.js +0 -1
- package/dist/utils/erc20-types.d.ts +0 -1
- package/dist/utils/erc20-types.js +0 -1
- package/dist/utils/holders-maker/helpers.d.ts +0 -43
- package/dist/utils/holders-maker/helpers.js +0 -371
- package/dist/utils/holders-maker/index.d.ts +0 -26
- package/dist/utils/holders-maker/index.js +0 -218
- package/dist/utils/holders-maker/types.d.ts +0 -72
- package/dist/utils/holders-maker/types.js +0 -4
- package/dist/utils/holders-maker-types.d.ts +0 -1
- package/dist/utils/holders-maker-types.js +0 -1
- package/dist/utils/lp-inspect/index.d.ts +0 -44
- package/dist/utils/lp-inspect/index.js +0 -937
- package/dist/utils/lp-inspect/types.d.ts +0 -100
- package/dist/utils/lp-inspect/types.js +0 -1
- package/dist/utils/lp-inspect-types.d.ts +0 -1
- package/dist/utils/lp-inspect-types.js +0 -1
- package/dist/utils/private-sale-types.d.ts +0 -1
- package/dist/utils/private-sale-types.js +0 -1
- package/dist/utils/quote-helpers/index.d.ts +0 -107
- package/dist/utils/quote-helpers/index.js +0 -346
- package/dist/utils/quote-helpers/types.d.ts +0 -16
- package/dist/utils/quote-helpers/types.js +0 -1
- package/dist/utils/quote-helpers-types.d.ts +0 -1
- package/dist/utils/quote-helpers-types.js +0 -1
- /package/dist/{chains/bsc/four/submit/types.js → __tests__/subpath-exports.test.d.ts} +0 -0
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { FixedNumber } from 'ethers';
|
|
2
|
-
/**
|
|
3
|
-
* CDPV2 Bonding Curve 实现
|
|
4
|
-
* 使用 ethers FixedNumber 进行高精度计算,避免浮点数精度损失
|
|
5
|
-
*
|
|
6
|
-
* 公式:
|
|
7
|
-
* - Supply (S) = 1,000,000,000 + h - k / (R + r)
|
|
8
|
-
* - Reserve (R) = k / (1,000,000,000 + h - S) - r
|
|
9
|
-
* - Price (P) = k / (1,000,000,000 + h - S)²
|
|
10
|
-
*/
|
|
11
|
-
const BILLION = FixedNumber.fromString('1000000000');
|
|
12
|
-
export class CDPV2 {
|
|
13
|
-
static defaultDexSupplyThreshold() {
|
|
14
|
-
return FixedNumber.fromString('800000000');
|
|
15
|
-
}
|
|
16
|
-
static getCurve(r, h, k) {
|
|
17
|
-
if (h == null)
|
|
18
|
-
return new CDPV2(r, 0, 1e9 * r);
|
|
19
|
-
return new CDPV2(r, h, k);
|
|
20
|
-
}
|
|
21
|
-
constructor(r, h = 0, k = 0) {
|
|
22
|
-
this.r = r;
|
|
23
|
-
this.h = h;
|
|
24
|
-
this.k = k;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* 根据储备量估算供应量
|
|
28
|
-
* Supply = BILLION + h - k / (reserve + r)
|
|
29
|
-
* @returns FixedNumber 对象,保持高精度
|
|
30
|
-
*/
|
|
31
|
-
estimateSupply(reserve) {
|
|
32
|
-
if (!reserve || reserve === '0')
|
|
33
|
-
return FixedNumber.fromString('0');
|
|
34
|
-
const R = FixedNumber.fromString(reserve);
|
|
35
|
-
const r = FixedNumber.fromString(this.r.toString());
|
|
36
|
-
const h = FixedNumber.fromString(this.h.toString());
|
|
37
|
-
const k = FixedNumber.fromString(this.k.toString());
|
|
38
|
-
// k / (R + r)
|
|
39
|
-
const divisor = k.div(R.add(r));
|
|
40
|
-
// BILLION + h - divisor
|
|
41
|
-
return BILLION.add(h).sub(divisor);
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* 根据供应量估算储备量
|
|
45
|
-
* Reserve = k / (BILLION + h - amount) - r
|
|
46
|
-
* @returns FixedNumber 对象,保持高精度
|
|
47
|
-
*/
|
|
48
|
-
estimateReserve(amount) {
|
|
49
|
-
if (!amount || amount === '0')
|
|
50
|
-
return FixedNumber.fromString('0');
|
|
51
|
-
const S = FixedNumber.fromString(amount);
|
|
52
|
-
const h = FixedNumber.fromString(this.h.toString());
|
|
53
|
-
const k = FixedNumber.fromString(this.k.toString());
|
|
54
|
-
const r = FixedNumber.fromString(this.r.toString());
|
|
55
|
-
// k / (BILLION + h - S)
|
|
56
|
-
const dividend = k.div(BILLION.add(h).sub(S));
|
|
57
|
-
// dividend - r
|
|
58
|
-
return dividend.sub(r);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* 计算当前价格
|
|
62
|
-
* Price = k / (BILLION + h - supply)²
|
|
63
|
-
* @returns FixedNumber 对象,保持高精度
|
|
64
|
-
*/
|
|
65
|
-
price(supply) {
|
|
66
|
-
const S = FixedNumber.fromString(supply || '0');
|
|
67
|
-
const h = FixedNumber.fromString(this.h.toString());
|
|
68
|
-
const k = FixedNumber.fromString(this.k.toString());
|
|
69
|
-
// BILLION + h - S
|
|
70
|
-
const denominator = BILLION.add(h).sub(S);
|
|
71
|
-
// denominator²
|
|
72
|
-
const denominatorSquared = denominator.mul(denominator);
|
|
73
|
-
// k / denominator²
|
|
74
|
-
return k.div(denominatorSquared);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* 计算完全稀释估值 (FDV)
|
|
78
|
-
* FDV = price * BILLION
|
|
79
|
-
* @returns FixedNumber 对象,保持高精度
|
|
80
|
-
*/
|
|
81
|
-
fdv(supply) {
|
|
82
|
-
return this.price(supply).mul(BILLION);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Flap Protocol 错误代码
|
|
3
|
-
*/
|
|
4
|
-
export type FlapErrorCode = 'TOKEN_ALREADY_EXISTS' | 'TOKEN_NOT_FOUND' | 'TOKEN_NOT_TRADABLE' | 'ALREADY_ON_DEX' | 'INSUFFICIENT_BALANCE' | 'SLIPPAGE_EXCEEDED' | 'INVALID_TOKEN' | 'INVALID_QUOTE_TOKEN' | 'INVALID_AMOUNT' | 'TAX_RATE_TOO_HIGH' | 'PERMIT_EXPIRED' | 'PERMIT_INVALID' | 'UNKNOWN_ERROR';
|
|
5
|
-
/**
|
|
6
|
-
* 解析 Flap Protocol 错误信息
|
|
7
|
-
*
|
|
8
|
-
* @param error - 捕获的错误对象
|
|
9
|
-
* @returns 错误代码或 null(无法识别的错误)
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* try {
|
|
14
|
-
* await portal.swapExactInput(...);
|
|
15
|
-
* } catch (err) {
|
|
16
|
-
* const errorCode = parseFlapError(err);
|
|
17
|
-
* if (errorCode === 'SLIPPAGE_EXCEEDED') {
|
|
18
|
-
* console.log('滑点过大,请调整参数');
|
|
19
|
-
* }
|
|
20
|
-
* }
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export declare function parseFlapError(error: any): FlapErrorCode | null;
|
|
24
|
-
/**
|
|
25
|
-
* 获取错误的友好提示信息(中文)
|
|
26
|
-
*
|
|
27
|
-
* @param errorCode - 错误代码
|
|
28
|
-
* @returns 友好的错误提示
|
|
29
|
-
*/
|
|
30
|
-
export declare function getFlapErrorMessage(errorCode: FlapErrorCode | null): string;
|
|
31
|
-
/**
|
|
32
|
-
* 获取错误的友好提示信息(英文)
|
|
33
|
-
*
|
|
34
|
-
* @param errorCode - 错误代码
|
|
35
|
-
* @returns 友好的错误提示
|
|
36
|
-
*/
|
|
37
|
-
export declare function getFlapErrorMessageEn(errorCode: FlapErrorCode | null): string;
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 解析 Flap Protocol 错误信息
|
|
3
|
-
*
|
|
4
|
-
* @param error - 捕获的错误对象
|
|
5
|
-
* @returns 错误代码或 null(无法识别的错误)
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* try {
|
|
10
|
-
* await portal.swapExactInput(...);
|
|
11
|
-
* } catch (err) {
|
|
12
|
-
* const errorCode = parseFlapError(err);
|
|
13
|
-
* if (errorCode === 'SLIPPAGE_EXCEEDED') {
|
|
14
|
-
* console.log('滑点过大,请调整参数');
|
|
15
|
-
* }
|
|
16
|
-
* }
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
export function parseFlapError(error) {
|
|
20
|
-
const msg = error?.message || error?.data?.message || String(error);
|
|
21
|
-
const msgLower = msg.toLowerCase();
|
|
22
|
-
// Token 状态相关错误
|
|
23
|
-
if (msgLower.includes('token already exists') || msgLower.includes('already created')) {
|
|
24
|
-
return 'TOKEN_ALREADY_EXISTS';
|
|
25
|
-
}
|
|
26
|
-
if (msgLower.includes('token not found') || msgLower.includes('invalid token')) {
|
|
27
|
-
return 'TOKEN_NOT_FOUND';
|
|
28
|
-
}
|
|
29
|
-
if (msgLower.includes('not tradable') || msgLower.includes('trading disabled')) {
|
|
30
|
-
return 'TOKEN_NOT_TRADABLE';
|
|
31
|
-
}
|
|
32
|
-
if (msgLower.includes('already on dex') || msgLower.includes('already migrated')) {
|
|
33
|
-
return 'ALREADY_ON_DEX';
|
|
34
|
-
}
|
|
35
|
-
// 余额相关错误
|
|
36
|
-
if (msgLower.includes('insufficient balance') || msgLower.includes('insufficient funds')) {
|
|
37
|
-
return 'INSUFFICIENT_BALANCE';
|
|
38
|
-
}
|
|
39
|
-
// 滑点错误
|
|
40
|
-
if (msgLower.includes('slippage') || msgLower.includes('min output')) {
|
|
41
|
-
return 'SLIPPAGE_EXCEEDED';
|
|
42
|
-
}
|
|
43
|
-
// 参数验证错误
|
|
44
|
-
if (msgLower.includes('invalid amount') || msgLower.includes('amount too small')) {
|
|
45
|
-
return 'INVALID_AMOUNT';
|
|
46
|
-
}
|
|
47
|
-
if (msgLower.includes('invalid quote token') || msgLower.includes('quote token not supported')) {
|
|
48
|
-
return 'INVALID_QUOTE_TOKEN';
|
|
49
|
-
}
|
|
50
|
-
if (msgLower.includes('tax rate') && msgLower.includes('too high')) {
|
|
51
|
-
return 'TAX_RATE_TOO_HIGH';
|
|
52
|
-
}
|
|
53
|
-
// Permit 相关错误
|
|
54
|
-
if (msgLower.includes('permit expired') || msgLower.includes('deadline')) {
|
|
55
|
-
return 'PERMIT_EXPIRED';
|
|
56
|
-
}
|
|
57
|
-
if (msgLower.includes('permit') && (msgLower.includes('invalid') || msgLower.includes('signature'))) {
|
|
58
|
-
return 'PERMIT_INVALID';
|
|
59
|
-
}
|
|
60
|
-
// 无法识别的错误
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* 获取错误的友好提示信息(中文)
|
|
65
|
-
*
|
|
66
|
-
* @param errorCode - 错误代码
|
|
67
|
-
* @returns 友好的错误提示
|
|
68
|
-
*/
|
|
69
|
-
export function getFlapErrorMessage(errorCode) {
|
|
70
|
-
if (!errorCode)
|
|
71
|
-
return '未知错误,请检查交易参数';
|
|
72
|
-
const messages = {
|
|
73
|
-
TOKEN_ALREADY_EXISTS: '代币已存在,请使用不同的参数创建',
|
|
74
|
-
TOKEN_NOT_FOUND: '代币不存在或地址无效',
|
|
75
|
-
TOKEN_NOT_TRADABLE: '代币当前不可交易',
|
|
76
|
-
ALREADY_ON_DEX: '代币已迁移到 DEX,无法在联合曲线上交易',
|
|
77
|
-
INSUFFICIENT_BALANCE: '余额不足',
|
|
78
|
-
SLIPPAGE_EXCEEDED: '滑点过大,请调整最小输出数量或重试',
|
|
79
|
-
INVALID_TOKEN: '无效的代币地址',
|
|
80
|
-
INVALID_QUOTE_TOKEN: '不支持的 quote token',
|
|
81
|
-
INVALID_AMOUNT: '无效的交易数量',
|
|
82
|
-
TAX_RATE_TOO_HIGH: '税率设置过高(最大 10%)',
|
|
83
|
-
PERMIT_EXPIRED: 'Permit 签名已过期',
|
|
84
|
-
PERMIT_INVALID: 'Permit 签名无效',
|
|
85
|
-
UNKNOWN_ERROR: '未知错误',
|
|
86
|
-
};
|
|
87
|
-
return messages[errorCode];
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* 获取错误的友好提示信息(英文)
|
|
91
|
-
*
|
|
92
|
-
* @param errorCode - 错误代码
|
|
93
|
-
* @returns 友好的错误提示
|
|
94
|
-
*/
|
|
95
|
-
export function getFlapErrorMessageEn(errorCode) {
|
|
96
|
-
if (!errorCode)
|
|
97
|
-
return 'Unknown error, please check transaction parameters';
|
|
98
|
-
const messages = {
|
|
99
|
-
TOKEN_ALREADY_EXISTS: 'Token already exists, please use different parameters',
|
|
100
|
-
TOKEN_NOT_FOUND: 'Token not found or invalid address',
|
|
101
|
-
TOKEN_NOT_TRADABLE: 'Token is not tradable at the moment',
|
|
102
|
-
ALREADY_ON_DEX: 'Token has been migrated to DEX, cannot trade on bonding curve',
|
|
103
|
-
INSUFFICIENT_BALANCE: 'Insufficient balance',
|
|
104
|
-
SLIPPAGE_EXCEEDED: 'Slippage tolerance exceeded, please adjust parameters or retry',
|
|
105
|
-
INVALID_TOKEN: 'Invalid token address',
|
|
106
|
-
INVALID_QUOTE_TOKEN: 'Quote token not supported',
|
|
107
|
-
INVALID_AMOUNT: 'Invalid trade amount',
|
|
108
|
-
TAX_RATE_TOO_HIGH: 'Tax rate too high (maximum 10%)',
|
|
109
|
-
PERMIT_EXPIRED: 'Permit signature expired',
|
|
110
|
-
PERMIT_INVALID: 'Invalid permit signature',
|
|
111
|
-
UNKNOWN_ERROR: 'Unknown error',
|
|
112
|
-
};
|
|
113
|
-
return messages[errorCode];
|
|
114
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Flap Protocol 模块
|
|
3
|
-
*
|
|
4
|
-
* 跨链支持的 Flap 协议功能
|
|
5
|
-
*
|
|
6
|
-
* 注意:由于历史原因,多个文件中有同名但不同的 FlapChain 类型
|
|
7
|
-
* 使用时请从具体文件导入
|
|
8
|
-
*/
|
|
9
|
-
export { FlapPortal, FlapPortalWriter, type FlapChain, // 主要的 FlapChain 定义
|
|
10
|
-
type PortalConfig, type TokenStateV2, type TokenStateV3, type TokenStateV4, type TokenStateV5, type TokenStateV7, type QuoteExactInputParams, type ExactInputParams, type ExactInputV3Params, type NewTokenV3Params, type NewTokenV4Params, type NewTokenV5Params, type TaxDistributionConfig, validateTaxDistribution, TokenStatus, TokenVersion, DexThreshType, MigratorType, V3LPFeeProfile, lpFeeProfileToV3Fee, DEXId, } from './portal.js';
|
|
11
|
-
export { CDPV2 } from './curve.js';
|
|
12
|
-
export { buildPermitPiggybackAuto } from './permit.js';
|
|
13
|
-
export { uploadTokenMeta, type TokenMetaInput } from './ipfs.js';
|
|
14
|
-
export { PinataClient, type PinataConfig, pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob, type PinataPinResp } from './pinata.js';
|
|
15
|
-
export { predictVanityTokenAddressByChain, findSaltEndingByChain } from './vanity.js';
|
|
16
|
-
export { getFlapMetaByAddress, getFlapMetasByAddresses } from './meta.js';
|
|
17
|
-
export { parseFlapError, getFlapErrorMessage, getFlapErrorMessageEn, type FlapErrorCode } from './errors.js';
|
|
18
|
-
export { FLAP_DEFAULT_FEE_RATES, FLAP_IPFS_API_URL, FLAP_VANITY_SUFFIX, FLAP_DEX_THRESHOLDS, FLAP_TOTAL_SUPPLY, ZERO_ADDRESS, CHAIN_TAX_SUPPORT, getVanitySuffix, isChainSupportTax, FLAP_PORTAL_ADDRESSES } from './constants.js';
|
|
19
|
-
export * from './abi.js';
|
|
20
|
-
export { createTokenWithBundleBuy, batchBuyWithBundle, batchSellWithBundle, type FlapBundleConfig, type FlapChainForBundle, type FlapCreateWithBundleBuyParams, type FlapCreateWithBundleBuyResult, type FlapBatchBuyParams, type FlapBatchBuyResult, type FlapBatchSellParams, type FlapBatchSellResult, flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell, type FlapPrivateBuyParams, type FlapPrivateSellParams, type FlapBatchPrivateBuyParams, type FlapBatchPrivateSellParams, type FlapBatchPrivateSellResult, } from './portal-bundle.js';
|
|
21
|
-
export * from './portal-bundle-merkle/index.js';
|
|
22
|
-
export { NONE_EXTENSION_ID, VAULT_TYPE_LABELS, VAULT_TYPE_CATEGORIES, VAULT_FACTORY_ADDRESSES, VAULT_PORTAL_ADDRESSES, VAULT_PORTAL_ABI, VAULT_EXTRA_CONFIG, FLAP_GUARDIAN_ADDRESSES, VAULT_FACTORY_ABI, VAULT_FACTORY_V2_ABI, VAULT_BASE_ABI, VAULT_BASE_V2_ABI, type VaultType, type TaxVaultConfig, type VaultInfo, type FieldDescriptor, type VaultDataSchema, type ApproveAction, type VaultMethodSchema, type VaultUISchema, encodeVaultData, buildVaultParams, buildVaultExtensionParams, getVaultFactoryAddress, getVaultPortalAddress, queryVaultDataSchema, queryVaultUISchema, queryVaultDescription, validateVaultFactory, getVaultInfo, isValidContract, } from './vault.js';
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Flap Protocol 模块
|
|
3
|
-
*
|
|
4
|
-
* 跨链支持的 Flap 协议功能
|
|
5
|
-
*
|
|
6
|
-
* 注意:由于历史原因,多个文件中有同名但不同的 FlapChain 类型
|
|
7
|
-
* 使用时请从具体文件导入
|
|
8
|
-
*/
|
|
9
|
-
// 核心模块 - 显式导出避免冲突
|
|
10
|
-
export { FlapPortal, FlapPortalWriter, validateTaxDistribution, TokenStatus, TokenVersion, DexThreshType, MigratorType, V3LPFeeProfile, lpFeeProfileToV3Fee, DEXId, } from './portal.js';
|
|
11
|
-
export { CDPV2 } from './curve.js';
|
|
12
|
-
export { buildPermitPiggybackAuto } from './permit.js';
|
|
13
|
-
export { uploadTokenMeta } from './ipfs.js';
|
|
14
|
-
export { PinataClient, pinFileToIPFSWithJWT, pinImageByPath, pinFileToIPFSWithJWTWeb, pinDataURLWithJWTWeb, dataURLToBlob } from './pinata.js';
|
|
15
|
-
export { predictVanityTokenAddressByChain, findSaltEndingByChain } from './vanity.js';
|
|
16
|
-
export { getFlapMetaByAddress, getFlapMetasByAddresses } from './meta.js';
|
|
17
|
-
export { parseFlapError, getFlapErrorMessage, getFlapErrorMessageEn } from './errors.js';
|
|
18
|
-
export { FLAP_DEFAULT_FEE_RATES, FLAP_IPFS_API_URL, FLAP_VANITY_SUFFIX, FLAP_DEX_THRESHOLDS, FLAP_TOTAL_SUPPLY, ZERO_ADDRESS, CHAIN_TAX_SUPPORT, getVanitySuffix, isChainSupportTax, FLAP_PORTAL_ADDRESSES } from './constants.js';
|
|
19
|
-
export * from './abi.js';
|
|
20
|
-
// Bundle 功能
|
|
21
|
-
export { createTokenWithBundleBuy, batchBuyWithBundle, batchSellWithBundle, flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell, } from './portal-bundle.js';
|
|
22
|
-
// portal-bundle-merkle 子模块
|
|
23
|
-
export * from './portal-bundle-merkle/index.js';
|
|
24
|
-
// ✅ Tax Vault 金库模块(基于 VaultPortal + VaultFactory 规范)
|
|
25
|
-
export {
|
|
26
|
-
// 常量
|
|
27
|
-
NONE_EXTENSION_ID, VAULT_TYPE_LABELS, VAULT_TYPE_CATEGORIES, VAULT_FACTORY_ADDRESSES, VAULT_PORTAL_ADDRESSES, VAULT_PORTAL_ABI, VAULT_EXTRA_CONFIG, FLAP_GUARDIAN_ADDRESSES,
|
|
28
|
-
// ABI
|
|
29
|
-
VAULT_FACTORY_ABI, VAULT_FACTORY_V2_ABI, VAULT_BASE_ABI, VAULT_BASE_V2_ABI,
|
|
30
|
-
// 工具函数
|
|
31
|
-
encodeVaultData, buildVaultParams, buildVaultExtensionParams, getVaultFactoryAddress, getVaultPortalAddress,
|
|
32
|
-
// 链上查询
|
|
33
|
-
queryVaultDataSchema, queryVaultUISchema, queryVaultDescription, validateVaultFactory, getVaultInfo, isValidContract, } from './vault.js';
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export type TokenMetaInput = {
|
|
2
|
-
website?: string | null;
|
|
3
|
-
twitter?: string | null;
|
|
4
|
-
telegram?: string | null;
|
|
5
|
-
description: string;
|
|
6
|
-
creator: string;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* 上传代币元数据到 IPFS
|
|
10
|
-
* @param file 图片文件(File 对象)
|
|
11
|
-
* @param meta 元数据信息
|
|
12
|
-
* @param apiUrl IPFS GraphQL 端点(可选,默认使用 Flap 官方端点)
|
|
13
|
-
* @returns IPFS CID
|
|
14
|
-
*
|
|
15
|
-
* ⚠️ 注意:
|
|
16
|
-
* - 默认端点 (FLAP_IPFS_API_URL) 是占位符,可能不可用
|
|
17
|
-
* - 建议联系 Flap 团队获取真实的 IPFS GraphQL 端点
|
|
18
|
-
* - 或使用自己的 IPFS 服务(Pinata、Infura、Web3.Storage 等)
|
|
19
|
-
* - 或在 newTokenV2/newTokenV3 中直接传入 imageFile,让 SDK 自动处理
|
|
20
|
-
*/
|
|
21
|
-
export declare function uploadTokenMeta(file: File, meta: TokenMetaInput, apiUrl?: string): Promise<string>;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { FLAP_IPFS_API_URL } from './constants.js';
|
|
2
|
-
/**
|
|
3
|
-
* 上传代币元数据到 IPFS
|
|
4
|
-
* @param file 图片文件(File 对象)
|
|
5
|
-
* @param meta 元数据信息
|
|
6
|
-
* @param apiUrl IPFS GraphQL 端点(可选,默认使用 Flap 官方端点)
|
|
7
|
-
* @returns IPFS CID
|
|
8
|
-
*
|
|
9
|
-
* ⚠️ 注意:
|
|
10
|
-
* - 默认端点 (FLAP_IPFS_API_URL) 是占位符,可能不可用
|
|
11
|
-
* - 建议联系 Flap 团队获取真实的 IPFS GraphQL 端点
|
|
12
|
-
* - 或使用自己的 IPFS 服务(Pinata、Infura、Web3.Storage 等)
|
|
13
|
-
* - 或在 newTokenV2/newTokenV3 中直接传入 imageFile,让 SDK 自动处理
|
|
14
|
-
*/
|
|
15
|
-
export async function uploadTokenMeta(file, meta, apiUrl) {
|
|
16
|
-
const endpoint = apiUrl || FLAP_IPFS_API_URL;
|
|
17
|
-
// 如果使用默认端点,给出警告
|
|
18
|
-
if (!apiUrl && endpoint === FLAP_IPFS_API_URL) {
|
|
19
|
-
console.warn('⚠️ Warning: Using default IPFS endpoint which may not be available.\n' +
|
|
20
|
-
'Please either:\n' +
|
|
21
|
-
'1. Pass a valid IPFS GraphQL endpoint as the 3rd parameter\n' +
|
|
22
|
-
'2. Contact Flap team for the real IPFS endpoint\n' +
|
|
23
|
-
'3. Use your own IPFS service (Pinata, Infura, Web3.Storage, etc.)');
|
|
24
|
-
}
|
|
25
|
-
const form = new FormData();
|
|
26
|
-
const MUTATION_CREATE = `mutation Create($file: Upload!, $meta: MetadataInput!) { create(file: $file, meta: $meta) }`;
|
|
27
|
-
form.append('operations', JSON.stringify({ query: MUTATION_CREATE, variables: { file: null, meta } }));
|
|
28
|
-
form.append('map', JSON.stringify({ '0': ['variables.file'] }));
|
|
29
|
-
form.append('0', file);
|
|
30
|
-
const res = await fetch(endpoint, { method: 'POST', body: form });
|
|
31
|
-
if (!res.ok) {
|
|
32
|
-
throw new Error(`IPFS upload failed: ${res.statusText} (${res.status})\n` +
|
|
33
|
-
`Endpoint: ${endpoint}\n` +
|
|
34
|
-
`This endpoint may not be valid. Please provide a working IPFS GraphQL endpoint.`);
|
|
35
|
-
}
|
|
36
|
-
const j = await res.json();
|
|
37
|
-
return j?.data?.create;
|
|
38
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { JsonRpcProvider } from 'ethers';
|
|
2
|
-
export type FlapChain = 'BSC' | 'BASE' | 'XLAYER' | 'MORPH';
|
|
3
|
-
export type FetchMetaOptions = {
|
|
4
|
-
ipfsGateway?: string;
|
|
5
|
-
multicall3?: string;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* 根据代币地址直接读取合约 metaURI()/meta()(IPFS CID),并拉取元数据 JSON。
|
|
9
|
-
*/
|
|
10
|
-
export declare function getFlapMetaByAddress(chain: FlapChain, rpcUrl: string, tokenAddress: string, opts?: FetchMetaOptions): Promise<{
|
|
11
|
-
cid: string;
|
|
12
|
-
data?: any;
|
|
13
|
-
} | undefined>;
|
|
14
|
-
export declare function getFlapMetasByAddresses(chain: FlapChain, rpcUrl: string, tokenAddresses: string[], opts?: FetchMetaOptions): Promise<Array<{
|
|
15
|
-
token: string;
|
|
16
|
-
cid?: string;
|
|
17
|
-
data?: any;
|
|
18
|
-
imageUrl?: string;
|
|
19
|
-
error?: string;
|
|
20
|
-
}>>;
|
|
21
|
-
/**
|
|
22
|
-
* 使用 Multicall3 批量读取 metaURI()/meta(),metaURI 优先、meta 兜底。
|
|
23
|
-
*/
|
|
24
|
-
export declare function getFlapMetaUrisWithMulticall(provider: JsonRpcProvider, chain: FlapChain, tokenAddresses: string[], multicall3?: string, ipfsGateway?: string): Promise<Array<{
|
|
25
|
-
token: string;
|
|
26
|
-
cid?: string;
|
|
27
|
-
data?: any;
|
|
28
|
-
imageUrl?: string;
|
|
29
|
-
error?: string;
|
|
30
|
-
}>>;
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { JsonRpcProvider, Contract, Interface } from 'ethers';
|
|
2
|
-
import { ADDRESSES } from '../../utils/constants.js';
|
|
3
|
-
const DEFAULT_GATEWAYS = {
|
|
4
|
-
BSC: 'https://ipfs.io/ipfs/',
|
|
5
|
-
BASE: 'https://ipfs.io/ipfs/',
|
|
6
|
-
XLAYER: 'https://ipfs.io/ipfs/',
|
|
7
|
-
MORPH: 'https://ipfs.io/ipfs/'
|
|
8
|
-
};
|
|
9
|
-
function normalizeCid(cidOrUrl) {
|
|
10
|
-
if (!cidOrUrl)
|
|
11
|
-
return cidOrUrl;
|
|
12
|
-
if (cidOrUrl.startsWith('ipfs://'))
|
|
13
|
-
return cidOrUrl.slice('ipfs://'.length);
|
|
14
|
-
return cidOrUrl;
|
|
15
|
-
}
|
|
16
|
-
async function fetchIpfsJson(cid, gateway) {
|
|
17
|
-
const url = `${gateway}${normalizeCid(cid)}`;
|
|
18
|
-
const resp = await fetch(url);
|
|
19
|
-
if (!resp.ok)
|
|
20
|
-
throw new Error(`IPFS fetch failed: ${resp.status} ${await resp.text()}`);
|
|
21
|
-
return await resp.json();
|
|
22
|
-
}
|
|
23
|
-
async function readCidFromToken(provider, tokenAddress) {
|
|
24
|
-
const abi = [
|
|
25
|
-
'function metaURI() view returns (string)',
|
|
26
|
-
'function meta() view returns (string)'
|
|
27
|
-
];
|
|
28
|
-
const c = new Contract(tokenAddress, abi, provider);
|
|
29
|
-
try {
|
|
30
|
-
const v = await c.metaURI();
|
|
31
|
-
if (typeof v === 'string' && v.length > 0)
|
|
32
|
-
return v;
|
|
33
|
-
}
|
|
34
|
-
catch { }
|
|
35
|
-
try {
|
|
36
|
-
const v = await c.meta();
|
|
37
|
-
if (typeof v === 'string' && v.length > 0)
|
|
38
|
-
return v;
|
|
39
|
-
}
|
|
40
|
-
catch { }
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* 根据代币地址直接读取合约 metaURI()/meta()(IPFS CID),并拉取元数据 JSON。
|
|
45
|
-
*/
|
|
46
|
-
export async function getFlapMetaByAddress(chain, rpcUrl, tokenAddress, opts = {}) {
|
|
47
|
-
const provider = new JsonRpcProvider(rpcUrl);
|
|
48
|
-
// 优先尝试:直接从代币合约读取 metaURI()/meta()
|
|
49
|
-
try {
|
|
50
|
-
const onChainCid = await readCidFromToken(provider, tokenAddress);
|
|
51
|
-
if (onChainCid) {
|
|
52
|
-
const gateway = opts.ipfsGateway || DEFAULT_GATEWAYS[chain];
|
|
53
|
-
try {
|
|
54
|
-
const data = await fetchIpfsJson(onChainCid, gateway);
|
|
55
|
-
return { cid: onChainCid, data };
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return { cid: onChainCid };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
catch { }
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
export async function getFlapMetasByAddresses(chain, rpcUrl, tokenAddresses, opts = {}) {
|
|
66
|
-
if (!tokenAddresses?.length)
|
|
67
|
-
return [];
|
|
68
|
-
const provider = new JsonRpcProvider(rpcUrl);
|
|
69
|
-
const uris = await getFlapMetaUrisWithMulticall(provider, chain, tokenAddresses, opts.multicall3, opts.ipfsGateway);
|
|
70
|
-
const gateway = opts.ipfsGateway || DEFAULT_GATEWAYS[chain];
|
|
71
|
-
const results = await Promise.all(uris.map(async (u) => {
|
|
72
|
-
if (!u.cid)
|
|
73
|
-
return { token: u.token, error: u.error };
|
|
74
|
-
if (u.data || u.imageUrl) {
|
|
75
|
-
return { token: u.token, cid: u.cid, data: u.data, imageUrl: u.imageUrl };
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
const data = await fetchIpfsJson(u.cid, gateway);
|
|
79
|
-
return { token: u.token, cid: u.cid, data };
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return { token: u.token, cid: u.cid, imageUrl: `${gateway}${normalizeCid(u.cid)}` };
|
|
83
|
-
}
|
|
84
|
-
}));
|
|
85
|
-
return results;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* 使用 Multicall3 批量读取 metaURI()/meta(),metaURI 优先、meta 兜底。
|
|
89
|
-
*/
|
|
90
|
-
export async function getFlapMetaUrisWithMulticall(provider, chain, tokenAddresses, multicall3, ipfsGateway) {
|
|
91
|
-
// ✅ 所有链使用相同的 Multicall3 地址
|
|
92
|
-
const DEFAULT_MULTICALL3 = {
|
|
93
|
-
BSC: ADDRESSES.BSC.Multicall3,
|
|
94
|
-
BASE: ADDRESSES.BSC.Multicall3, // 所有链使用相同地址
|
|
95
|
-
XLAYER: ADDRESSES.BSC.Multicall3,
|
|
96
|
-
MORPH: ADDRESSES.BSC.Multicall3
|
|
97
|
-
};
|
|
98
|
-
const mcAddress = multicall3 || DEFAULT_MULTICALL3[chain];
|
|
99
|
-
const mcAbi = [
|
|
100
|
-
'function tryAggregate(bool requireSuccess, tuple(address target, bytes callData)[] calls) public returns (tuple(bool success, bytes returnData)[])'
|
|
101
|
-
];
|
|
102
|
-
const mc = new Contract(mcAddress, mcAbi, provider);
|
|
103
|
-
const iface = new Interface([
|
|
104
|
-
'function metaURI() view returns (string)',
|
|
105
|
-
'function meta() view returns (string)'
|
|
106
|
-
]);
|
|
107
|
-
// 第一轮:metaURI()
|
|
108
|
-
const callDataMetaURI = iface.encodeFunctionData('metaURI', []);
|
|
109
|
-
const calls1 = tokenAddresses.map((t) => ({ target: t, callData: callDataMetaURI }));
|
|
110
|
-
let res1 = [];
|
|
111
|
-
try {
|
|
112
|
-
res1 = await mc.tryAggregate(false, calls1);
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
// 如果 multicall 不可用,降级为逐个查询
|
|
116
|
-
const fallbacks = await Promise.all(tokenAddresses.map(async (t) => {
|
|
117
|
-
try {
|
|
118
|
-
const cid = await readCidFromToken(provider, t);
|
|
119
|
-
return { token: t, cid };
|
|
120
|
-
}
|
|
121
|
-
catch (err) {
|
|
122
|
-
return { token: t, error: String(err?.message || err) };
|
|
123
|
-
}
|
|
124
|
-
}));
|
|
125
|
-
return fallbacks;
|
|
126
|
-
}
|
|
127
|
-
const needMeta = [];
|
|
128
|
-
const interim = tokenAddresses.map((t, i) => {
|
|
129
|
-
const r = res1[i];
|
|
130
|
-
if (r && r.success && r.returnData && r.returnData !== '0x') {
|
|
131
|
-
try {
|
|
132
|
-
const [uri] = iface.decodeFunctionResult('metaURI', r.returnData);
|
|
133
|
-
return { token: t, cid: String(uri) };
|
|
134
|
-
}
|
|
135
|
-
catch (e) {
|
|
136
|
-
needMeta.push(t);
|
|
137
|
-
return { token: t };
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
needMeta.push(t);
|
|
141
|
-
return { token: t };
|
|
142
|
-
});
|
|
143
|
-
if (needMeta.length === 0) {
|
|
144
|
-
// 尝试拉取 JSON,否则返回 imageUrl
|
|
145
|
-
const gateway = ipfsGateway || DEFAULT_GATEWAYS[chain];
|
|
146
|
-
const enriched = await Promise.all(interim.map(async (x) => {
|
|
147
|
-
if (!x.cid)
|
|
148
|
-
return x;
|
|
149
|
-
try {
|
|
150
|
-
const data = await fetchIpfsJson(x.cid, gateway);
|
|
151
|
-
return { ...x, data };
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
return { ...x, imageUrl: `${gateway}${normalizeCid(x.cid)}` };
|
|
155
|
-
}
|
|
156
|
-
}));
|
|
157
|
-
return enriched;
|
|
158
|
-
}
|
|
159
|
-
// 第二轮:meta() 兜底
|
|
160
|
-
const callDataMeta = iface.encodeFunctionData('meta', []);
|
|
161
|
-
const calls2 = needMeta.map((t) => ({ target: t, callData: callDataMeta }));
|
|
162
|
-
const res2 = await mc.tryAggregate(false, calls2);
|
|
163
|
-
let idx = 0;
|
|
164
|
-
for (let i = 0; i < interim.length; i++) {
|
|
165
|
-
if (interim[i].cid)
|
|
166
|
-
continue;
|
|
167
|
-
const r = res2[idx++];
|
|
168
|
-
if (r && r.success && r.returnData && r.returnData !== '0x') {
|
|
169
|
-
try {
|
|
170
|
-
const [uri] = iface.decodeFunctionResult('meta', r.returnData);
|
|
171
|
-
interim[i].cid = String(uri);
|
|
172
|
-
}
|
|
173
|
-
catch (e) {
|
|
174
|
-
interim[i].error = String(e?.message || e);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
interim[i].error = 'meta() call failed';
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
// 为所有项填充 data 或 imageUrl
|
|
182
|
-
const gateway = ipfsGateway || DEFAULT_GATEWAYS[chain];
|
|
183
|
-
const enriched = await Promise.all(interim.map(async (x) => {
|
|
184
|
-
if (!x.cid)
|
|
185
|
-
return x;
|
|
186
|
-
try {
|
|
187
|
-
const data = await fetchIpfsJson(x.cid, gateway);
|
|
188
|
-
return { ...x, data };
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
return { ...x, imageUrl: `${gateway}${normalizeCid(x.cid)}` };
|
|
192
|
-
}
|
|
193
|
-
}));
|
|
194
|
-
return enriched;
|
|
195
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 构建 Permit Piggyback 数据
|
|
3
|
-
* 自动签名并使用正确的 Portal 代理地址
|
|
4
|
-
*
|
|
5
|
-
* @param chain 链名称
|
|
6
|
-
* @param privateKey 用户私钥
|
|
7
|
-
* @param tokenAddress ERC20 代币地址(需要支持 EIP-2612 Permit)
|
|
8
|
-
* @param value 授权金额
|
|
9
|
-
* @param deadline 截止时间戳
|
|
10
|
-
* @param nonce Permit nonce(通常从代币合约的 nonces(owner) 获取)
|
|
11
|
-
* @returns Permit Piggyback 编码数据(Hex string)
|
|
12
|
-
*/
|
|
13
|
-
export declare function buildPermitPiggybackAuto(chain: 'BSC' | 'BASE' | 'XLAYER' | 'MORPH', privateKey: string, tokenAddress: string, value: bigint, deadline: bigint, nonce: bigint, opts?: {
|
|
14
|
-
rpcUrl?: string;
|
|
15
|
-
tokenNameOverride?: string;
|
|
16
|
-
}): Promise<string>;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Wallet, AbiCoder, Contract, JsonRpcProvider } from 'ethers';
|
|
2
|
-
import { FLAP_PORTAL_ADDRESSES } from './constants.js';
|
|
3
|
-
import { CHAIN } from '../../utils/constants.js';
|
|
4
|
-
/**
|
|
5
|
-
* 构建 Permit Piggyback 数据
|
|
6
|
-
* 自动签名并使用正确的 Portal 代理地址
|
|
7
|
-
*
|
|
8
|
-
* @param chain 链名称
|
|
9
|
-
* @param privateKey 用户私钥
|
|
10
|
-
* @param tokenAddress ERC20 代币地址(需要支持 EIP-2612 Permit)
|
|
11
|
-
* @param value 授权金额
|
|
12
|
-
* @param deadline 截止时间戳
|
|
13
|
-
* @param nonce Permit nonce(通常从代币合约的 nonces(owner) 获取)
|
|
14
|
-
* @returns Permit Piggyback 编码数据(Hex string)
|
|
15
|
-
*/
|
|
16
|
-
export async function buildPermitPiggybackAuto(chain, privateKey, tokenAddress, value, deadline, nonce, opts) {
|
|
17
|
-
const spender = FLAP_PORTAL_ADDRESSES[chain];
|
|
18
|
-
if (!spender) {
|
|
19
|
-
throw new Error(`Flap Portal not deployed on ${chain}`);
|
|
20
|
-
}
|
|
21
|
-
// 创建钱包
|
|
22
|
-
const wallet = new Wallet(privateKey);
|
|
23
|
-
const owner = wallet.address;
|
|
24
|
-
// 获取 chainId
|
|
25
|
-
const chainId = CHAIN[chain].chainId;
|
|
26
|
-
// 读取代币 name(优先 override,其次链上查询,不可用时回退为空字符串)
|
|
27
|
-
let tokenName = opts?.tokenNameOverride ?? '';
|
|
28
|
-
if (!tokenName && opts?.rpcUrl) {
|
|
29
|
-
try {
|
|
30
|
-
const erc20 = new Contract(tokenAddress, ['function name() view returns (string)'], new JsonRpcProvider(opts.rpcUrl));
|
|
31
|
-
tokenName = await erc20.name();
|
|
32
|
-
}
|
|
33
|
-
catch { }
|
|
34
|
-
}
|
|
35
|
-
// 构建 EIP-2612 Permit 消息(name 可能为空字符串,符合部分实现)
|
|
36
|
-
const domain = {
|
|
37
|
-
name: tokenName,
|
|
38
|
-
version: '1',
|
|
39
|
-
chainId,
|
|
40
|
-
verifyingContract: tokenAddress,
|
|
41
|
-
};
|
|
42
|
-
const types = {
|
|
43
|
-
Permit: [
|
|
44
|
-
{ name: 'owner', type: 'address' },
|
|
45
|
-
{ name: 'spender', type: 'address' },
|
|
46
|
-
{ name: 'value', type: 'uint256' },
|
|
47
|
-
{ name: 'nonce', type: 'uint256' },
|
|
48
|
-
{ name: 'deadline', type: 'uint256' },
|
|
49
|
-
],
|
|
50
|
-
};
|
|
51
|
-
const message = {
|
|
52
|
-
owner,
|
|
53
|
-
spender,
|
|
54
|
-
value: value.toString(),
|
|
55
|
-
nonce: nonce.toString(),
|
|
56
|
-
deadline: deadline.toString(),
|
|
57
|
-
};
|
|
58
|
-
// 签名
|
|
59
|
-
const signature = await wallet.signTypedData(domain, types, message);
|
|
60
|
-
// 解析签名为 v, r, s
|
|
61
|
-
const r = `0x${signature.slice(2, 66)}`;
|
|
62
|
-
const s = `0x${signature.slice(66, 130)}`;
|
|
63
|
-
const v = parseInt(signature.slice(130, 132), 16);
|
|
64
|
-
// 使用 ethers AbiCoder 编码 Permit Piggyback 数据
|
|
65
|
-
const abiCoder = AbiCoder.defaultAbiCoder();
|
|
66
|
-
return abiCoder.encode(['address', 'address', 'uint256', 'uint256', 'uint8', 'bytes32', 'bytes32'], [owner, spender, value, deadline, v, r, s]);
|
|
67
|
-
}
|