跳至主要内容

池指标

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 日终时的状态:

字段描述示例
dateUTC 日期字符串"2025-04-15"
tvl以 USDC 计的总锁仓价值2500000
apy年化收益率(小数)0.0825
utilization资金利用率(小数)0.72
volume以 USDC 计的总交易量1200000
transactionCount池交易笔数347
netInflow存款减去提款85000
feesCollected以 USDC 计的收取费用3200.50

后续步骤