forgex-cli 1.0.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/README.md +479 -0
- package/dist/bin/forgex.d.ts +12 -0
- package/dist/bin/forgex.d.ts.map +1 -0
- package/dist/bin/forgex.js +23 -0
- package/dist/bin/forgex.js.map +1 -0
- package/dist/src/adapters/codex-adapter.d.ts +238 -0
- package/dist/src/adapters/codex-adapter.d.ts.map +1 -0
- package/dist/src/adapters/codex-adapter.js +524 -0
- package/dist/src/adapters/codex-adapter.js.map +1 -0
- package/dist/src/adapters/connection.d.ts +20 -0
- package/dist/src/adapters/connection.d.ts.map +1 -0
- package/dist/src/adapters/connection.js +43 -0
- package/dist/src/adapters/connection.js.map +1 -0
- package/dist/src/adapters/ipfs.d.ts +17 -0
- package/dist/src/adapters/ipfs.d.ts.map +1 -0
- package/dist/src/adapters/ipfs.js +30 -0
- package/dist/src/adapters/ipfs.js.map +1 -0
- package/dist/src/adapters/jito-adapter.d.ts +194 -0
- package/dist/src/adapters/jito-adapter.d.ts.map +1 -0
- package/dist/src/adapters/jito-adapter.js +474 -0
- package/dist/src/adapters/jito-adapter.js.map +1 -0
- package/dist/src/adapters/rpc-adapter.d.ts +148 -0
- package/dist/src/adapters/rpc-adapter.d.ts.map +1 -0
- package/dist/src/adapters/rpc-adapter.js +410 -0
- package/dist/src/adapters/rpc-adapter.js.map +1 -0
- package/dist/src/adapters/sdk-adapter.d.ts +148 -0
- package/dist/src/adapters/sdk-adapter.d.ts.map +1 -0
- package/dist/src/adapters/sdk-adapter.js +554 -0
- package/dist/src/adapters/sdk-adapter.js.map +1 -0
- package/dist/src/commands/config/index.d.ts +8 -0
- package/dist/src/commands/config/index.d.ts.map +1 -0
- package/dist/src/commands/config/index.js +91 -0
- package/dist/src/commands/config/index.js.map +1 -0
- package/dist/src/commands/query/index.d.ts +10 -0
- package/dist/src/commands/query/index.d.ts.map +1 -0
- package/dist/src/commands/query/index.js +376 -0
- package/dist/src/commands/query/index.js.map +1 -0
- package/dist/src/commands/sniper/index.d.ts +16 -0
- package/dist/src/commands/sniper/index.d.ts.map +1 -0
- package/dist/src/commands/sniper/index.js +292 -0
- package/dist/src/commands/sniper/index.js.map +1 -0
- package/dist/src/commands/token/index.d.ts +16 -0
- package/dist/src/commands/token/index.d.ts.map +1 -0
- package/dist/src/commands/token/index.js +295 -0
- package/dist/src/commands/token/index.js.map +1 -0
- package/dist/src/commands/tools/index.d.ts +17 -0
- package/dist/src/commands/tools/index.d.ts.map +1 -0
- package/dist/src/commands/tools/index.js +626 -0
- package/dist/src/commands/tools/index.js.map +1 -0
- package/dist/src/commands/trade/index.d.ts +8 -0
- package/dist/src/commands/trade/index.d.ts.map +1 -0
- package/dist/src/commands/trade/index.js +531 -0
- package/dist/src/commands/trade/index.js.map +1 -0
- package/dist/src/commands/transfer/index.d.ts +16 -0
- package/dist/src/commands/transfer/index.d.ts.map +1 -0
- package/dist/src/commands/transfer/index.js +509 -0
- package/dist/src/commands/transfer/index.js.map +1 -0
- package/dist/src/commands/wallet/index.d.ts +10 -0
- package/dist/src/commands/wallet/index.d.ts.map +1 -0
- package/dist/src/commands/wallet/index.js +828 -0
- package/dist/src/commands/wallet/index.js.map +1 -0
- package/dist/src/config.d.ts +74 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +190 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/const/IDL/index.d.ts +4 -0
- package/dist/src/const/IDL/index.d.ts.map +1 -0
- package/dist/src/const/IDL/index.js +2 -0
- package/dist/src/const/IDL/index.js.map +1 -0
- package/dist/src/const/IDL/meteora-DLMM.d.ts +10249 -0
- package/dist/src/const/IDL/meteora-DLMM.d.ts.map +1 -0
- package/dist/src/const/IDL/meteora-DLMM.js +4177 -0
- package/dist/src/const/IDL/meteora-DLMM.js.map +1 -0
- package/dist/src/const/IDL/pump-fun.d.ts +4811 -0
- package/dist/src/const/IDL/pump-fun.d.ts.map +1 -0
- package/dist/src/const/IDL/pump-fun.js +2954 -0
- package/dist/src/const/IDL/pump-fun.js.map +1 -0
- package/dist/src/const/IDL/pump-swap-IDL.d.ts +3119 -0
- package/dist/src/const/IDL/pump-swap-IDL.d.ts.map +1 -0
- package/dist/src/const/IDL/pump-swap-IDL.js +2095 -0
- package/dist/src/const/IDL/pump-swap-IDL.js.map +1 -0
- package/dist/src/const/IDL/raydium-launchlab-IDL.d.ts +4031 -0
- package/dist/src/const/IDL/raydium-launchlab-IDL.d.ts.map +1 -0
- package/dist/src/const/IDL/raydium-launchlab-IDL.js +2110 -0
- package/dist/src/const/IDL/raydium-launchlab-IDL.js.map +1 -0
- package/dist/src/const/index.d.ts +40 -0
- package/dist/src/const/index.d.ts.map +1 -0
- package/dist/src/const/index.js +57 -0
- package/dist/src/const/index.js.map +1 -0
- package/dist/src/data-source.d.ts +270 -0
- package/dist/src/data-source.d.ts.map +1 -0
- package/dist/src/data-source.js +628 -0
- package/dist/src/data-source.js.map +1 -0
- package/dist/src/data-store/index.d.ts +87 -0
- package/dist/src/data-store/index.d.ts.map +1 -0
- package/dist/src/data-store/index.js +561 -0
- package/dist/src/data-store/index.js.map +1 -0
- package/dist/src/data-store/types.d.ts +91 -0
- package/dist/src/data-store/types.d.ts.map +1 -0
- package/dist/src/data-store/types.js +8 -0
- package/dist/src/data-store/types.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +36 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/output.d.ts +52 -0
- package/dist/src/output.d.ts.map +1 -0
- package/dist/src/output.js +218 -0
- package/dist/src/output.js.map +1 -0
- package/dist/src/shims/store.d.ts +58 -0
- package/dist/src/shims/store.d.ts.map +1 -0
- package/dist/src/shims/store.js +55 -0
- package/dist/src/shims/store.js.map +1 -0
- package/dist/src/sol-sdk/account/index.d.ts +13 -0
- package/dist/src/sol-sdk/account/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/account/index.js +174 -0
- package/dist/src/sol-sdk/account/index.js.map +1 -0
- package/dist/src/sol-sdk/account/lookupTable.d.ts +24 -0
- package/dist/src/sol-sdk/account/lookupTable.d.ts.map +1 -0
- package/dist/src/sol-sdk/account/lookupTable.js +103 -0
- package/dist/src/sol-sdk/account/lookupTable.js.map +1 -0
- package/dist/src/sol-sdk/batch/create.d.ts +23 -0
- package/dist/src/sol-sdk/batch/create.d.ts.map +1 -0
- package/dist/src/sol-sdk/batch/create.js +580 -0
- package/dist/src/sol-sdk/batch/create.js.map +1 -0
- package/dist/src/sol-sdk/batch/external-sniper.d.ts +31 -0
- package/dist/src/sol-sdk/batch/external-sniper.d.ts.map +1 -0
- package/dist/src/sol-sdk/batch/external-sniper.js +163 -0
- package/dist/src/sol-sdk/batch/external-sniper.js.map +1 -0
- package/dist/src/sol-sdk/batch/index.d.ts +144 -0
- package/dist/src/sol-sdk/batch/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/batch/index.js +1573 -0
- package/dist/src/sol-sdk/batch/index.js.map +1 -0
- package/dist/src/sol-sdk/calc.d.ts +277 -0
- package/dist/src/sol-sdk/calc.d.ts.map +1 -0
- package/dist/src/sol-sdk/calc.js +590 -0
- package/dist/src/sol-sdk/calc.js.map +1 -0
- package/dist/src/sol-sdk/index.d.ts +1 -0
- package/dist/src/sol-sdk/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/index.js +1 -0
- package/dist/src/sol-sdk/index.js.map +1 -0
- package/dist/src/sol-sdk/jito/index.d.ts +50 -0
- package/dist/src/sol-sdk/jito/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/jito/index.js +225 -0
- package/dist/src/sol-sdk/jito/index.js.map +1 -0
- package/dist/src/sol-sdk/launchlab/index.d.ts +32 -0
- package/dist/src/sol-sdk/launchlab/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/launchlab/index.js +78 -0
- package/dist/src/sol-sdk/launchlab/index.js.map +1 -0
- package/dist/src/sol-sdk/launchlab/instructions/buy.d.ts +27 -0
- package/dist/src/sol-sdk/launchlab/instructions/buy.d.ts.map +1 -0
- package/dist/src/sol-sdk/launchlab/instructions/buy.js +124 -0
- package/dist/src/sol-sdk/launchlab/instructions/buy.js.map +1 -0
- package/dist/src/sol-sdk/launchlab/instructions/create.d.ts +27 -0
- package/dist/src/sol-sdk/launchlab/instructions/create.d.ts.map +1 -0
- package/dist/src/sol-sdk/launchlab/instructions/create.js +125 -0
- package/dist/src/sol-sdk/launchlab/instructions/create.js.map +1 -0
- package/dist/src/sol-sdk/launchlab/instructions/sell.d.ts +15 -0
- package/dist/src/sol-sdk/launchlab/instructions/sell.d.ts.map +1 -0
- package/dist/src/sol-sdk/launchlab/instructions/sell.js +65 -0
- package/dist/src/sol-sdk/launchlab/instructions/sell.js.map +1 -0
- package/dist/src/sol-sdk/meteora/index.d.ts +32 -0
- package/dist/src/sol-sdk/meteora/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/meteora/index.js +72 -0
- package/dist/src/sol-sdk/meteora/index.js.map +1 -0
- package/dist/src/sol-sdk/meteora/instructions/buy.d.ts +46 -0
- package/dist/src/sol-sdk/meteora/instructions/buy.d.ts.map +1 -0
- package/dist/src/sol-sdk/meteora/instructions/buy.js +153 -0
- package/dist/src/sol-sdk/meteora/instructions/buy.js.map +1 -0
- package/dist/src/sol-sdk/meteora/instructions/sell.d.ts +24 -0
- package/dist/src/sol-sdk/meteora/instructions/sell.d.ts.map +1 -0
- package/dist/src/sol-sdk/meteora/instructions/sell.js +98 -0
- package/dist/src/sol-sdk/meteora/instructions/sell.js.map +1 -0
- package/dist/src/sol-sdk/pump/index.d.ts +22 -0
- package/dist/src/sol-sdk/pump/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/pump/index.js +101 -0
- package/dist/src/sol-sdk/pump/index.js.map +1 -0
- package/dist/src/sol-sdk/pump/instructions/buy.d.ts +29 -0
- package/dist/src/sol-sdk/pump/instructions/buy.d.ts.map +1 -0
- package/dist/src/sol-sdk/pump/instructions/buy.js +131 -0
- package/dist/src/sol-sdk/pump/instructions/buy.js.map +1 -0
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts +36 -0
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts.map +1 -0
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.js +77 -0
- package/dist/src/sol-sdk/pump/instructions/createAndBuy.js.map +1 -0
- package/dist/src/sol-sdk/pump/instructions/sell.d.ts +7 -0
- package/dist/src/sol-sdk/pump/instructions/sell.d.ts.map +1 -0
- package/dist/src/sol-sdk/pump/instructions/sell.js +38 -0
- package/dist/src/sol-sdk/pump/instructions/sell.js.map +1 -0
- package/dist/src/sol-sdk/pumpswap/index.d.ts +9 -0
- package/dist/src/sol-sdk/pumpswap/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/pumpswap/index.js +27 -0
- package/dist/src/sol-sdk/pumpswap/index.js.map +1 -0
- package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts +61 -0
- package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts.map +1 -0
- package/dist/src/sol-sdk/pumpswap/instructions/buy.js +215 -0
- package/dist/src/sol-sdk/pumpswap/instructions/buy.js.map +1 -0
- package/dist/src/sol-sdk/pumpswap/instructions/migrate.d.ts +3 -0
- package/dist/src/sol-sdk/pumpswap/instructions/migrate.d.ts.map +1 -0
- package/dist/src/sol-sdk/pumpswap/instructions/migrate.js +33 -0
- package/dist/src/sol-sdk/pumpswap/instructions/migrate.js.map +1 -0
- package/dist/src/sol-sdk/pumpswap/instructions/sell.d.ts +20 -0
- package/dist/src/sol-sdk/pumpswap/instructions/sell.d.ts.map +1 -0
- package/dist/src/sol-sdk/pumpswap/instructions/sell.js +107 -0
- package/dist/src/sol-sdk/pumpswap/instructions/sell.js.map +1 -0
- package/dist/src/sol-sdk/pumpswap/rpc/index.d.ts +28 -0
- package/dist/src/sol-sdk/pumpswap/rpc/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/pumpswap/rpc/index.js +63 -0
- package/dist/src/sol-sdk/pumpswap/rpc/index.js.map +1 -0
- package/dist/src/sol-sdk/raydium/index.d.ts +16 -0
- package/dist/src/sol-sdk/raydium/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/index.js +47 -0
- package/dist/src/sol-sdk/raydium/index.js.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/buy.d.ts +29 -0
- package/dist/src/sol-sdk/raydium/instructions/buy.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/buy.js +106 -0
- package/dist/src/sol-sdk/raydium/instructions/buy.js.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.d.ts +29 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.js +80 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.js.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmSell.d.ts +17 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmSell.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js +56 -0
- package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/sell.d.ts +8558 -0
- package/dist/src/sol-sdk/raydium/instructions/sell.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/instructions/sell.js +70 -0
- package/dist/src/sol-sdk/raydium/instructions/sell.js.map +1 -0
- package/dist/src/sol-sdk/raydium/rpc/index.d.ts +39 -0
- package/dist/src/sol-sdk/raydium/rpc/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/rpc/index.js +82 -0
- package/dist/src/sol-sdk/raydium/rpc/index.js.map +1 -0
- package/dist/src/sol-sdk/raydium/rpc/raydium.d.ts +5 -0
- package/dist/src/sol-sdk/raydium/rpc/raydium.d.ts.map +1 -0
- package/dist/src/sol-sdk/raydium/rpc/raydium.js +18 -0
- package/dist/src/sol-sdk/raydium/rpc/raydium.js.map +1 -0
- package/dist/src/sol-sdk/rpc/index.d.ts +33 -0
- package/dist/src/sol-sdk/rpc/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/rpc/index.js +128 -0
- package/dist/src/sol-sdk/rpc/index.js.map +1 -0
- package/dist/src/sol-sdk/transfer/index.d.ts +24 -0
- package/dist/src/sol-sdk/transfer/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/transfer/index.js +65 -0
- package/dist/src/sol-sdk/transfer/index.js.map +1 -0
- package/dist/src/sol-sdk/turnover/index.d.ts +84 -0
- package/dist/src/sol-sdk/turnover/index.d.ts.map +1 -0
- package/dist/src/sol-sdk/turnover/index.js +569 -0
- package/dist/src/sol-sdk/turnover/index.js.map +1 -0
- package/dist/src/tx-tracker/detail-adapter.d.ts +100 -0
- package/dist/src/tx-tracker/detail-adapter.d.ts.map +1 -0
- package/dist/src/tx-tracker/detail-adapter.js +215 -0
- package/dist/src/tx-tracker/detail-adapter.js.map +1 -0
- package/dist/src/tx-tracker/index.d.ts +142 -0
- package/dist/src/tx-tracker/index.d.ts.map +1 -0
- package/dist/src/tx-tracker/index.js +447 -0
- package/dist/src/tx-tracker/index.js.map +1 -0
- package/dist/src/types/index.d.ts +76 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +69 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/websocket.d.ts +15 -0
- package/dist/src/types/websocket.d.ts.map +1 -0
- package/dist/src/types/websocket.js +18 -0
- package/dist/src/types/websocket.js.map +1 -0
- package/dist/src/utils/index.d.ts +13 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +174 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/wallet-store.d.ts +124 -0
- package/dist/src/wallet-store.d.ts.map +1 -0
- package/dist/src/wallet-store.js +524 -0
- package/dist/src/wallet-store.js.map +1 -0
- package/package.json +86 -0
- package/scripts/postinstall.js +88 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ForgeX CLI TxDetailAdapter -- 交易详情字段适配器
|
|
3
|
+
*
|
|
4
|
+
* 将 RPC 返回的原始交易数据 (ParsedTransactionDetail) 映射为
|
|
5
|
+
* CLI DataStore 的 TransactionRecord 结构。
|
|
6
|
+
*
|
|
7
|
+
* 核心职责:
|
|
8
|
+
* - 从 preBalances / postBalances 计算 SOL 变化量
|
|
9
|
+
* - 从 preTokenBalances / postTokenBalances 计算 Token 变化量
|
|
10
|
+
* - 计算成交价格 (pricePerToken = |solChange| / |tokenChange|)
|
|
11
|
+
* - 提取手续费
|
|
12
|
+
* - 根据交易记录更新持仓数据 (avgBuyPrice, realizedPnl 等)
|
|
13
|
+
*
|
|
14
|
+
* 设计参考: ARCH-DESIGN-v2.md Section 3.4
|
|
15
|
+
*/
|
|
16
|
+
import type { ParsedTransactionDetail } from '../adapters/rpc-adapter.js';
|
|
17
|
+
import type { TransactionRecord, WalletHolding } from '../data-store/types.js';
|
|
18
|
+
/** 追踪上下文 (由 TxTracker 传入) */
|
|
19
|
+
export interface TrackingContext {
|
|
20
|
+
/** 代币合约地址 */
|
|
21
|
+
ca: string;
|
|
22
|
+
/** 钱包组 ID */
|
|
23
|
+
groupId: number;
|
|
24
|
+
/** 交易类型 */
|
|
25
|
+
txType: 'buy' | 'sell' | 'transfer_in' | 'transfer_out' | 'turnover';
|
|
26
|
+
/** 参与交易的钱包地址列表 */
|
|
27
|
+
wallets: string[];
|
|
28
|
+
/** 预期 SOL 金额 (用于验证,可选) */
|
|
29
|
+
expectedAmountSol?: number;
|
|
30
|
+
/** Jito Bundle ID (如有) */
|
|
31
|
+
jitoBundle?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare class TxDetailAdapter {
|
|
34
|
+
/**
|
|
35
|
+
* 核心适配方法:
|
|
36
|
+
* 从 RPC 原始交易数据中提取并映射为 TransactionRecord。
|
|
37
|
+
*
|
|
38
|
+
* 解析流程:
|
|
39
|
+
* 1. 在 accountKeys 中找到目标钱包的索引
|
|
40
|
+
* 2. 通过索引比较 preBalances vs postBalances 计算 SOL 变化
|
|
41
|
+
* 3. 从 preTokenBalances / postTokenBalances 中筛选目标代币和钱包,计算 Token 变化
|
|
42
|
+
* 4. 计算成交价格: |SOL变化 - fee| / |Token变化|
|
|
43
|
+
* 5. 组装 TransactionRecord
|
|
44
|
+
*
|
|
45
|
+
* @param txHash 交易签名
|
|
46
|
+
* @param detail RPC 返回的解析后交易详情
|
|
47
|
+
* @param context 追踪上下文
|
|
48
|
+
* @returns TransactionRecord
|
|
49
|
+
*/
|
|
50
|
+
adaptToTransactionRecord(txHash: string, detail: ParsedTransactionDetail, context: TrackingContext): TransactionRecord;
|
|
51
|
+
/**
|
|
52
|
+
* 根据交易记录更新持仓数据。
|
|
53
|
+
*
|
|
54
|
+
* 更新逻辑:
|
|
55
|
+
* - buy: 增加 tokenBalance, totalBought, totalCostSol; 重算 avgBuyPrice
|
|
56
|
+
* - sell: 减少 tokenBalance, 增加 totalSold, totalRevenueSol; 计算 realizedPnl
|
|
57
|
+
* - transfer_in: 增加 tokenBalance (不影响成本)
|
|
58
|
+
* - transfer_out: 减少 tokenBalance (不影响成本)
|
|
59
|
+
* - turnover: 不更新持仓 (换手不改变净持仓)
|
|
60
|
+
*
|
|
61
|
+
* @param currentHolding 当前持仓数据
|
|
62
|
+
* @param tx 交易记录
|
|
63
|
+
* @returns 更新后的持仓数据 (新对象,不修改原对象)
|
|
64
|
+
*/
|
|
65
|
+
updateHoldingFromTx(currentHolding: WalletHolding, tx: TransactionRecord): WalletHolding;
|
|
66
|
+
/**
|
|
67
|
+
* 为指定钱包创建空的初始持仓
|
|
68
|
+
*/
|
|
69
|
+
createEmptyHolding(walletAddress: string): WalletHolding;
|
|
70
|
+
/**
|
|
71
|
+
* 在 accountKeys 中找到目标钱包的索引。
|
|
72
|
+
* 优先匹配第一个钱包地址(主钱包)。
|
|
73
|
+
*/
|
|
74
|
+
private findWalletIndex;
|
|
75
|
+
/**
|
|
76
|
+
* 解析实际使用的钱包地址。
|
|
77
|
+
* 如果在 accountKeys 中找到了匹配的钱包,返回该地址;
|
|
78
|
+
* 否则返回 context.wallets[0] 作为兜底。
|
|
79
|
+
*/
|
|
80
|
+
private resolveWalletAddress;
|
|
81
|
+
/**
|
|
82
|
+
* 计算 Token 余额变化量。
|
|
83
|
+
*
|
|
84
|
+
* 从 preTokenBalances 和 postTokenBalances 中筛选:
|
|
85
|
+
* - mint === 目标代币合约地址
|
|
86
|
+
* - owner 属于参与交易的钱包之一
|
|
87
|
+
*
|
|
88
|
+
* 然后计算 post - pre 得到变化量。
|
|
89
|
+
*
|
|
90
|
+
* 注意: preTokenBalances/postTokenBalances 中的 owner 字段可能不存在,
|
|
91
|
+
* 此时通过 accountIndex 映射 accountKeys 来确定 owner。
|
|
92
|
+
*/
|
|
93
|
+
private calculateTokenChange;
|
|
94
|
+
/**
|
|
95
|
+
* 从 tokenBalances 数组中,汇总指定代币和钱包的余额。
|
|
96
|
+
* 支持通过 owner 字段直接匹配,或通过 accountIndex -> accountKeys 间接匹配。
|
|
97
|
+
*/
|
|
98
|
+
private sumTokenBalance;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=detail-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detail-adapter.d.ts","sourceRoot":"","sources":["../../../src/tx-tracker/detail-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAM/E,6BAA6B;AAC7B,MAAM,WAAW,eAAe;IAC9B,aAAa;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,UAAU,CAAC;IACrE,kBAAkB;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0BAA0B;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA6BD,qBAAa,eAAe;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,wBAAwB,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,uBAAuB,EAC/B,OAAO,EAAE,eAAe,GACvB,iBAAiB;IA8CpB;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,cAAc,EAAE,aAAa,EAAE,EAAE,EAAE,iBAAiB,GAAG,aAAa;IA0DxF;;OAEG;IACH,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa;IAkBxD;;;OAGG;IACH,OAAO,CAAC,eAAe;IASvB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAO5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IAY5B;;;OAGG;IACH,OAAO,CAAC,eAAe;CA6BxB"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ForgeX CLI TxDetailAdapter -- 交易详情字段适配器
|
|
3
|
+
*
|
|
4
|
+
* 将 RPC 返回的原始交易数据 (ParsedTransactionDetail) 映射为
|
|
5
|
+
* CLI DataStore 的 TransactionRecord 结构。
|
|
6
|
+
*
|
|
7
|
+
* 核心职责:
|
|
8
|
+
* - 从 preBalances / postBalances 计算 SOL 变化量
|
|
9
|
+
* - 从 preTokenBalances / postTokenBalances 计算 Token 变化量
|
|
10
|
+
* - 计算成交价格 (pricePerToken = |solChange| / |tokenChange|)
|
|
11
|
+
* - 提取手续费
|
|
12
|
+
* - 根据交易记录更新持仓数据 (avgBuyPrice, realizedPnl 等)
|
|
13
|
+
*
|
|
14
|
+
* 设计参考: ARCH-DESIGN-v2.md Section 3.4
|
|
15
|
+
*/
|
|
16
|
+
// ============================================================
|
|
17
|
+
// TxDetailAdapter 实现
|
|
18
|
+
// ============================================================
|
|
19
|
+
export class TxDetailAdapter {
|
|
20
|
+
/**
|
|
21
|
+
* 核心适配方法:
|
|
22
|
+
* 从 RPC 原始交易数据中提取并映射为 TransactionRecord。
|
|
23
|
+
*
|
|
24
|
+
* 解析流程:
|
|
25
|
+
* 1. 在 accountKeys 中找到目标钱包的索引
|
|
26
|
+
* 2. 通过索引比较 preBalances vs postBalances 计算 SOL 变化
|
|
27
|
+
* 3. 从 preTokenBalances / postTokenBalances 中筛选目标代币和钱包,计算 Token 变化
|
|
28
|
+
* 4. 计算成交价格: |SOL变化 - fee| / |Token变化|
|
|
29
|
+
* 5. 组装 TransactionRecord
|
|
30
|
+
*
|
|
31
|
+
* @param txHash 交易签名
|
|
32
|
+
* @param detail RPC 返回的解析后交易详情
|
|
33
|
+
* @param context 追踪上下文
|
|
34
|
+
* @returns TransactionRecord
|
|
35
|
+
*/
|
|
36
|
+
adaptToTransactionRecord(txHash, detail, context) {
|
|
37
|
+
const { accountKeys, preBalances, postBalances, preTokenBalances, postTokenBalances, fee, err, slot, blockTime } = detail;
|
|
38
|
+
// 1. 找到目标钱包在 accountKeys 中的索引
|
|
39
|
+
const walletIndex = this.findWalletIndex(accountKeys, context.wallets);
|
|
40
|
+
// 2. 计算 SOL 变化 (lamports -> SOL)
|
|
41
|
+
const solChangeLamports = walletIndex >= 0 ? (postBalances[walletIndex] ?? 0) - (preBalances[walletIndex] ?? 0) : 0;
|
|
42
|
+
const solChange = solChangeLamports / 1e9;
|
|
43
|
+
// 3. 计算 Token 变化
|
|
44
|
+
const tokenChange = this.calculateTokenChange(preTokenBalances, postTokenBalances, context.ca, context.wallets, accountKeys);
|
|
45
|
+
// 4. 计算成交价格
|
|
46
|
+
// 对于 buy: 花费 SOL 获取 Token,solChange 为负,tokenChange 为正
|
|
47
|
+
// 对于 sell: 花费 Token 获取 SOL,solChange 为正,tokenChange 为负
|
|
48
|
+
// 价格 = |净 SOL 变化(扣除 fee)| / |Token 变化|
|
|
49
|
+
const feeInSol = (fee || 0) / 1e9;
|
|
50
|
+
const netSolChange = Math.abs(solChange) - feeInSol;
|
|
51
|
+
const pricePerToken = tokenChange !== 0 ? Math.max(0, netSolChange) / Math.abs(tokenChange) : 0;
|
|
52
|
+
// 5. 组装记录
|
|
53
|
+
return {
|
|
54
|
+
txHash,
|
|
55
|
+
txType: context.txType,
|
|
56
|
+
walletAddress: this.resolveWalletAddress(accountKeys, context.wallets, walletIndex),
|
|
57
|
+
tokenCA: context.ca,
|
|
58
|
+
amountSol: solChange,
|
|
59
|
+
amountToken: tokenChange,
|
|
60
|
+
pricePerToken,
|
|
61
|
+
fee: feeInSol,
|
|
62
|
+
slot,
|
|
63
|
+
blockTime: blockTime || Math.floor(Date.now() / 1000),
|
|
64
|
+
status: err ? 'failed' : 'confirmed',
|
|
65
|
+
jitoBundle: context.jitoBundle,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 根据交易记录更新持仓数据。
|
|
70
|
+
*
|
|
71
|
+
* 更新逻辑:
|
|
72
|
+
* - buy: 增加 tokenBalance, totalBought, totalCostSol; 重算 avgBuyPrice
|
|
73
|
+
* - sell: 减少 tokenBalance, 增加 totalSold, totalRevenueSol; 计算 realizedPnl
|
|
74
|
+
* - transfer_in: 增加 tokenBalance (不影响成本)
|
|
75
|
+
* - transfer_out: 减少 tokenBalance (不影响成本)
|
|
76
|
+
* - turnover: 不更新持仓 (换手不改变净持仓)
|
|
77
|
+
*
|
|
78
|
+
* @param currentHolding 当前持仓数据
|
|
79
|
+
* @param tx 交易记录
|
|
80
|
+
* @returns 更新后的持仓数据 (新对象,不修改原对象)
|
|
81
|
+
*/
|
|
82
|
+
updateHoldingFromTx(currentHolding, tx) {
|
|
83
|
+
const updated = { ...currentHolding };
|
|
84
|
+
switch (tx.txType) {
|
|
85
|
+
case 'buy': {
|
|
86
|
+
const boughtTokens = Math.abs(tx.amountToken);
|
|
87
|
+
const costSol = Math.abs(tx.amountSol);
|
|
88
|
+
updated.totalBought += boughtTokens;
|
|
89
|
+
updated.totalCostSol += costSol;
|
|
90
|
+
updated.tokenBalance += boughtTokens;
|
|
91
|
+
// 重算平均买入价 (加权平均)
|
|
92
|
+
if (updated.totalBought > 0) {
|
|
93
|
+
updated.avgBuyPrice = updated.totalCostSol / updated.totalBought;
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 'sell': {
|
|
98
|
+
const soldTokens = Math.abs(tx.amountToken);
|
|
99
|
+
const revenueSol = Math.abs(tx.amountSol);
|
|
100
|
+
updated.totalSold += soldTokens;
|
|
101
|
+
updated.totalRevenueSol += revenueSol;
|
|
102
|
+
updated.tokenBalance = Math.max(0, updated.tokenBalance - soldTokens);
|
|
103
|
+
// 计算本次卖出的已实现盈亏
|
|
104
|
+
// realizedPnl += 卖出收入 - 卖出数量 * 平均买入成本
|
|
105
|
+
const soldCost = soldTokens * updated.avgBuyPrice;
|
|
106
|
+
updated.realizedPnl += revenueSol - soldCost;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'transfer_in': {
|
|
110
|
+
// 转入: 增加余额,不影响成本数据
|
|
111
|
+
const transferredIn = Math.abs(tx.amountToken);
|
|
112
|
+
updated.tokenBalance += transferredIn;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case 'transfer_out': {
|
|
116
|
+
// 转出: 减少余额,不影响成本数据
|
|
117
|
+
const transferredOut = Math.abs(tx.amountToken);
|
|
118
|
+
updated.tokenBalance = Math.max(0, updated.tokenBalance - transferredOut);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case 'turnover': {
|
|
122
|
+
// 换手: 不改变净持仓
|
|
123
|
+
// 换手交易本质上是一买一卖的对冲操作,net 持仓不变
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return updated;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 为指定钱包创建空的初始持仓
|
|
131
|
+
*/
|
|
132
|
+
createEmptyHolding(walletAddress) {
|
|
133
|
+
return {
|
|
134
|
+
walletAddress,
|
|
135
|
+
tokenBalance: 0,
|
|
136
|
+
avgBuyPrice: 0,
|
|
137
|
+
totalBought: 0,
|
|
138
|
+
totalSold: 0,
|
|
139
|
+
totalCostSol: 0,
|
|
140
|
+
totalRevenueSol: 0,
|
|
141
|
+
realizedPnl: 0,
|
|
142
|
+
unrealizedPnl: 0,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// ============================================================
|
|
146
|
+
// 私有方法
|
|
147
|
+
// ============================================================
|
|
148
|
+
/**
|
|
149
|
+
* 在 accountKeys 中找到目标钱包的索引。
|
|
150
|
+
* 优先匹配第一个钱包地址(主钱包)。
|
|
151
|
+
*/
|
|
152
|
+
findWalletIndex(accountKeys, wallets) {
|
|
153
|
+
// 先尝试精确匹配第一个钱包(主钱包)
|
|
154
|
+
for (const wallet of wallets) {
|
|
155
|
+
const idx = accountKeys.indexOf(wallet);
|
|
156
|
+
if (idx >= 0)
|
|
157
|
+
return idx;
|
|
158
|
+
}
|
|
159
|
+
return -1;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 解析实际使用的钱包地址。
|
|
163
|
+
* 如果在 accountKeys 中找到了匹配的钱包,返回该地址;
|
|
164
|
+
* 否则返回 context.wallets[0] 作为兜底。
|
|
165
|
+
*/
|
|
166
|
+
resolveWalletAddress(accountKeys, wallets, walletIndex) {
|
|
167
|
+
if (walletIndex >= 0 && walletIndex < accountKeys.length) {
|
|
168
|
+
return accountKeys[walletIndex];
|
|
169
|
+
}
|
|
170
|
+
return wallets[0] || '';
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 计算 Token 余额变化量。
|
|
174
|
+
*
|
|
175
|
+
* 从 preTokenBalances 和 postTokenBalances 中筛选:
|
|
176
|
+
* - mint === 目标代币合约地址
|
|
177
|
+
* - owner 属于参与交易的钱包之一
|
|
178
|
+
*
|
|
179
|
+
* 然后计算 post - pre 得到变化量。
|
|
180
|
+
*
|
|
181
|
+
* 注意: preTokenBalances/postTokenBalances 中的 owner 字段可能不存在,
|
|
182
|
+
* 此时通过 accountIndex 映射 accountKeys 来确定 owner。
|
|
183
|
+
*/
|
|
184
|
+
calculateTokenChange(preTokenBalances, postTokenBalances, tokenMint, walletAddresses, accountKeys) {
|
|
185
|
+
const preBalance = this.sumTokenBalance(preTokenBalances, tokenMint, walletAddresses, accountKeys);
|
|
186
|
+
const postBalance = this.sumTokenBalance(postTokenBalances, tokenMint, walletAddresses, accountKeys);
|
|
187
|
+
return postBalance - preBalance;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 从 tokenBalances 数组中,汇总指定代币和钱包的余额。
|
|
191
|
+
* 支持通过 owner 字段直接匹配,或通过 accountIndex -> accountKeys 间接匹配。
|
|
192
|
+
*/
|
|
193
|
+
sumTokenBalance(tokenBalances, tokenMint, walletAddresses, accountKeys) {
|
|
194
|
+
if (!Array.isArray(tokenBalances))
|
|
195
|
+
return 0;
|
|
196
|
+
let total = 0;
|
|
197
|
+
for (const entry of tokenBalances) {
|
|
198
|
+
// 只关心目标代币
|
|
199
|
+
if (entry.mint !== tokenMint)
|
|
200
|
+
continue;
|
|
201
|
+
// 确定 owner: 优先使用 entry.owner,否则通过 accountIndex 查找
|
|
202
|
+
const owner = entry.owner || (entry.accountIndex >= 0 ? accountKeys[entry.accountIndex] : undefined);
|
|
203
|
+
if (!owner)
|
|
204
|
+
continue;
|
|
205
|
+
// 检查 owner 是否属于参与交易的钱包
|
|
206
|
+
if (!walletAddresses.includes(owner))
|
|
207
|
+
continue;
|
|
208
|
+
// 取 uiAmount
|
|
209
|
+
const uiAmount = entry.uiTokenAmount?.uiAmount ?? 0;
|
|
210
|
+
total += uiAmount;
|
|
211
|
+
}
|
|
212
|
+
return total;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=detail-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detail-adapter.js","sourceRoot":"","sources":["../../../src/tx-tracker/detail-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ForgeX CLI TxTracker -- 交易追踪系统
|
|
3
|
+
*
|
|
4
|
+
* 在每次交易发起后:
|
|
5
|
+
* 1. 通过 RPC 或 Jito API 轮询检查交易状态
|
|
6
|
+
* 2. 确认后获取完整交易详情
|
|
7
|
+
* 3. 通过 TxDetailAdapter 将链上原始数据映射为 CLI 数据结构
|
|
8
|
+
* 4. 自动写入 DataStore (交易记录、持仓、余额)
|
|
9
|
+
*
|
|
10
|
+
* 支持:
|
|
11
|
+
* - 普通交易追踪 (trackTransaction)
|
|
12
|
+
* - Jito Bundle 追踪 (trackBundle)
|
|
13
|
+
* - 批量交易追踪 (trackBatch)
|
|
14
|
+
* - 进度回调 (onProgress)
|
|
15
|
+
* - 可配置的轮询间隔和超时
|
|
16
|
+
*
|
|
17
|
+
* 设计参考: ARCH-DESIGN-v2.md Section 3.2 ~ 3.6
|
|
18
|
+
*/
|
|
19
|
+
import { RpcAdapter } from '../adapters/rpc-adapter.js';
|
|
20
|
+
import { JitoAdapter } from '../adapters/jito-adapter.js';
|
|
21
|
+
import { DataStore } from '../data-store/index.js';
|
|
22
|
+
import type { TrackingContext } from './detail-adapter.js';
|
|
23
|
+
import type { TransactionRecord } from '../data-store/types.js';
|
|
24
|
+
export { TxDetailAdapter } from './detail-adapter.js';
|
|
25
|
+
export type { TrackingContext } from './detail-adapter.js';
|
|
26
|
+
/** 追踪选项 */
|
|
27
|
+
export interface TrackingOptions {
|
|
28
|
+
/** 轮询间隔 (ms), 默认 2000 */
|
|
29
|
+
pollIntervalMs?: number;
|
|
30
|
+
/** 超时时间 (ms), 默认 60000 */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
/** 最大重试次数 (RPC 请求失败时), 默认 3 */
|
|
33
|
+
maxRetries?: number;
|
|
34
|
+
/** 进度回调 */
|
|
35
|
+
onProgress?: (status: string, txHash: string) => void;
|
|
36
|
+
}
|
|
37
|
+
/** 单笔交易追踪结果 */
|
|
38
|
+
export interface TrackingResult {
|
|
39
|
+
/** 交易签名 */
|
|
40
|
+
txHash: string;
|
|
41
|
+
/** 最终状态 */
|
|
42
|
+
status: 'confirmed' | 'failed' | 'timeout';
|
|
43
|
+
/** 成功时的交易记录 */
|
|
44
|
+
record?: TransactionRecord;
|
|
45
|
+
/** 失败原因 */
|
|
46
|
+
error?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare class TxTracker {
|
|
49
|
+
private rpc;
|
|
50
|
+
private jito;
|
|
51
|
+
private store;
|
|
52
|
+
private adapter;
|
|
53
|
+
constructor(rpc?: RpcAdapter, jito?: JitoAdapter, store?: DataStore);
|
|
54
|
+
/**
|
|
55
|
+
* 追踪单笔普通交易。
|
|
56
|
+
*
|
|
57
|
+
* 流程:
|
|
58
|
+
* 1. 轮询 RPC 直到交易确认 / 失败 / 超时
|
|
59
|
+
* 2. 确认后获取交易详情
|
|
60
|
+
* 3. 通过 TxDetailAdapter 适配为 TransactionRecord
|
|
61
|
+
* 4. 写入 DataStore (交易记录 + 持仓 + 余额)
|
|
62
|
+
*
|
|
63
|
+
* @param txHash 交易签名
|
|
64
|
+
* @param context 追踪上下文
|
|
65
|
+
* @param options 追踪选项 (可选)
|
|
66
|
+
* @returns 追踪结果
|
|
67
|
+
*/
|
|
68
|
+
trackTransaction(txHash: string, context: TrackingContext, options?: TrackingOptions): Promise<TrackingResult>;
|
|
69
|
+
/**
|
|
70
|
+
* 追踪 Jito Bundle。
|
|
71
|
+
*
|
|
72
|
+
* 流程:
|
|
73
|
+
* 1. 通过 JitoAdapter 等待 Bundle 确认
|
|
74
|
+
* 2. Bundle 确认后,逐个获取内部交易详情
|
|
75
|
+
* 3. 适配并写入 DataStore
|
|
76
|
+
*
|
|
77
|
+
* @param bundleId Jito Bundle ID
|
|
78
|
+
* @param txHashes Bundle 中包含的交易签名列表
|
|
79
|
+
* @param context 追踪上下文
|
|
80
|
+
* @param options 追踪选项 (可选)
|
|
81
|
+
* @returns 每笔交易的追踪结果
|
|
82
|
+
*/
|
|
83
|
+
trackBundle(bundleId: string, txHashes: string[], context: TrackingContext, options?: TrackingOptions): Promise<TrackingResult[]>;
|
|
84
|
+
/**
|
|
85
|
+
* 批量追踪多笔独立交易。
|
|
86
|
+
* 并发追踪所有交易,每笔交易独立处理。
|
|
87
|
+
*
|
|
88
|
+
* @param entries 交易列表 (txHash + context)
|
|
89
|
+
* @param options 追踪选项 (可选)
|
|
90
|
+
* @returns 每笔交易的追踪结果
|
|
91
|
+
*/
|
|
92
|
+
trackBatch(entries: Array<{
|
|
93
|
+
txHash: string;
|
|
94
|
+
context: TrackingContext;
|
|
95
|
+
}>, options?: TrackingOptions): Promise<TrackingResult[]>;
|
|
96
|
+
/**
|
|
97
|
+
* 轮询 RPC 直到交易确认、失败或超时。
|
|
98
|
+
*
|
|
99
|
+
* 策略:
|
|
100
|
+
* - 每隔 pollIntervalMs 查询一次交易状态
|
|
101
|
+
* - confirmed / finalized -> 返回 'confirmed'
|
|
102
|
+
* - failed -> 返回 'failed'
|
|
103
|
+
* - not_found -> 继续等待
|
|
104
|
+
* - RPC 请求错误 -> 计入重试次数,超限后抛出
|
|
105
|
+
* - 超时 -> 返回 'timeout'
|
|
106
|
+
*/
|
|
107
|
+
private pollUntilConfirmed;
|
|
108
|
+
/**
|
|
109
|
+
* 带重试的交易详情获取。
|
|
110
|
+
* 交易刚确认时,详情可能还没有被索引,需要多次尝试。
|
|
111
|
+
*/
|
|
112
|
+
private fetchDetailWithRetry;
|
|
113
|
+
/**
|
|
114
|
+
* 处理已确认的单笔交易: 获取详情 -> 适配 -> 持久化
|
|
115
|
+
*/
|
|
116
|
+
private processConfirmedTransaction;
|
|
117
|
+
/**
|
|
118
|
+
* 将交易记录写入 DataStore
|
|
119
|
+
*/
|
|
120
|
+
private persistTransaction;
|
|
121
|
+
/**
|
|
122
|
+
* 根据交易记录更新持仓数据
|
|
123
|
+
*/
|
|
124
|
+
private updateHoldingFromRecord;
|
|
125
|
+
/**
|
|
126
|
+
* 根据交易记录更新余额快照
|
|
127
|
+
*/
|
|
128
|
+
private updateBalanceFromRecord;
|
|
129
|
+
/** 创建 pending (超时) 状态的交易记录 */
|
|
130
|
+
private createPendingRecord;
|
|
131
|
+
/** 创建 failed 状态的交易记录 */
|
|
132
|
+
private createFailedRecord;
|
|
133
|
+
/** 创建已确认但无详情的交易记录 */
|
|
134
|
+
private createConfirmedPartialRecord;
|
|
135
|
+
/** 合并用户选项和默认选项 */
|
|
136
|
+
private resolveOptions;
|
|
137
|
+
}
|
|
138
|
+
/** 获取 TxTracker 全局单例 */
|
|
139
|
+
export declare function getTxTracker(): TxTracker;
|
|
140
|
+
/** 重置单例 (用于测试或配置变更) */
|
|
141
|
+
export declare function resetTxTracker(): void;
|
|
142
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tx-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAiB,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,WAAW,EAAoC,MAAM,6BAA6B,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAgB,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,wBAAwB,CAAC;AAG/E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAM3D,WAAW;AACX,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW;IACX,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED,eAAe;AACf,MAAM,WAAW,cAAc;IAC7B,WAAW;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,eAAe;IACf,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwBD,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,OAAO,CAAkB;gBAErB,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,SAAS;IAWnE;;;;;;;;;;;;;OAaG;IACG,gBAAgB,CACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC;IAwE1B;;;;;;;;;;;;;OAaG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,EAAE,CAAC;IAiE5B;;;;;;;OAOG;IACG,UAAU,CACd,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC,EAC5D,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,EAAE,CAAC;IAqB5B;;;;;;;;;;OAUG;YACW,kBAAkB;IAuChC;;;OAGG;YACW,oBAAoB;IAwBlC;;OAEG;YACW,2BAA2B;IAwCzC;;OAEG;YACW,kBAAkB;IAQhC;;OAEG;YACW,uBAAuB;IAqBrC;;OAEG;YACW,uBAAuB;IA0BrC,8BAA8B;IAC9B,OAAO,CAAC,mBAAmB;IAiB3B,wBAAwB;IACxB,OAAO,CAAC,kBAAkB;IAiB1B,qBAAqB;IACrB,OAAO,CAAC,4BAA4B;IAqBpC,kBAAkB;IAClB,OAAO,CAAC,cAAc;CAQvB;AAQD,wBAAwB;AACxB,wBAAgB,YAAY,IAAI,SAAS,CAKxC;AAED,uBAAuB;AACvB,wBAAgB,cAAc,IAAI,IAAI,CAErC"}
|