池指标
useForexPoolData hook 提供各外汇池的详细指标,包括追踪 TVL、APY 和利用率随时间变化的每日快照。
核心类型
ForexPoolDailySnapshot
import type { ForexPoolDailySnapshot } from '@one_deploy/sdk';
interface ForexPoolDailySnapshot {
/** The date of this snapshot (ISO-8601 date string, e.g. "2025-04-15"). */
date: string;
/** Pool identifier. */
poolId: string;
/** Pool type at time of snapshot. */
poolType: 'clearing' | 'hedging' | 'insurance';
/** Total value locked at end of day (in USDC). */
tvl: number;
/** Annualized percentage yield for this day. */
apy: number;
/** Pool utilization as a decimal (0.0 to 1.0). */
utilization: number;
/** Total volume processed through the pool on this day. */
volume: number;
/** Number of transactions processed on this day. */
transactionCount: number;
/** Net inflow (deposits - withdrawals) on this day. */
netInflow: number;
/** Fees collected on this day (in USDC). */
feesCollected: number;
}
useForexPoolData Hook
Hook 签名
import { useForexPoolData } from '@one_deploy/sdk';
function useForexPoolData(poolId: string): UseForexPoolDataResult;
UseForexPoolDataResult
interface UseForexPoolDataResult {
/** Current pool state. */
pool: ForexPool | null;
/** Daily snapshots for the pool, ordered by date descending. */
snapshots: ForexPoolDailySnapshot[];
/** Whether data is being fetched. */
isLoading: boolean;
/** Error object if the fetch failed. */
error: Error | null;
/** Re-fetch pool data and snapshots. */
refetch: () => Promise<void>;
/** Fetch snapshots for a specific date range. */
fetchSnapshots: (params: {
startDate: string;
endDate: string;
}) => Promise<ForexPoolDailySnapshot[]>;
}
获取池指标
基础用法
import React from 'react';
import { View, Text, ActivityIndicator, StyleSheet } from 'react-native';
import { useForexPoolData } from '@one_deploy/sdk';
function PoolMetricsView({ poolId }: { poolId: string }) {
const { pool, snapshots, isLoading, error } = useForexPoolData(poolId);
if (isLoading) return <ActivityIndicator size="large" />;
if (error) return <Text style={styles.error}>Error: {error.message}</Text>;
if (!pool) return <Text>Pool not found</Text>;
const latestSnapshot = snapshots[0];
return (
<View style={styles.container}>
<Text style={styles.header}>
{pool.type.charAt(0).toUpperCase() + pool.type.slice(1)} Pool
</Text>
<View style={styles.metricsRow}>
<MetricCard
label="TVL"
value={`$${pool.totalValueLocked.toLocaleString()}`}
/>
<MetricCard
label="APY"
value={`${(pool.apy * 100).toFixed(2)}%`}
/>
<MetricCard
label="Utilization"
value={`${(pool.utilization * 100).toFixed(1)}%`}
/>
</View>
{latestSnapshot && (
<View style={styles.snapshot}>
<Text style={styles.snapshotHeader}>
Latest Snapshot ({latestSnapshot.date})
</Text>
<Text style={styles.snapshotText}>
Volume: ${latestSnapshot.volume.toLocaleString()}
</Text>
<Text style={styles.snapshotText}>
Transactions: {latestSnapshot.transactionCount}
</Text>
<Text style={styles.snapshotText}>
Net Inflow: ${latestSnapshot.netInflow.toLocaleString()}
</Text>
<Text style={styles.snapshotText}>
Fees: ${latestSnapshot.feesCollected.toFixed(2)}
</Text>
</View>
)}
</View>
);
}
function MetricCard({ label, value }: { label: string; value: string }) {
return (
<View style={styles.metricCard}>
<Text style={styles.metricLabel}>{label}</Text>
<Text style={styles.metricValue}>{value}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { padding: 16 },
header: { fontSize: 20, fontWeight: '700', color: '#fff', marginBottom: 16 },
error: { color: '#cc4444', padding: 16 },
metricsRow: { flexDirection: 'row', gap: 12, marginBottom: 20 },
metricCard: {
flex: 1,
backgroundColor: '#1a1a2e',
padding: 14,
borderRadius: 10,
alignItems: 'center',
},
metricLabel: { fontSize: 12, color: '#8888aa', marginBottom: 4 },
metricValue: { fontSize: 18, fontWeight: '700', color: '#ffffff' },
snapshot: {
backgroundColor: '#1a1a2e',
padding: 16,
borderRadius: 12,
},
snapshotHeader: { fontSize: 14, fontWeight: '600', color: '#ccc', marginBottom: 10 },
snapshotText: { fontSize: 13, color: '#aaa', marginBottom: 4 },
});
获取日期范围快照
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import { useForexPoolData } from '@one_deploy/sdk';
import type { ForexPoolDailySnapshot } from '@one_deploy/sdk';
function PoolHistory({ poolId }: { poolId: string }) {
const { fetchSnapshots } = useForexPoolData(poolId);
const [history, setHistory] = useState<ForexPoolDailySnapshot[]>([]);
useEffect(() => {
// Fetch last 30 days
const endDate = new Date().toISOString().split('T')[0];
const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
.toISOString()
.split('T')[0];
fetchSnapshots({ startDate, endDate }).then(setHistory);
}, [poolId, fetchSnapshots]);
return (
<FlatList
data={history}
keyExtractor={(item) => item.date}
renderItem={({ item }) => (
<View style={styles.row}>
<Text style={styles.date}>{item.date}</Text>
<Text style={styles.cell}>
TVL: ${(item.tvl / 1000).toFixed(0)}k
</Text>
<Text style={styles.cell}>
APY: {(item.apy * 100).toFixed(2)}%
</Text>
<Text style={styles.cell}>
Util: {(item.utilization * 100).toFixed(0)}%
</Text>
</View>
)}
/>
);
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 10,
borderBottomWidth: 1,
borderColor: '#222',
},
date: { color: '#888', fontSize: 12, width: 90 },
cell: { color: '#ccc', fontSize: 12, flex: 1 },
});
聚合所有池指标
import { useForexPools, useForexPoolData } from '@one_deploy/sdk';
function useAggregatedMetrics() {
const { pools } = useForexPools();
const totalTvl = pools.reduce((sum, pool) => sum + pool.totalValueLocked, 0);
const weightedApy = pools.reduce(
(sum, pool) => sum + pool.apy * pool.totalValueLocked,
0
) / (totalTvl || 1);
const avgUtilization = pools.reduce(
(sum, pool) => sum + pool.utilization,
0
) / (pools.length || 1);
return { totalTvl, weightedApy, avgUtilization, poolCount: pools.length };
}
// Usage in a component
function AggregatedMetrics() {
const { totalTvl, weightedApy, avgUtilization } = useAggregatedMetrics();
return (
<View style={{ padding: 16 }}>
<Text style={{ color: '#fff', fontSize: 16, fontWeight: '700' }}>
StableFX Overview
</Text>
<Text style={{ color: '#aaa', marginTop: 8 }}>
Total TVL: ${totalTvl.toLocaleString()}
</Text>
<Text style={{ color: '#aaa' }}>
Weighted APY: {(weightedApy * 100).toFixed(2)}%
</Text>
<Text style={{ color: '#aaa' }}>
Avg Utilization: {(avgUtilization * 100).toFixed(1)}%
</Text>
</View>
);
}
快照数据模型
每个每日快照捕获一个池在 UTC 日终 时的状态:
| 字段 | 描述 | 示例 |
|---|---|---|
date | UTC 日期字符串 | "2025-04-15" |
tvl | 以 USDC 计的总锁仓价值 | 2500000 |
apy | 年化收益率(小数) | 0.0825 |
utilization | 资金利用率(小数) | 0.72 |
volume | 以 USDC 计的总交易量 | 1200000 |
transactionCount | 池交易笔数 | 347 |
netInflow | 存款减去提款 | 85000 |
feesCollected | 以 USDC 计的收取费用 | 3200.50 |
后续步骤
- 交易历史 -- 查看驱动池活动的个别交易。
- 控制台视图 -- 实时监控池操作。
- 组件:OneForexPoolCard -- 在卡片中显示池指标。