Forex Hooks
The ONE SDK exports 5 specialized hooks for on-chain forex (StableFX) trading, plus token management functions for authentication. These hooks are standalone -- they do not require OneProvider and manage their own auth tokens and engine URL.
Import
import {
// Hooks
useForexPools,
useForexInvestments,
useForexSimulation,
useForexPoolData,
useForexTrading,
// Token management
setForexAccessToken,
clearForexAccessToken,
setForexEngineUrl,
} from '@one_deploy/sdk';
Token Management
Forex hooks do not read from OneProvider context. You must call setForexAccessToken and setForexEngineUrl before using any forex hook. Calling a hook without a token results in an UNAUTHORIZED error.
Setup
import {
setForexAccessToken,
clearForexAccessToken,
setForexEngineUrl,
} from '@one_deploy/sdk';
// 1. Set the engine URL (call once at app startup)
setForexEngineUrl('https://engine.one23.io');
// 2. Set the user's access token after authentication
function onUserLogin(accessToken: string) {
setForexAccessToken(accessToken);
}
// 3. Clear on logout
function onUserLogout() {
clearForexAccessToken();
}
Function Signatures
/** Set the bearer token used by all forex hooks and API calls.
* Call this once after authentication. The token is stored in module-level
* state and shared across all forex hook instances. */
function setForexAccessToken(token: string): void;
/** Clear the current forex access token.
* Subsequent hook calls will return UNAUTHORIZED errors until a new token is set. */
function clearForexAccessToken(): void;
/** Set the ONE Engine URL for forex API calls.
* Defaults to 'https://engine.one23.io' if not called.
* Useful for staging/development environments. */
function setForexEngineUrl(url: string): void;
Why Standalone?
Forex components are designed primarily for React Native, where the provider model used by the web widgets does not apply. The standalone token functions allow you to integrate forex into any React Native navigation structure without nesting providers. They also work on web.
Full Setup Example
import {
setForexAccessToken,
clearForexAccessToken,
setForexEngineUrl,
useForexPools,
} from '@one_deploy/sdk';
import { useEffect, useState } from 'react';
function ForexApp() {
const [isReady, setIsReady] = useState(false);
useEffect(() => {
async function init() {
setForexEngineUrl('https://engine.one23.io');
const token = await fetchAccessTokenFromYourAuthService();
setForexAccessToken(token);
setIsReady(true);
}
init();
return () => {
clearForexAccessToken();
};
}, []);
if (!isReady) return <p>Authenticating...</p>;
return (
<>
<PoolList />
<InvestmentDashboard />
</>
);
}
Core Types
These types are shared across all forex hooks:
type ForexPoolType = 'clearing' | 'hedging' | 'insurance';
interface ForexPool {
id: string;
type: ForexPoolType;
totalValueLocked: number;
apy: number;
utilization: number;
currency: string;
createdAt: string;
updatedAt: string;
}
interface ForexInvestment {
id: string;
poolId: string;
poolType: ForexPoolType;
amount: number;
currentValue: number;
pnl: number;
pnlPercentage: number;
currency: string;
status: 'active' | 'matured' | 'withdrawn';
investedAt: string;
maturesAt: string;
}
interface ForexPoolDailyMetric {
date: string;
tvl: number;
apy: number;
utilization: number;
volume: number;
feeRevenue: number;
}
useForexPools
Fetches all forex liquidity pools (clearing, hedging, and insurance).
Signature
function useForexPools(): UseForexPoolsResult;
Return Type
interface UseForexPoolsResult {
/** Array of all forex pools. */
pools: ForexPool[];
/** Whether the initial fetch is in progress. */
isLoading: boolean;
/** Error object, or null. */
error: OneSDKError | null;
/** Manually trigger a refetch. */
refetch: () => Promise<void>;
}
Usage
import { useForexPools } from '@one_deploy/sdk';
function PoolList() {
const { pools, isLoading, error } = useForexPools();
if (isLoading) return <p>Loading pools...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h2>Forex Liquidity Pools</h2>
{pools.map((pool) => (
<div key={pool.id} style={{ padding: 12, borderBottom: '1px solid #eee' }}>
<strong>{pool.type.toUpperCase()} Pool</strong>
<dl>
<dt>TVL</dt><dd>${pool.totalValueLocked.toLocaleString()}</dd>
<dt>APY</dt><dd>{pool.apy.toFixed(2)}%</dd>
<dt>Utilization</dt><dd>{(pool.utilization * 100).toFixed(1)}%</dd>
<dt>Currency</dt><dd>{pool.currency}</dd>
</dl>
</div>
))}
</div>
);
}
useForexInvestments
Fetches the authenticated user's forex investment positions across all pools.
Signature
function useForexInvestments(): UseForexInvestmentsResult;
Return Type
interface UseForexInvestmentsResult {
/** Array of the user's forex investments. */
investments: ForexInvestment[];
/** Total invested amount across all positions (in USD). */
totalInvested: number;
/** Total current value across all positions (in USD). */
totalCurrentValue: number;
/** Aggregate P&L in USD. */
totalPnl: number;
/** Whether the fetch is in progress. */
isLoading: boolean;
/** Error object, or null. */
error: OneSDKError | null;
/** Manually trigger a refetch. */
refetch: () => Promise<void>;
}
Usage
import { useForexInvestments } from '@one_deploy/sdk';
function InvestmentDashboard() {
const {
investments,
totalInvested,
totalCurrentValue,
totalPnl,
isLoading,
error,
} = useForexInvestments();
if (isLoading) return <p>Loading investments...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h2>My Forex Investments</h2>
<div style={{ display: 'flex', gap: 24 }}>
<div>
<strong>Total Invested</strong>
<p>${totalInvested.toLocaleString()}</p>
</div>
<div>
<strong>Current Value</strong>
<p>${totalCurrentValue.toLocaleString()}</p>
</div>
<div>
<strong>P&L</strong>
<p style={{ color: totalPnl >= 0 ? 'green' : 'red' }}>
{totalPnl >= 0 ? '+' : ''}${totalPnl.toFixed(2)}
</p>
</div>
</div>
<h3>Positions</h3>
{investments.map((inv) => (
<div key={inv.id} style={{ padding: 8, borderBottom: '1px solid #eee' }}>
<strong>{inv.poolType} pool</strong> |
Invested: ${inv.amount.toFixed(2)} |
Current: ${inv.currentValue.toFixed(2)} |
P&L: <span style={{ color: inv.pnl >= 0 ? 'green' : 'red' }}>
{inv.pnl >= 0 ? '+' : ''}{inv.pnlPercentage.toFixed(2)}%
</span> |
Status: {inv.status}
</div>
))}
</div>
);
}
useForexSimulation
Runs pool simulations client-side using the forexSimulationEngine. Use this to model capital allocation scenarios before investing.
Signature
function useForexSimulation(): UseForexSimulationResult;
Return Type
interface UseForexSimulationResult {
/** Run a simulation with given parameters. */
simulate: (params: ForexSimulationParams) => Promise<ForexSimulationOutput>;
/** The most recent simulation result, or null. */
result: ForexSimulationOutput | null;
/** Whether a simulation is currently running. */
isSimulating: boolean;
/** Error object, or null. */
error: OneSDKError | null;
/** Clear the current result. */
reset: () => void;
}
interface ForexSimulationParams {
/** Total deposit amount in USD. */
depositAmount: number;
/** Duration of the simulation in days. */
durationDays: number;
/** Target pool type. */
poolType: ForexPoolType;
/** Optional: override the capital split ratio (defaults to FOREX_CAPITAL_SPLIT = 0.5). */
capitalSplitOverride?: number;
}
interface ForexSimulationOutput {
/** Projected value at the end of the simulation period. */
projectedValue: number;
/** Projected yield (profit) in USD. */
projectedYield: number;
/** Projected APY based on the simulation. */
projectedApy: number;
/** Breakdown of capital allocation across pools. */
allocation: {
tradingCapital: number;
clearingPool: number;
hedgingPool: number;
insurancePool: number;
};
/** Day-by-day projection data points. */
projectionCurve: Array<{
day: number;
value: number;
yield: number;
}>;
}
Usage
import { useForexSimulation } from '@one_deploy/sdk';
function SimulationTool() {
const { simulate, result, isSimulating, error, reset } = useForexSimulation();
const handleSimulate = async () => {
await simulate({
depositAmount: 10000,
durationDays: 90,
poolType: 'clearing',
});
};
return (
<div>
<h2>Pool Simulation</h2>
<button onClick={handleSimulate} disabled={isSimulating}>
{isSimulating ? 'Simulating...' : 'Simulate $10,000 / 90 days / Clearing'}
</button>
{result && (
<button onClick={reset}>Clear</button>
)}
{error && <p>Error: {error.message}</p>}
{result && (
<div>
<dl>
<dt>Projected Value</dt><dd>${result.projectedValue.toFixed(2)}</dd>
<dt>Projected Yield</dt><dd>${result.projectedYield.toFixed(2)}</dd>
<dt>Projected APY</dt><dd>{result.projectedApy.toFixed(2)}%</dd>
</dl>
<h3>Capital Allocation</h3>
<ul>
<li>Trading Capital: ${result.allocation.tradingCapital.toFixed(2)}</li>
<li>Clearing Pool: ${result.allocation.clearingPool.toFixed(2)}</li>
<li>Hedging Pool: ${result.allocation.hedgingPool.toFixed(2)}</li>
<li>Insurance Pool: ${result.allocation.insurancePool.toFixed(2)}</li>
</ul>
<h3>Projection Curve</h3>
<ul>
{result.projectionCurve
.filter((_, i) => i % 10 === 0 || i === result.projectionCurve.length - 1)
.map((point) => (
<li key={point.day}>
Day {point.day}: ${point.value.toFixed(2)} (+${point.yield.toFixed(2)})
</li>
))}
</ul>
</div>
)}
</div>
);
}
useForexPoolData
Fetches detailed daily metrics for a specific forex pool. Use this for pool analytics and chart rendering.
Signature
function useForexPoolData(poolId?: string): UseForexPoolDataResult;
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
poolId | string | No | The pool ID to fetch metrics for. When undefined, the hook is idle. |
Return Type
interface UseForexPoolDataResult {
/** The pool object, or null if not loaded. */
pool: ForexPool | null;
/** Array of daily metric snapshots. */
dailyMetrics: ForexPoolDailyMetric[];
/** Whether the fetch is in progress. */
isLoading: boolean;
/** Error object, or null. */
error: OneSDKError | null;
/** Manually trigger a refetch. */
refetch: () => Promise<void>;
}
Usage
import { useForexPoolData } from '@one_deploy/sdk';
function PoolDetailView({ poolId }: { poolId: string }) {
const { pool, dailyMetrics, isLoading, error } = useForexPoolData(poolId);
if (isLoading) return <p>Loading pool data...</p>;
if (error) return <p>Error: {error.message}</p>;
if (!pool) return <p>Pool not found.</p>;
return (
<div>
<h2>{pool.type.toUpperCase()} Pool</h2>
<dl>
<dt>TVL</dt><dd>${pool.totalValueLocked.toLocaleString()}</dd>
<dt>APY</dt><dd>{pool.apy.toFixed(2)}%</dd>
<dt>Utilization</dt><dd>{(pool.utilization * 100).toFixed(1)}%</dd>
</dl>
<h3>Daily Metrics (last {dailyMetrics.length} days)</h3>
<table>
<thead>
<tr>
<th>Date</th>
<th>TVL</th>
<th>APY</th>
<th>Utilization</th>
<th>Volume</th>
<th>Fees</th>
</tr>
</thead>
<tbody>
{dailyMetrics.slice(-7).map((m) => (
<tr key={m.date}>
<td>{m.date}</td>
<td>${m.tvl.toLocaleString()}</td>
<td>{m.apy.toFixed(2)}%</td>
<td>{(m.utilization * 100).toFixed(1)}%</td>
<td>${m.volume.toLocaleString()}</td>
<td>${m.feeRevenue.toFixed(2)}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
useForexTrading
A combined hook that aggregates the functionality of all four hooks above into a single interface, plus methods to create and manage forex positions.
Signature
function useForexTrading(): UseForexTradingResult;
Return Type
interface UseForexTradingResult {
/** All forex pools. */
pools: ForexPool[];
/** User's investment positions. */
investments: ForexInvestment[];
/** Create a new forex investment. */
createInvestment: (params: CreateForexInvestmentParams) => Promise<ForexInvestment>;
/** Withdraw from an existing investment. */
withdrawInvestment: (investmentId: string) => Promise<void>;
/** Run a pool simulation. */
simulate: (params: ForexSimulationParams) => Promise<ForexSimulationOutput>;
/** Fetch daily metrics for a pool. */
getPoolData: (poolId: string) => Promise<{
pool: ForexPool;
dailyMetrics: ForexPoolDailyMetric[];
}>;
/** Whether any data is loading. */
isLoading: boolean;
/** The most recent error, or null. */
error: OneSDKError | null;
/** Refetch all data (pools and investments). */
refetch: () => Promise<void>;
}
interface CreateForexInvestmentParams {
/** The pool ID to invest in. */
poolId: string;
/** Investment amount in USD. */
amount: number;
/** Investment duration in days. */
durationDays: number;
}
Usage
import { useForexTrading } from '@one_deploy/sdk';
function ForexTradingDashboard() {
const {
pools,
investments,
createInvestment,
withdrawInvestment,
simulate,
isLoading,
error,
refetch,
} = useForexTrading();
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
const handleInvest = async (poolId: string) => {
// Simulate first
const sim = await simulate({
depositAmount: 5000,
durationDays: 30,
poolType: 'clearing',
});
console.log('Projected yield:', sim.projectedYield);
// Create the investment
const investment = await createInvestment({
poolId,
amount: 5000,
durationDays: 30,
});
console.log('Created investment:', investment.id);
await refetch();
};
return (
<div>
{/* Pool overview */}
<h2>Forex Pools</h2>
{pools.map((pool) => (
<div key={pool.id} style={{ padding: 12, borderBottom: '1px solid #eee' }}>
<strong>{pool.type.toUpperCase()}</strong> |
TVL: ${pool.totalValueLocked.toLocaleString()} |
APY: {pool.apy.toFixed(2)}%
<button onClick={() => handleInvest(pool.id)} style={{ marginLeft: 12 }}>
Invest $5,000
</button>
</div>
))}
{/* Active investments */}
<h2>My Investments ({investments.length})</h2>
{investments.map((inv) => (
<div key={inv.id} style={{ padding: 8, borderBottom: '1px solid #eee' }}>
{inv.poolType} pool |
${inv.amount.toFixed(2)} invested |
Current: ${inv.currentValue.toFixed(2)} |
Status: {inv.status}
{inv.status === 'matured' && (
<button onClick={() => withdrawInvestment(inv.id)} style={{ marginLeft: 8 }}>
Withdraw
</button>
)}
</div>
))}
</div>
);
}
Complete Integration Example
End-to-end example showing token setup, pool browsing, simulation, and investment:
import {
setForexAccessToken,
setForexEngineUrl,
clearForexAccessToken,
useForexPools,
useForexSimulation,
useForexTrading,
FOREX_CAPITAL_SPLIT,
} from '@one_deploy/sdk';
import { useEffect, useState } from 'react';
function ForexScreen({ userAccessToken }: { userAccessToken: string }) {
const [ready, setReady] = useState(false);
useEffect(() => {
setForexEngineUrl('https://engine.one23.io');
setForexAccessToken(userAccessToken);
setReady(true);
return () => clearForexAccessToken();
}, [userAccessToken]);
if (!ready) return <p>Initializing forex...</p>;
return <ForexContent />;
}
function ForexContent() {
const { pools, isLoading: poolsLoading } = useForexPools();
const { simulate, result: simResult, isSimulating } = useForexSimulation();
const {
investments,
createInvestment,
withdrawInvestment,
isLoading: tradingLoading,
error,
} = useForexTrading();
const [selectedPool, setSelectedPool] = useState<string | null>(null);
if (poolsLoading || tradingLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
const handleSimulate = async () => {
if (!selectedPool) return;
const pool = pools.find((p) => p.id === selectedPool);
if (!pool) return;
await simulate({
depositAmount: 10000,
durationDays: 60,
poolType: pool.type,
});
};
const handleInvest = async () => {
if (!selectedPool) return;
const investment = await createInvestment({
poolId: selectedPool,
amount: 10000,
durationDays: 60,
});
console.log('Created investment:', investment.id);
};
return (
<div>
<p>Capital split ratio: {FOREX_CAPITAL_SPLIT * 100}% trading / {FOREX_CAPITAL_SPLIT * 100}% reserves</p>
{/* Pool picker */}
<h2>Select Pool</h2>
<select
value={selectedPool ?? ''}
onChange={(e) => setSelectedPool(e.target.value || null)}
>
<option value="">-- Choose a pool --</option>
{pools.map((p) => (
<option key={p.id} value={p.id}>
{p.type.toUpperCase()} -- TVL: ${p.totalValueLocked.toLocaleString()} -- APY: {p.apy.toFixed(2)}%
</option>
))}
</select>
<button onClick={handleSimulate} disabled={!selectedPool || isSimulating}>
{isSimulating ? 'Running...' : 'Simulate $10K / 60 days'}
</button>
{simResult && (
<div>
<h3>Simulation Result</h3>
<p>Projected Value: ${simResult.projectedValue.toFixed(2)}</p>
<p>Projected Yield: ${simResult.projectedYield.toFixed(2)}</p>
<p>Projected APY: {simResult.projectedApy.toFixed(2)}%</p>
<button onClick={handleInvest}>Invest $10,000</button>
</div>
)}
{/* Investments */}
<h2>My Investments</h2>
{investments.length === 0 && <p>No investments yet.</p>}
{investments.map((inv) => (
<div key={inv.id}>
{inv.poolType} | ${inv.amount} -> ${inv.currentValue.toFixed(2)} |
{inv.status === 'matured' && (
<button onClick={() => withdrawInvestment(inv.id)}>Withdraw</button>
)}
</div>
))}
</div>
);
}
See Also
- Hooks Overview -- all hook categories.
- Forex Overview -- StableFX architecture, 3-pool system, currency pairs.
- Capital Allocation -- the 50/50 split model.
- Creating Investments -- step-by-step investment guide.
- AI Trading Hooks -- similar standalone hooks for AI trading.