four-flap-meme-sdk 1.8.7 → 1.8.8
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/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/shared/flap/index.d.ts +1 -0
- package/dist/shared/flap/index.js +8 -0
- package/dist/shared/flap/portal-bundle-merkle/core.js +7 -2
- package/dist/shared/flap/portal-bundle-merkle/create-to-dex.d.ts +2 -0
- package/dist/shared/flap/portal-bundle-merkle/create-to-dex.js +7 -2
- package/dist/shared/flap/portal-bundle-merkle/index.js +3 -0
- package/dist/shared/flap/portal-bundle-merkle/types.d.ts +3 -0
- package/dist/shared/flap/vault.d.ts +204 -0
- package/dist/shared/flap/vault.js +288 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export { flapBundleBuyFirstMerkle, type FlapBuyFirstSignConfig, type FlapBuyFirs
|
|
|
50
50
|
export { pancakeBundleBuyFirstMerkle, type PancakeBuyFirstSignConfig, type PancakeBuyFirstConfig, type PancakeBundleBuyFirstSignParams, type PancakeBundleBuyFirstParams, type PancakeBuyFirstResult } from './chains/bsc/pancake/bundle-buy-first.js';
|
|
51
51
|
export { flapBundleCurveToDex, type CurveToDexChain, type DexPoolType, type CurveToDexSignConfig, type CurveBuyerConfig, type DexBuyerConfig, type FlapCurveToDexParams, type FlapCurveToDexResult } from './shared/flap/portal-bundle-merkle/curve-to-dex.js';
|
|
52
52
|
export { flapBundleCreateToDex, type CreateToDexChain, type CreateToDexSignConfig, type CreateTokenInfo, type FlapCreateToDexParams, type FlapCreateToDexResult } from './shared/flap/portal-bundle-merkle/create-to-dex.js';
|
|
53
|
+
export { VAULT_EXTENSION_IDS, VAULT_TYPE_LABELS, TAX_VAULT_ABI, VAULT_FACTORY_ABI, type VaultType, type TaxVaultConfig, type VaultInfo, type VaultRewards, getVaultExtensionId, encodeVaultExtensionData, buildVaultExtensionParams, getVaultTypeFromExtensionId, getVaultInfo, getVaultRewards, claimVaultRewards, isValidVaultContract, } from './shared/flap/vault.js';
|
|
53
54
|
export { PROFIT_CONFIG } from './shared/constants/index.js';
|
|
54
55
|
export { quoteV2, quoteV3, quote, getTokenToNativeQuote, getNativeToTokenQuote, getWrappedNativeAddress, // ✅ 来自 quote-helpers,与 shared/constants 同名但实现可能不同
|
|
55
56
|
getStableCoins, V3_FEE_TIERS, // ✅ 来自 quote-helpers
|
package/dist/index.js
CHANGED
|
@@ -95,6 +95,8 @@ export { pancakeBundleBuyFirstMerkle } from './chains/bsc/pancake/bundle-buy-fir
|
|
|
95
95
|
export { flapBundleCurveToDex } from './shared/flap/portal-bundle-merkle/curve-to-dex.js';
|
|
96
96
|
// ✅ 发币 + 一键买到外盘(Create → Curve → DEX)- 新代币
|
|
97
97
|
export { flapBundleCreateToDex } from './shared/flap/portal-bundle-merkle/create-to-dex.js';
|
|
98
|
+
// ✅ Tax Vault 金库模块
|
|
99
|
+
export { VAULT_EXTENSION_IDS, VAULT_TYPE_LABELS, TAX_VAULT_ABI, VAULT_FACTORY_ABI, getVaultExtensionId, encodeVaultExtensionData, buildVaultExtensionParams, getVaultTypeFromExtensionId, getVaultInfo, getVaultRewards, claimVaultRewards, isValidVaultContract, } from './shared/flap/vault.js';
|
|
98
100
|
// ✅ 硬编码利润配置(统一管理)- 从 shared/constants 导出
|
|
99
101
|
export { PROFIT_CONFIG } from './shared/constants/index.js';
|
|
100
102
|
// ✅ V2/V3 报价工具(统一管理)
|
|
@@ -19,3 +19,4 @@ export { FLAP_DEFAULT_FEE_RATES, FLAP_IPFS_API_URL, FLAP_VANITY_SUFFIX, FLAP_DEX
|
|
|
19
19
|
export * from './abi.js';
|
|
20
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
21
|
export * from './portal-bundle-merkle/index.js';
|
|
22
|
+
export { VAULT_EXTENSION_IDS, VAULT_TYPE_LABELS, TAX_VAULT_ABI, VAULT_FACTORY_ABI, type VaultType, type TaxVaultConfig, type VaultInfo, type VaultRewards, getVaultExtensionId, encodeVaultExtensionData, buildVaultExtensionParams, getVaultTypeFromExtensionId, getVaultInfo, getVaultRewards, claimVaultRewards, isValidVaultContract, } from './vault.js';
|
|
@@ -21,3 +21,11 @@ export * from './abi.js';
|
|
|
21
21
|
export { createTokenWithBundleBuy, batchBuyWithBundle, batchSellWithBundle, flapPrivateBuy, flapPrivateSell, flapBatchPrivateBuy, flapBatchPrivateSell, } from './portal-bundle.js';
|
|
22
22
|
// portal-bundle-merkle 子模块
|
|
23
23
|
export * from './portal-bundle-merkle/index.js';
|
|
24
|
+
// ✅ Tax Vault 金库模块
|
|
25
|
+
export {
|
|
26
|
+
// 常量
|
|
27
|
+
VAULT_EXTENSION_IDS, VAULT_TYPE_LABELS, TAX_VAULT_ABI, VAULT_FACTORY_ABI,
|
|
28
|
+
// 编码/解码工具
|
|
29
|
+
getVaultExtensionId, encodeVaultExtensionData, buildVaultExtensionParams, getVaultTypeFromExtensionId,
|
|
30
|
+
// 链上查询
|
|
31
|
+
getVaultInfo, getVaultRewards, claimVaultRewards, isValidVaultContract, } from './vault.js';
|
|
@@ -4,6 +4,7 @@ import { ADDRESSES, ZERO_ADDRESS } from '../../../utils/constants.js';
|
|
|
4
4
|
import { GAS_LIMITS, CHAINS } from '../../constants/index.js';
|
|
5
5
|
import { MULTICALL3_ABI, V2_ROUTER_QUOTE_ABI } from '../../abis/common.js';
|
|
6
6
|
import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
|
|
7
|
+
import { buildVaultExtensionParams } from '../vault.js';
|
|
7
8
|
import { CHAIN_ID_MAP, PORTAL_ABI, getErrorMessage, getTxType, getGasPriceConfig, shouldExtractProfit, calculateProfit, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA } from './config.js';
|
|
8
9
|
// ✅ 常量
|
|
9
10
|
const MULTICALL3_ADDRESS = ADDRESSES.BSC.Multicall3;
|
|
@@ -119,6 +120,10 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
119
120
|
if (total !== 10000) {
|
|
120
121
|
throw new Error(`Tax distribution must sum to 10000 (100%), got ${total}`);
|
|
121
122
|
}
|
|
123
|
+
// ✅ 如果配置了 Tax Vault,使用金库的 extensionID/extensionData
|
|
124
|
+
const vaultParams = buildVaultExtensionParams(tv2.vaultConfig);
|
|
125
|
+
const finalExtensionID = params.extensionID || vaultParams.extensionID;
|
|
126
|
+
const finalExtensionData = params.extensionData || vaultParams.extensionData;
|
|
122
127
|
createTxPromise = portal.newTokenV5.populateTransaction({
|
|
123
128
|
name: tokenInfo.name,
|
|
124
129
|
symbol: tokenInfo.symbol,
|
|
@@ -131,8 +136,8 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
131
136
|
quoteAmt: 0n,
|
|
132
137
|
beneficiary: devWallet.address,
|
|
133
138
|
permitData: '0x',
|
|
134
|
-
extensionID:
|
|
135
|
-
extensionData:
|
|
139
|
+
extensionID: finalExtensionID,
|
|
140
|
+
extensionData: finalExtensionData,
|
|
136
141
|
dexId: (params.dexId ?? 0) & 0xff,
|
|
137
142
|
lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff,
|
|
138
143
|
taxDuration: BigInt(tv2.taxDuration),
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
11
11
|
import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../../utils/bundle-helpers.js';
|
|
12
12
|
import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
|
|
13
|
+
import { buildVaultExtensionParams } from '../vault.js';
|
|
13
14
|
import { PROFIT_CONFIG, ZERO_ADDRESS } from '../../../utils/constants.js';
|
|
14
15
|
import { GAS_LIMITS } from '../../constants/index.js';
|
|
15
16
|
import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
|
|
@@ -333,6 +334,10 @@ export async function flapBundleCreateToDex(params) {
|
|
|
333
334
|
if (total !== 10000) {
|
|
334
335
|
throw new Error(`Tax distribution must sum to 10000 (100%), got ${total}`);
|
|
335
336
|
}
|
|
337
|
+
// ✅ 如果配置了 Tax Vault,使用金库的 extensionID/extensionData
|
|
338
|
+
const vaultParams = buildVaultExtensionParams(tv2.vaultConfig);
|
|
339
|
+
const finalExtensionID = params.extensionID || vaultParams.extensionID;
|
|
340
|
+
const finalExtensionData = params.extensionData || vaultParams.extensionData;
|
|
336
341
|
createUnsigned = await originalPortal.newTokenV5.populateTransaction({
|
|
337
342
|
name: tokenInfo.name,
|
|
338
343
|
symbol: tokenInfo.symbol,
|
|
@@ -345,8 +350,8 @@ export async function flapBundleCreateToDex(params) {
|
|
|
345
350
|
quoteAmt: 0n,
|
|
346
351
|
beneficiary: devWallet.address,
|
|
347
352
|
permitData: '0x',
|
|
348
|
-
extensionID:
|
|
349
|
-
extensionData:
|
|
353
|
+
extensionID: finalExtensionID,
|
|
354
|
+
extensionData: finalExtensionData,
|
|
350
355
|
dexId: (params.dexId ?? 0) & 0xff,
|
|
351
356
|
lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff,
|
|
352
357
|
// Tax Token V2 专属字段
|
|
@@ -21,3 +21,6 @@ export { flapBundleCurveToDex } from './curve-to-dex.js';
|
|
|
21
21
|
export { flapBundleCreateToDex } from './create-to-dex.js';
|
|
22
22
|
// ✅ 内盘换手方法(一卖一买、一卖多买、快捷资金利用率、交叉换手)
|
|
23
23
|
export { flapBundleSwapMerkle, flapBatchSwapMerkle, flapQuickBatchSwapMerkle, flapCrossSwapMerkle } from './swap.js';
|
|
24
|
+
// ✅ Tax Vault 金库类型(types.ts 中 TaxV2Config.vaultConfig 使用的类型)
|
|
25
|
+
// 注意:TaxVaultConfig 完整导出在 flap/index.ts → vault.js 中
|
|
26
|
+
// 这里仅从 types.ts 导出 TaxV2Config 中嵌套使用时的类型引用
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GeneratedWallet } from '../../../utils/wallet.js';
|
|
2
|
+
import type { TaxVaultConfig } from '../vault.js';
|
|
2
3
|
/**
|
|
3
4
|
* ✅ 利润模式:
|
|
4
5
|
* - 'single': 单一模式(默认),从金额最大的钱包统一扣除所有利润,只有一组多跳交易
|
|
@@ -32,6 +33,8 @@ export type TaxV2Config = {
|
|
|
32
33
|
antiFarmerDuration: number;
|
|
33
34
|
/** 税收分配配置 */
|
|
34
35
|
distribution: TaxDistributionConfig;
|
|
36
|
+
/** ✅ Tax Vault 金库配置(可选) */
|
|
37
|
+
vaultConfig?: TaxVaultConfig;
|
|
35
38
|
};
|
|
36
39
|
export type FlapSignConfig = {
|
|
37
40
|
rpcUrl: string;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flap Tax Vaults(税收金库)
|
|
3
|
+
*
|
|
4
|
+
* Tax Vaults 是 Flap Protocol 的扩展功能,允许开发者创建自定义智能合约
|
|
5
|
+
* 来管理税收代币的税费收入。通过 newTokenV5 的 extensionID/extensionData 参数集成。
|
|
6
|
+
*
|
|
7
|
+
* 工作原理:
|
|
8
|
+
* 1. extensionID = 金库类型标识符(bytes32)
|
|
9
|
+
* 2. extensionData = ABI 编码的金库初始化参数
|
|
10
|
+
* 3. 代币创建后,税费自动流入金库合约
|
|
11
|
+
* 4. 金库合约根据预设规则分配税费收入
|
|
12
|
+
*
|
|
13
|
+
* @module vault
|
|
14
|
+
*/
|
|
15
|
+
import { type JsonRpcProvider, type Wallet } from 'ethers';
|
|
16
|
+
/**
|
|
17
|
+
* Flap 预定义金库扩展 ID
|
|
18
|
+
*
|
|
19
|
+
* 这些 ID 用于标识金库类型,作为 newTokenV5 的 extensionID 参数
|
|
20
|
+
* 计算方式:keccak256(vaultTypeName)
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ 注意:当 Flap 官方发布正式的 Vault Extension ID 时,需要更新这些值
|
|
23
|
+
*/
|
|
24
|
+
export declare const VAULT_EXTENSION_IDS: {
|
|
25
|
+
/** 无金库(默认) */
|
|
26
|
+
readonly NONE: string;
|
|
27
|
+
/** 标准税收金库 - 累积税费并允许受益人提取 */
|
|
28
|
+
readonly STANDARD: string;
|
|
29
|
+
/** 自动回购金库 - 税费用于自动回购代币并销毁 */
|
|
30
|
+
readonly AUTO_BUYBACK: string;
|
|
31
|
+
/** 分红金库 - 税费按持仓比例分配给持有者 */
|
|
32
|
+
readonly DIVIDEND: string;
|
|
33
|
+
/** 流动性金库 - 税费自动添加到流动性池 */
|
|
34
|
+
readonly LIQUIDITY: string;
|
|
35
|
+
/** 自定义金库 - 用户部署的自定义合约 */
|
|
36
|
+
readonly CUSTOM: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* 金库类型标签(用于 UI 显示)
|
|
40
|
+
*/
|
|
41
|
+
export declare const VAULT_TYPE_LABELS: Record<string, string>;
|
|
42
|
+
/** 金库类型枚举 */
|
|
43
|
+
export type VaultType = 'none' | 'standard' | 'auto_buyback' | 'dividend' | 'liquidity' | 'custom';
|
|
44
|
+
/**
|
|
45
|
+
* Tax Vault 配置
|
|
46
|
+
* 用于在创建代币时指定金库设置
|
|
47
|
+
*/
|
|
48
|
+
export interface TaxVaultConfig {
|
|
49
|
+
/** 金库类型 */
|
|
50
|
+
vaultType: VaultType;
|
|
51
|
+
/**
|
|
52
|
+
* 自定义金库合约地址
|
|
53
|
+
* 仅当 vaultType === 'custom' 时必填
|
|
54
|
+
* 合约必须实现 ITaxVault 接口
|
|
55
|
+
*/
|
|
56
|
+
vaultAddress?: string;
|
|
57
|
+
/**
|
|
58
|
+
* 自定义扩展 ID(bytes32)
|
|
59
|
+
* 高级用法:直接指定 extensionID,覆盖 vaultType 对应的默认值
|
|
60
|
+
*/
|
|
61
|
+
customExtensionId?: string;
|
|
62
|
+
/**
|
|
63
|
+
* 自定义扩展数据(hex)
|
|
64
|
+
* 高级用法:直接指定 extensionData
|
|
65
|
+
* 不提供时,SDK 将根据 vaultType 自动编码
|
|
66
|
+
*/
|
|
67
|
+
customExtensionData?: string;
|
|
68
|
+
/**
|
|
69
|
+
* 自动回购参数(vaultType === 'auto_buyback' 时使用)
|
|
70
|
+
*/
|
|
71
|
+
buybackConfig?: {
|
|
72
|
+
/** 回购间隔(秒) */
|
|
73
|
+
interval: number;
|
|
74
|
+
/** 每次回购的最大金额(原生代币,wei) */
|
|
75
|
+
maxAmount: bigint;
|
|
76
|
+
/** 回购的代币是否销毁(true=销毁,false=发送到 beneficiary) */
|
|
77
|
+
burnAfterBuy: boolean;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* 分红参数(vaultType === 'dividend' 时使用)
|
|
81
|
+
*/
|
|
82
|
+
dividendConfig?: {
|
|
83
|
+
/** 最低持仓门槛(代币数量,ether 单位) */
|
|
84
|
+
minimumBalance: number;
|
|
85
|
+
/** 分红周期(秒) */
|
|
86
|
+
distributionInterval: number;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* 流动性参数(vaultType === 'liquidity' 时使用)
|
|
90
|
+
*/
|
|
91
|
+
liquidityConfig?: {
|
|
92
|
+
/** 自动添加流动性的触发阈值(原生代币,ether 单位) */
|
|
93
|
+
threshold: number;
|
|
94
|
+
/** 添加到的 DEX 池类型 */
|
|
95
|
+
poolType: 'v2' | 'v3';
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 金库信息(链上查询结果)
|
|
100
|
+
*/
|
|
101
|
+
export interface VaultInfo {
|
|
102
|
+
/** 金库合约地址 */
|
|
103
|
+
address: string;
|
|
104
|
+
/** 金库中的代币余额 */
|
|
105
|
+
tokenBalance: bigint;
|
|
106
|
+
/** 金库中的原生代币余额 */
|
|
107
|
+
nativeBalance: bigint;
|
|
108
|
+
/** 金库所有者 */
|
|
109
|
+
owner: string;
|
|
110
|
+
/** 关联的代币地址 */
|
|
111
|
+
tokenAddress: string;
|
|
112
|
+
/** 是否已激活 */
|
|
113
|
+
isActive: boolean;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 金库奖励信息
|
|
117
|
+
*/
|
|
118
|
+
export interface VaultRewards {
|
|
119
|
+
/** 待领取的代币奖励 */
|
|
120
|
+
pendingTokenRewards: bigint;
|
|
121
|
+
/** 待领取的原生代币奖励 */
|
|
122
|
+
pendingNativeRewards: bigint;
|
|
123
|
+
/** 已领取的总代币奖励 */
|
|
124
|
+
claimedTokenRewards: bigint;
|
|
125
|
+
/** 已领取的总原生代币奖励 */
|
|
126
|
+
claimedNativeRewards: bigint;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* ITaxVault 接口 ABI
|
|
130
|
+
* 所有 Flap Tax Vault 合约必须实现此接口
|
|
131
|
+
*
|
|
132
|
+
* ⚠️ 注意:这是基于 Flap 文档推断的标准接口
|
|
133
|
+
* 当官方发布正式接口规范时,需要更新此 ABI
|
|
134
|
+
*/
|
|
135
|
+
export declare const TAX_VAULT_ABI: string[];
|
|
136
|
+
/**
|
|
137
|
+
* Vault Factory ABI
|
|
138
|
+
* 用于部署新的金库合约
|
|
139
|
+
*/
|
|
140
|
+
export declare const VAULT_FACTORY_ABI: string[];
|
|
141
|
+
/**
|
|
142
|
+
* 根据 VaultType 获取对应的 extensionID
|
|
143
|
+
*/
|
|
144
|
+
export declare function getVaultExtensionId(vaultType: VaultType): string;
|
|
145
|
+
/**
|
|
146
|
+
* 编码金库配置为 extensionData
|
|
147
|
+
*
|
|
148
|
+
* @param config - 金库配置
|
|
149
|
+
* @returns ABI 编码的 extensionData(hex string)
|
|
150
|
+
*/
|
|
151
|
+
export declare function encodeVaultExtensionData(config: TaxVaultConfig): string;
|
|
152
|
+
/**
|
|
153
|
+
* 将 TaxVaultConfig 转换为 newTokenV5 需要的 extensionID 和 extensionData
|
|
154
|
+
*
|
|
155
|
+
* @param config - 金库配置
|
|
156
|
+
* @returns { extensionID, extensionData }
|
|
157
|
+
*/
|
|
158
|
+
export declare function buildVaultExtensionParams(config?: TaxVaultConfig): {
|
|
159
|
+
extensionID: string;
|
|
160
|
+
extensionData: string;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* 查询金库信息
|
|
164
|
+
*
|
|
165
|
+
* @param provider - RPC Provider
|
|
166
|
+
* @param vaultAddress - 金库合约地址
|
|
167
|
+
* @returns 金库信息
|
|
168
|
+
*/
|
|
169
|
+
export declare function getVaultInfo(provider: JsonRpcProvider, vaultAddress: string): Promise<VaultInfo | null>;
|
|
170
|
+
/**
|
|
171
|
+
* 查询用户在金库中的奖励
|
|
172
|
+
*
|
|
173
|
+
* @param provider - RPC Provider
|
|
174
|
+
* @param vaultAddress - 金库合约地址
|
|
175
|
+
* @param userAddress - 用户地址
|
|
176
|
+
* @returns 奖励信息
|
|
177
|
+
*/
|
|
178
|
+
export declare function getVaultRewards(provider: JsonRpcProvider, vaultAddress: string, userAddress: string): Promise<VaultRewards>;
|
|
179
|
+
/**
|
|
180
|
+
* 从金库领取奖励
|
|
181
|
+
*
|
|
182
|
+
* @param wallet - 签名钱包
|
|
183
|
+
* @param vaultAddress - 金库合约地址
|
|
184
|
+
* @returns 交易收据
|
|
185
|
+
*/
|
|
186
|
+
export declare function claimVaultRewards(wallet: Wallet, vaultAddress: string): Promise<{
|
|
187
|
+
txHash: string;
|
|
188
|
+
amount: bigint;
|
|
189
|
+
}>;
|
|
190
|
+
/**
|
|
191
|
+
* 验证金库合约是否有效(是否部署了代码)
|
|
192
|
+
*
|
|
193
|
+
* @param provider - RPC Provider
|
|
194
|
+
* @param vaultAddress - 金库合约地址
|
|
195
|
+
* @returns 是否为有效合约
|
|
196
|
+
*/
|
|
197
|
+
export declare function isValidVaultContract(provider: JsonRpcProvider, vaultAddress: string): Promise<boolean>;
|
|
198
|
+
/**
|
|
199
|
+
* 获取代币关联的金库地址(通过 extensionID 推断)
|
|
200
|
+
*
|
|
201
|
+
* @param extensionID - 代币的 extensionID(从 getTokenV5 获取)
|
|
202
|
+
* @returns 金库类型
|
|
203
|
+
*/
|
|
204
|
+
export declare function getVaultTypeFromExtensionId(extensionID: string): VaultType;
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flap Tax Vaults(税收金库)
|
|
3
|
+
*
|
|
4
|
+
* Tax Vaults 是 Flap Protocol 的扩展功能,允许开发者创建自定义智能合约
|
|
5
|
+
* 来管理税收代币的税费收入。通过 newTokenV5 的 extensionID/extensionData 参数集成。
|
|
6
|
+
*
|
|
7
|
+
* 工作原理:
|
|
8
|
+
* 1. extensionID = 金库类型标识符(bytes32)
|
|
9
|
+
* 2. extensionData = ABI 编码的金库初始化参数
|
|
10
|
+
* 3. 代币创建后,税费自动流入金库合约
|
|
11
|
+
* 4. 金库合约根据预设规则分配税费收入
|
|
12
|
+
*
|
|
13
|
+
* @module vault
|
|
14
|
+
*/
|
|
15
|
+
import { Contract, AbiCoder, keccak256, toUtf8Bytes, ZeroAddress } from 'ethers';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// 常量
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Flap 预定义金库扩展 ID
|
|
21
|
+
*
|
|
22
|
+
* 这些 ID 用于标识金库类型,作为 newTokenV5 的 extensionID 参数
|
|
23
|
+
* 计算方式:keccak256(vaultTypeName)
|
|
24
|
+
*
|
|
25
|
+
* ⚠️ 注意:当 Flap 官方发布正式的 Vault Extension ID 时,需要更新这些值
|
|
26
|
+
*/
|
|
27
|
+
export const VAULT_EXTENSION_IDS = {
|
|
28
|
+
/** 无金库(默认) */
|
|
29
|
+
NONE: '0x' + '00'.repeat(32),
|
|
30
|
+
/** 标准税收金库 - 累积税费并允许受益人提取 */
|
|
31
|
+
STANDARD: keccak256(toUtf8Bytes('FlapTaxVault.Standard')),
|
|
32
|
+
/** 自动回购金库 - 税费用于自动回购代币并销毁 */
|
|
33
|
+
AUTO_BUYBACK: keccak256(toUtf8Bytes('FlapTaxVault.AutoBuyback')),
|
|
34
|
+
/** 分红金库 - 税费按持仓比例分配给持有者 */
|
|
35
|
+
DIVIDEND: keccak256(toUtf8Bytes('FlapTaxVault.Dividend')),
|
|
36
|
+
/** 流动性金库 - 税费自动添加到流动性池 */
|
|
37
|
+
LIQUIDITY: keccak256(toUtf8Bytes('FlapTaxVault.Liquidity')),
|
|
38
|
+
/** 自定义金库 - 用户部署的自定义合约 */
|
|
39
|
+
CUSTOM: keccak256(toUtf8Bytes('FlapTaxVault.Custom')),
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* 金库类型标签(用于 UI 显示)
|
|
43
|
+
*/
|
|
44
|
+
export const VAULT_TYPE_LABELS = {
|
|
45
|
+
none: '无金库(标准税收)',
|
|
46
|
+
standard: '标准税收金库',
|
|
47
|
+
auto_buyback: '自动回购金库',
|
|
48
|
+
dividend: '分红金库',
|
|
49
|
+
liquidity: '流动性金库',
|
|
50
|
+
custom: '自定义金库',
|
|
51
|
+
};
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// ABI 定义
|
|
54
|
+
// ============================================================================
|
|
55
|
+
/**
|
|
56
|
+
* ITaxVault 接口 ABI
|
|
57
|
+
* 所有 Flap Tax Vault 合约必须实现此接口
|
|
58
|
+
*
|
|
59
|
+
* ⚠️ 注意:这是基于 Flap 文档推断的标准接口
|
|
60
|
+
* 当官方发布正式接口规范时,需要更新此 ABI
|
|
61
|
+
*/
|
|
62
|
+
export const TAX_VAULT_ABI = [
|
|
63
|
+
// 查询方法
|
|
64
|
+
'function token() external view returns (address)',
|
|
65
|
+
'function owner() external view returns (address)',
|
|
66
|
+
'function isActive() external view returns (bool)',
|
|
67
|
+
'function totalTaxCollected() external view returns (uint256)',
|
|
68
|
+
'function pendingRewards(address user) external view returns (uint256)',
|
|
69
|
+
'function claimedRewards(address user) external view returns (uint256)',
|
|
70
|
+
// 写入方法
|
|
71
|
+
'function claimRewards() external returns (uint256)',
|
|
72
|
+
'function withdraw(uint256 amount) external',
|
|
73
|
+
'function withdrawNative(uint256 amount) external',
|
|
74
|
+
'function activate() external',
|
|
75
|
+
'function deactivate() external',
|
|
76
|
+
// 事件
|
|
77
|
+
'event TaxReceived(address indexed token, uint256 amount)',
|
|
78
|
+
'event RewardsClaimed(address indexed user, uint256 amount)',
|
|
79
|
+
'event VaultActivated()',
|
|
80
|
+
'event VaultDeactivated()',
|
|
81
|
+
];
|
|
82
|
+
/**
|
|
83
|
+
* Vault Factory ABI
|
|
84
|
+
* 用于部署新的金库合约
|
|
85
|
+
*/
|
|
86
|
+
export const VAULT_FACTORY_ABI = [
|
|
87
|
+
'function createVault(address token, address owner, bytes32 vaultType, bytes initData) external returns (address)',
|
|
88
|
+
'function getVault(address token) external view returns (address)',
|
|
89
|
+
'function getVaultsByOwner(address owner) external view returns (address[])',
|
|
90
|
+
'event VaultCreated(address indexed token, address indexed vault, address indexed owner, bytes32 vaultType)',
|
|
91
|
+
];
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// 编码/解码工具
|
|
94
|
+
// ============================================================================
|
|
95
|
+
const abiCoder = AbiCoder.defaultAbiCoder();
|
|
96
|
+
/**
|
|
97
|
+
* 根据 VaultType 获取对应的 extensionID
|
|
98
|
+
*/
|
|
99
|
+
export function getVaultExtensionId(vaultType) {
|
|
100
|
+
switch (vaultType) {
|
|
101
|
+
case 'none':
|
|
102
|
+
return VAULT_EXTENSION_IDS.NONE;
|
|
103
|
+
case 'standard':
|
|
104
|
+
return VAULT_EXTENSION_IDS.STANDARD;
|
|
105
|
+
case 'auto_buyback':
|
|
106
|
+
return VAULT_EXTENSION_IDS.AUTO_BUYBACK;
|
|
107
|
+
case 'dividend':
|
|
108
|
+
return VAULT_EXTENSION_IDS.DIVIDEND;
|
|
109
|
+
case 'liquidity':
|
|
110
|
+
return VAULT_EXTENSION_IDS.LIQUIDITY;
|
|
111
|
+
case 'custom':
|
|
112
|
+
return VAULT_EXTENSION_IDS.CUSTOM;
|
|
113
|
+
default:
|
|
114
|
+
return VAULT_EXTENSION_IDS.NONE;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 编码金库配置为 extensionData
|
|
119
|
+
*
|
|
120
|
+
* @param config - 金库配置
|
|
121
|
+
* @returns ABI 编码的 extensionData(hex string)
|
|
122
|
+
*/
|
|
123
|
+
export function encodeVaultExtensionData(config) {
|
|
124
|
+
if (config.customExtensionData) {
|
|
125
|
+
return config.customExtensionData;
|
|
126
|
+
}
|
|
127
|
+
switch (config.vaultType) {
|
|
128
|
+
case 'none':
|
|
129
|
+
return '0x';
|
|
130
|
+
case 'standard':
|
|
131
|
+
// 标准金库无额外参数
|
|
132
|
+
return '0x';
|
|
133
|
+
case 'auto_buyback': {
|
|
134
|
+
if (!config.buybackConfig)
|
|
135
|
+
return '0x';
|
|
136
|
+
return abiCoder.encode(['uint256', 'uint256', 'bool'], [config.buybackConfig.interval, config.buybackConfig.maxAmount, config.buybackConfig.burnAfterBuy]);
|
|
137
|
+
}
|
|
138
|
+
case 'dividend': {
|
|
139
|
+
if (!config.dividendConfig)
|
|
140
|
+
return '0x';
|
|
141
|
+
return abiCoder.encode(['uint256', 'uint256'], [config.dividendConfig.minimumBalance, config.dividendConfig.distributionInterval]);
|
|
142
|
+
}
|
|
143
|
+
case 'liquidity': {
|
|
144
|
+
if (!config.liquidityConfig)
|
|
145
|
+
return '0x';
|
|
146
|
+
const poolTypeInt = config.liquidityConfig.poolType === 'v3' ? 1 : 0;
|
|
147
|
+
return abiCoder.encode(['uint256', 'uint8'], [config.liquidityConfig.threshold, poolTypeInt]);
|
|
148
|
+
}
|
|
149
|
+
case 'custom': {
|
|
150
|
+
if (!config.vaultAddress) {
|
|
151
|
+
throw new Error('自定义金库必须提供 vaultAddress');
|
|
152
|
+
}
|
|
153
|
+
// 自定义金库:编码金库合约地址
|
|
154
|
+
return abiCoder.encode(['address'], [config.vaultAddress]);
|
|
155
|
+
}
|
|
156
|
+
default:
|
|
157
|
+
return '0x';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 将 TaxVaultConfig 转换为 newTokenV5 需要的 extensionID 和 extensionData
|
|
162
|
+
*
|
|
163
|
+
* @param config - 金库配置
|
|
164
|
+
* @returns { extensionID, extensionData }
|
|
165
|
+
*/
|
|
166
|
+
export function buildVaultExtensionParams(config) {
|
|
167
|
+
if (!config || config.vaultType === 'none') {
|
|
168
|
+
return {
|
|
169
|
+
extensionID: VAULT_EXTENSION_IDS.NONE,
|
|
170
|
+
extensionData: '0x',
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
extensionID: config.customExtensionId || getVaultExtensionId(config.vaultType),
|
|
175
|
+
extensionData: encodeVaultExtensionData(config),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// 链上查询
|
|
180
|
+
// ============================================================================
|
|
181
|
+
/**
|
|
182
|
+
* 查询金库信息
|
|
183
|
+
*
|
|
184
|
+
* @param provider - RPC Provider
|
|
185
|
+
* @param vaultAddress - 金库合约地址
|
|
186
|
+
* @returns 金库信息
|
|
187
|
+
*/
|
|
188
|
+
export async function getVaultInfo(provider, vaultAddress) {
|
|
189
|
+
try {
|
|
190
|
+
const vault = new Contract(vaultAddress, TAX_VAULT_ABI, provider);
|
|
191
|
+
const [tokenAddress, owner, isActive, nativeBalance] = await Promise.all([
|
|
192
|
+
vault.token().catch(() => ZeroAddress),
|
|
193
|
+
vault.owner().catch(() => ZeroAddress),
|
|
194
|
+
vault.isActive().catch(() => false),
|
|
195
|
+
provider.getBalance(vaultAddress),
|
|
196
|
+
]);
|
|
197
|
+
// 如果金库关联了代币,查询代币余额
|
|
198
|
+
let tokenBalance = 0n;
|
|
199
|
+
if (tokenAddress !== ZeroAddress) {
|
|
200
|
+
const erc20 = new Contract(tokenAddress, [
|
|
201
|
+
'function balanceOf(address) view returns (uint256)',
|
|
202
|
+
], provider);
|
|
203
|
+
tokenBalance = await erc20.balanceOf(vaultAddress).catch(() => 0n);
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
address: vaultAddress,
|
|
207
|
+
tokenBalance,
|
|
208
|
+
nativeBalance,
|
|
209
|
+
owner: owner,
|
|
210
|
+
tokenAddress: tokenAddress,
|
|
211
|
+
isActive: isActive,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 查询用户在金库中的奖励
|
|
220
|
+
*
|
|
221
|
+
* @param provider - RPC Provider
|
|
222
|
+
* @param vaultAddress - 金库合约地址
|
|
223
|
+
* @param userAddress - 用户地址
|
|
224
|
+
* @returns 奖励信息
|
|
225
|
+
*/
|
|
226
|
+
export async function getVaultRewards(provider, vaultAddress, userAddress) {
|
|
227
|
+
const vault = new Contract(vaultAddress, TAX_VAULT_ABI, provider);
|
|
228
|
+
const [pendingTokenRewards, claimedTokenRewards] = await Promise.all([
|
|
229
|
+
vault.pendingRewards(userAddress).catch(() => 0n),
|
|
230
|
+
vault.claimedRewards(userAddress).catch(() => 0n),
|
|
231
|
+
]);
|
|
232
|
+
return {
|
|
233
|
+
pendingTokenRewards: pendingTokenRewards,
|
|
234
|
+
pendingNativeRewards: 0n, // 需要根据实际合约接口调整
|
|
235
|
+
claimedTokenRewards: claimedTokenRewards,
|
|
236
|
+
claimedNativeRewards: 0n,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* 从金库领取奖励
|
|
241
|
+
*
|
|
242
|
+
* @param wallet - 签名钱包
|
|
243
|
+
* @param vaultAddress - 金库合约地址
|
|
244
|
+
* @returns 交易收据
|
|
245
|
+
*/
|
|
246
|
+
export async function claimVaultRewards(wallet, vaultAddress) {
|
|
247
|
+
const vault = new Contract(vaultAddress, TAX_VAULT_ABI, wallet);
|
|
248
|
+
const tx = await vault.claimRewards();
|
|
249
|
+
const receipt = await tx.wait();
|
|
250
|
+
return {
|
|
251
|
+
txHash: receipt.hash,
|
|
252
|
+
amount: 0n, // 从事件中解析实际金额
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* 验证金库合约是否有效(是否部署了代码)
|
|
257
|
+
*
|
|
258
|
+
* @param provider - RPC Provider
|
|
259
|
+
* @param vaultAddress - 金库合约地址
|
|
260
|
+
* @returns 是否为有效合约
|
|
261
|
+
*/
|
|
262
|
+
export async function isValidVaultContract(provider, vaultAddress) {
|
|
263
|
+
try {
|
|
264
|
+
const code = await provider.getCode(vaultAddress);
|
|
265
|
+
return code !== '0x' && code !== '0x0';
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 获取代币关联的金库地址(通过 extensionID 推断)
|
|
273
|
+
*
|
|
274
|
+
* @param extensionID - 代币的 extensionID(从 getTokenV5 获取)
|
|
275
|
+
* @returns 金库类型
|
|
276
|
+
*/
|
|
277
|
+
export function getVaultTypeFromExtensionId(extensionID) {
|
|
278
|
+
if (!extensionID || extensionID === VAULT_EXTENSION_IDS.NONE) {
|
|
279
|
+
return 'none';
|
|
280
|
+
}
|
|
281
|
+
for (const [key, value] of Object.entries(VAULT_EXTENSION_IDS)) {
|
|
282
|
+
if (value.toLowerCase() === extensionID.toLowerCase()) {
|
|
283
|
+
return key.toLowerCase();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// 未知的 extensionID,视为自定义金库
|
|
287
|
+
return 'custom';
|
|
288
|
+
}
|