Skip to main content

userVaultEquities

Get user's equity positions across all vaults, including share balances, current value, unrealized gains, and allocation details.

Why Hyperliquid? Build on the dominant perpetuals DEX with 70% market share, $2.7T+ lifetime volume, and $2B TVL with 200K orders/second throughput, zero gas fees, sub-second finality, and fully onchain Central Limit Order Book (CLOB).

When to Use This Endpoint#

The userVaultEquities endpoint is essential for portfolio trackers, wealth managers, and investors who need to:

  • Track Vault Investments — Monitor all vault positions in one place
  • Calculate Portfolio Value — Get real-time value of vault holdings
  • Analyze Performance — Track unrealized gains/losses across vaults
  • Portfolio Management — View vault allocation and diversification

Request#

Endpoint#

POST https://api-hyperliquid-mainnet-info.n.dwellir.com/info

Headers#

HeaderValueRequired
Content-Typeapplication/jsonYes
X-Api-KeyYour API keyYes

Parameters#

ParameterTypeRequiredDescription
typestringYesMust be "userVaultEquities"
userstringYesUser's Ethereum wallet address

Example Request#

{
"type": "userVaultEquities",
"user": "0x66e7293b07744b2d92384d33a0f86b9c333d8597"
}

Response#

Success Response#

[
{
"vaultAddress": "0x115849ce84370f25cadcf0d348510d73837e1aa5",
"equity": "9773.685144",
"lockedUntilTimestamp": 1770368683304
}
]

Response Fields#

The response is an array of vault equity objects. Each object contains:

FieldTypeDescription
vaultAddressstringEthereum address of the vault contract
equitystringUser's current equity value in the vault (USD)
lockedUntilTimestampintegerUnix timestamp (milliseconds) when vault funds unlock

Code Examples#

curl -X POST 'https://api-hyperliquid-mainnet-info.n.dwellir.com/info' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"type": "userVaultEquities",
"user": "0x63E8c7C149556D5f34F833419A287bb9Ef81487f"
}'

Common Use Cases#

1. Calculate Total Vault Portfolio Value#

Get comprehensive portfolio metrics:

async function getVaultPortfolioMetrics(userAddress) {
const equities = await getUserVaultEquities(userAddress);

if (equities.length === 0) {
return { message: 'No vault positions found' };
}

const totalCurrentValue = equities.reduce((sum, e) =>
sum + parseFloat(e.currentValue), 0
);

const totalDeposited = equities.reduce((sum, e) =>
sum + parseFloat(e.netDeposits), 0
);

const totalPnl = equities.reduce((sum, e) =>
sum + parseFloat(e.unrealizedPnl), 0
);

const weightedReturn = equities.reduce((sum, e) => {
const weight = parseFloat(e.currentValue) / totalCurrentValue;
return sum + (parseFloat(e.pnlPercent) * weight);
}, 0);

return {
totalPositions: equities.length,
totalValue: totalCurrentValue.toFixed(2),
totalDeposited: totalDeposited.toFixed(2),
totalPnl: totalPnl.toFixed(2),
totalReturnPercent: ((totalPnl / totalDeposited) * 100).toFixed(2),
weightedReturnPercent: weightedReturn.toFixed(2),
largestPosition: equities.reduce((max, e) =>
parseFloat(e.currentValue) > parseFloat(max.currentValue) ? e : max
)
};
}

// Usage
const metrics = await getVaultPortfolioMetrics('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log('Portfolio Metrics:', metrics);
console.log(`Largest position: ${metrics.largestPosition.vaultName}`);

2. Check Withdrawal Availability#

Determine which positions can be withdrawn:

async function checkWithdrawalAvailability(userAddress) {
const equities = await getUserVaultEquities(userAddress);
const now = Date.now();

const available = [];
const locked = [];

equities.forEach(equity => {
const position = {
vaultName: equity.vaultName,
value: parseFloat(equity.currentValue),
shares: parseFloat(equity.shares),
lockupExpiry: equity.lockupExpiry
};

if (equity.lockupExpiry <= now) {
position.status = 'Available';
available.push(position);
} else {
const daysRemaining = Math.ceil((equity.lockupExpiry - now) / (1000 * 60 * 60 * 24));
position.status = 'Locked';
position.daysRemaining = daysRemaining;
locked.push(position);
}
});

const availableValue = available.reduce((sum, p) => sum + p.value, 0);
const lockedValue = locked.reduce((sum, p) => sum + p.value, 0);

return {
available: available,
locked: locked,
availableValue: availableValue.toFixed(2),
lockedValue: lockedValue.toFixed(2),
totalValue: (availableValue + lockedValue).toFixed(2)
};
}

// Usage
const withdrawal = await checkWithdrawalAvailability('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`\nWithdrawal Status:`);
console.log(`Available: $${withdrawal.availableValue}`);
console.log(`Locked: $${withdrawal.lockedValue}`);

console.log(`\nAvailable Positions (${withdrawal.available.length}):`);
withdrawal.available.forEach(p => {
console.log(` ${p.vaultName}: $${p.value.toLocaleString()}`);
});

console.log(`\nLocked Positions (${withdrawal.locked.length}):`);
withdrawal.locked.forEach(p => {
console.log(` ${p.vaultName}: $${p.value.toLocaleString()} (${p.daysRemaining} days)`);
});

3. Analyze Vault Allocation#

View portfolio diversification across vaults:

async function analyzeVaultAllocation(userAddress) {
const equities = await getUserVaultEquities(userAddress);

const totalValue = equities.reduce((sum, e) =>
sum + parseFloat(e.currentValue), 0
);

const allocation = equities.map(e => {
const value = parseFloat(e.currentValue);
const percentage = (value / totalValue) * 100;

return {
vaultName: e.vaultName,
value: value,
percentage: percentage.toFixed(2),
shares: parseFloat(e.shares),
pnl: parseFloat(e.unrealizedPnl),
pnlPercent: parseFloat(e.pnlPercent)
};
}).sort((a, b) => b.value - a.value);

// Check concentration risk
const top3Concentration = allocation.slice(0, 3).reduce((sum, a) =>
sum + parseFloat(a.percentage), 0
);

return {
allocation: allocation,
totalValue: totalValue.toFixed(2),
positions: allocation.length,
top3Concentration: top3Concentration.toFixed(2),
diversified: top3Concentration < 75
};
}

// Usage
const analysis = await analyzeVaultAllocation('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`\n=== Portfolio Allocation ===`);
console.log(`Total Value: $${parseFloat(analysis.totalValue).toLocaleString()}`);
console.log(`Positions: ${analysis.positions}`);
console.log(`Top 3 Concentration: ${analysis.top3Concentration}%`);
console.log(`Diversified: ${analysis.diversified ? 'Yes' : 'No (concentrated)'}`);

console.log(`\n=== Allocation by Vault ===`);
analysis.allocation.forEach((a, i) => {
console.log(`${i + 1}. ${a.vaultName}: ${a.percentage}% ($${a.value.toLocaleString()})`);
console.log(` PnL: ${a.pnlPercent > 0 ? '+' : ''}${a.pnlPercent}%`);
});

4. Track Performance Over Time#

Monitor vault performance metrics:

async function trackVaultPerformance(userAddress) {
const equities = await getUserVaultEquities(userAddress);

const performance = equities.map(e => {
const currentValue = parseFloat(e.currentValue);
const depositValue = parseFloat(e.netDeposits);
const pnl = parseFloat(e.unrealizedPnl);
const pnlPercent = parseFloat(e.pnlPercent);

// Calculate holding period
const depositDate = new Date(e.depositTimestamp);
const now = new Date();
const daysHeld = Math.floor((now - depositDate) / (1000 * 60 * 60 * 24));

// Annualized return
const annualizedReturn = daysHeld > 0
? (pnlPercent / daysHeld) * 365
: 0;

return {
vaultName: e.vaultName,
currentValue: currentValue,
depositValue: depositValue,
pnl: pnl,
returnPercent: pnlPercent,
daysHeld: daysHeld,
annualizedReturn: annualizedReturn.toFixed(2),
dailyReturn: daysHeld > 0 ? (pnlPercent / daysHeld).toFixed(3) : '0.000'
};
}).sort((a, b) => parseFloat(b.annualizedReturn) - parseFloat(a.annualizedReturn));

return performance;
}

// Usage
const performance = await trackVaultPerformance('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');
console.log(`\n=== Vault Performance ===`);
performance.forEach((p, i) => {
console.log(`\n${i + 1}. ${p.vaultName}`);
console.log(` Value: $${p.currentValue.toLocaleString()}`);
console.log(` Return: ${p.returnPercent > 0 ? '+' : ''}${p.returnPercent}%`);
console.log(` Days Held: ${p.daysHeld}`);
console.log(` Annualized: ${p.annualizedReturn}%`);
console.log(` Daily Avg: ${p.dailyReturn}%`);
});

5. Identify Best and Worst Performers#

Analyze which vaults are performing well:

async function identifyPerformers(userAddress) {
const equities = await getUserVaultEquities(userAddress);

// Sort by PnL percentage
const sorted = [...equities].sort((a, b) =>
parseFloat(b.pnlPercent) - parseFloat(a.pnlPercent)
);

const bestPerformers = sorted.slice(0, 3).map(e => ({
vaultName: e.vaultName,
pnl: parseFloat(e.unrealizedPnl),
pnlPercent: parseFloat(e.pnlPercent),
value: parseFloat(e.currentValue)
}));

const worstPerformers = sorted.slice(-3).reverse().map(e => ({
vaultName: e.vaultName,
pnl: parseFloat(e.unrealizedPnl),
pnlPercent: parseFloat(e.pnlPercent),
value: parseFloat(e.currentValue)
}));

// Calculate averages
const avgPnlPercent = equities.reduce((sum, e) =>
sum + parseFloat(e.pnlPercent), 0
) / equities.length;

return {
bestPerformers: bestPerformers,
worstPerformers: worstPerformers,
avgReturn: avgPnlPercent.toFixed(2),
spread: (parseFloat(sorted[0].pnlPercent) - parseFloat(sorted[sorted.length - 1].pnlPercent)).toFixed(2)
};
}

// Usage
const performers = await identifyPerformers('0x63E8c7C149556D5f34F833419A287bb9Ef81487f');

console.log(`\n=== Best Performers ===`);
performers.bestPerformers.forEach((p, i) => {
console.log(`${i + 1}. ${p.vaultName}: +${p.pnlPercent}% ($${p.pnl.toLocaleString()})`);
});

console.log(`\n=== Worst Performers ===`);
performers.worstPerformers.forEach((p, i) => {
console.log(`${i + 1}. ${p.vaultName}: ${p.pnlPercent}% ($${p.pnl.toLocaleString()})`);
});

console.log(`\nPortfolio Statistics:`);
console.log(`Average Return: ${performers.avgReturn}%`);
console.log(`Performance Spread: ${performers.spread}%`);

Error Handling#

Common Errors#

ErrorCauseSolution
401 UnauthorizedInvalid API keyVerify your API key is correct
400 Bad RequestMissing or invalid user addressEnsure valid Ethereum address format
429 Too Many RequestsRate limit exceededImplement request throttling
500 Internal Server ErrorServer issueRetry with exponential backoff

Error Response Example#

{
"error": "Missing required parameter: user",
"code": "MISSING_PARAMETER"
}

Robust Error Handling#

async function safeGetUserVaultEquities(userAddress, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await getUserVaultEquities(userAddress);
} catch (error) {
if (error.response?.status === 429) {
// Rate limit - exponential backoff
const delay = Math.pow(2, i) * 1000;
await new Promise(r => setTimeout(r, delay));
} else if (error.response?.status === 400) {
throw new Error('Invalid user address');
} else if (i === maxRetries - 1) {
throw error;
}
}
}
}

Best Practices#

  1. Poll responsibly — Update vault positions every 30-60 seconds for dashboards
  2. Handle empty results — Users may have no vault positions
  3. Check lockup periods — Verify withdrawal availability before transactions
  4. Track allocation — Monitor portfolio concentration and diversification
  5. Calculate returns properly — Account for deposits/withdrawals over time

Track your Hyperliquid vault investments with Dwellir's HyperCore Info Endpoint. Get your API key →