⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

suix_getAllBalances

Retrieves all coin balances for a specific address on the Sui blockchain, providing a comprehensive overview of all owned fungible tokens in a single request.

Overview

The suix_getAllBalances method is essential for portfolio management and wallet applications. Unlike suix_getBalance which queries a specific coin type, this method returns all coin types owned by an address, including native SUI tokens and any custom fungible tokens. This makes it perfect for displaying complete portfolio overviews, calculating total portfolio values, and discovering all assets owned by an address.

Parameters

ParameterTypeRequiredDescription
ownerstringYesThe Sui address to query (66-character hex string with 0x prefix)

Returns

Returns an array of balance objects, one for each coin type owned by the address.

FieldTypeDescription
coinTypestringThe type of coin (e.g., "0x2::sui::SUI")
coinObjectCountnumberNumber of coin objects of this type
totalBalancestringTotal balance across all coin objects (in base units)
lockedBalanceobjectLocked balance information (if applicable)

Balance Array Structure

Each balance object in the array contains:

  • coinType: Full type identifier for the coin
  • coinObjectCount: How many individual coin objects make up this balance
  • totalBalance: Aggregate balance in the smallest denomination
  • lockedBalance: Any locked/staked amounts (optional)

Common Coin Types

  • Native SUI: 0x2::sui::SUI
  • USDC: 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC
  • Custom Tokens: 0x{package}::{module}::{type}

Code Examples

curl -X POST https://api-sui-mainnet-full.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "suix_getAllBalances",
"params": [
"0xac5bceec1b789ff840d7d4e6ce4ce61c90d190a7f8c4f4ddf0bff6ee2413c33c"
],
"id": 1
}'

Response Example

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"coinType": "0x1a98df3cad1701b8247cb716cef8f687adb657b5d28ffcb1ee91fd9973f70941::rmy::RMY",
"coinObjectCount": 1,
"totalBalance": "238543215486",
"lockedBalance": {}
},
{
"coinType": "0x2125f8f0af64238b2e23bec7897066fd5e5ea97969d7221fd67867a1e1e5592a::NaviReward::NAVIREWARD",
"coinObjectCount": 1,
"totalBalance": "7926000000000",
"lockedBalance": {}
},
...
]
}

Common Use Cases

1. Portfolio Dashboard

async function buildPortfolioDashboard(address) {
const balances = await client.getAllBalances({ owner: address });

const dashboard = {
totalAssets: balances.length,
nonZeroAssets: 0,
totalValue: 0, // Would need price data
assets: []
};

for (const balance of balances) {
const asset = {
symbol: extractSymbol(balance.coinType),
coinType: balance.coinType,
balance: balance.totalBalance,
objectCount: balance.coinObjectCount,
hasLockedBalance: !!balance.lockedBalance
};

if (parseInt(balance.totalBalance) > 0) {
dashboard.nonZeroAssets++;
}

dashboard.assets.push(asset);
}

// Sort by balance (highest first)
dashboard.assets.sort((a, b) =>
parseInt(b.balance) - parseInt(a.balance)
);

return dashboard;
}

2. Asset Discovery

async function discoverNewAssets(address, knownCoinTypes = []) {
const balances = await client.getAllBalances({ owner: address });

const newAssets = balances.filter(balance =>
!knownCoinTypes.includes(balance.coinType) &&
parseInt(balance.totalBalance) > 0
);

console.log(`Discovered ${newAssets.length} new assets:`);

for (const asset of newAssets) {
console.log(`- ${extractSymbol(asset.coinType)}: ${asset.totalBalance}`);

// Optionally fetch metadata for new assets
try {
const metadata = await client.getCoinMetadata({
coinType: asset.coinType
});

console.log(` Metadata: ${metadata?.name || 'Unknown'} (${metadata?.symbol || 'N/A'})`);
} catch (error) {
console.log(` Could not fetch metadata: ${error.message}`);
}
}

return newAssets;
}

3. Balance Monitoring with Alerts

class BalanceMonitor {
constructor(client) {
this.client = client;
this.thresholds = new Map();
this.lastBalances = new Map();
}

setThreshold(address, coinType, threshold) {
const key = `${address}:${coinType}`;
this.thresholds.set(key, threshold);
}

async checkBalances(address) {
const currentBalances = await this.client.getAllBalances({ owner: address });
const alerts = [];

for (const balance of currentBalances) {
const key = `${address}:${balance.coinType}`;
const threshold = this.thresholds.get(key);
const currentAmount = parseInt(balance.totalBalance);
const lastAmount = this.lastBalances.get(key) || 0;

// Check threshold alerts
if (threshold && currentAmount < threshold) {
alerts.push({
type: 'low_balance',
coinType: balance.coinType,
current: currentAmount,
threshold: threshold,
symbol: extractSymbol(balance.coinType)
});
}

// Check for significant changes
const percentChange = lastAmount > 0 ?
((currentAmount - lastAmount) / lastAmount) * 100 : 0;

if (Math.abs(percentChange) > 10) { // 10% change
alerts.push({
type: percentChange > 0 ? 'balance_increase' : 'balance_decrease',
coinType: balance.coinType,
current: currentAmount,
previous: lastAmount,
percentChange: percentChange,
symbol: extractSymbol(balance.coinType)
});
}

this.lastBalances.set(key, currentAmount);
}

return alerts;
}
}

// Usage
const monitor = new BalanceMonitor(client);
monitor.setThreshold(address, '0x2::sui::SUI', 1_000_000_000); // 1 SUI minimum

const alerts = await monitor.checkBalances(address);
alerts.forEach(alert => {
console.log(`Alert: ${alert.type} for ${alert.symbol}`);
});

4. Portfolio Value Calculator

async function calculatePortfolioValue(address, priceOracle) {
const balances = await client.getAllBalances({ owner: address });
let totalValue = 0;
const breakdown = [];

for (const balance of balances) {
const amount = parseInt(balance.totalBalance);

if (amount === 0) continue;

try {
// Get current price from oracle
const price = await priceOracle.getPrice(balance.coinType);
const decimals = await getDecimals(balance.coinType);
const formattedAmount = amount / Math.pow(10, decimals);
const value = formattedAmount * price;

totalValue += value;

breakdown.push({
symbol: extractSymbol(balance.coinType),
coinType: balance.coinType,
amount: formattedAmount,
price: price,
value: value,
percentage: 0 // Will be calculated after total
});
} catch (error) {
console.warn(`Could not get price for ${balance.coinType}:`, error.message);

breakdown.push({
symbol: extractSymbol(balance.coinType),
coinType: balance.coinType,
amount: amount / Math.pow(10, 9), // Assume 9 decimals
price: 0,
value: 0,
percentage: 0
});
}
}

// Calculate percentages
breakdown.forEach(item => {
item.percentage = totalValue > 0 ? (item.value / totalValue) * 100 : 0;
});

// Sort by value
breakdown.sort((a, b) => b.value - a.value);

return {
totalValue,
breakdown,
lastUpdated: new Date().toISOString()
};
}

Advanced Portfolio Management

1. Portfolio Rebalancing Suggestions

async function suggestRebalancing(address, targetAllocations) {
const balances = await client.getAllBalances({ owner: address });
const currentValue = await calculatePortfolioValue(address, priceOracle);

const suggestions = [];

for (const [coinType, targetPercent] of Object.entries(targetAllocations)) {
const current = currentValue.breakdown.find(b => b.coinType === coinType);
const currentPercent = current ? current.percentage : 0;
const difference = targetPercent - currentPercent;

if (Math.abs(difference) > 5) { // 5% threshold
const targetValue = (currentValue.totalValue * targetPercent) / 100;
const currentValue = current ? current.value : 0;
const adjustment = targetValue - currentValue;

suggestions.push({
coinType: coinType,
symbol: extractSymbol(coinType),
currentPercent: currentPercent,
targetPercent: targetPercent,
difference: difference,
action: adjustment > 0 ? 'buy' : 'sell',
amount: Math.abs(adjustment)
});
}
}

return suggestions;
}

2. Historical Balance Tracking

class PortfolioHistoryTracker {
constructor(client, storage) {
this.client = client;
this.storage = storage; // Database or local storage
}

async recordSnapshot(address) {
const balances = await this.client.getAllBalances({ owner: address });
const timestamp = Date.now();

const snapshot = {
address,
timestamp,
balances: balances.map(b => ({
coinType: b.coinType,
totalBalance: b.totalBalance,
coinObjectCount: b.coinObjectCount,
lockedBalance: b.lockedBalance
}))
};

await this.storage.saveSnapshot(snapshot);
return snapshot;
}

async getHistoricalData(address, days = 30) {
const snapshots = await this.storage.getSnapshots(address, days);

// Process into time series data
const timeSeries = {};

snapshots.forEach(snapshot => {
snapshot.balances.forEach(balance => {
if (!timeSeries[balance.coinType]) {
timeSeries[balance.coinType] = [];
}

timeSeries[balance.coinType].push({
timestamp: snapshot.timestamp,
balance: balance.totalBalance,
objectCount: balance.coinObjectCount
});
});
});

return timeSeries;
}

async generateGrowthReport(address, days = 30) {
const historyData = await this.getHistoricalData(address, days);
const report = {
period: days,
assets: {}
};

for (const [coinType, data] of Object.entries(historyData)) {
if (data.length < 2) continue;

const oldest = data[0];
const newest = data[data.length - 1];
const growth = parseInt(newest.balance) - parseInt(oldest.balance);
const growthPercent = parseInt(oldest.balance) > 0 ?
(growth / parseInt(oldest.balance)) * 100 : 0;

report.assets[coinType] = {
symbol: extractSymbol(coinType),
startBalance: oldest.balance,
endBalance: newest.balance,
absoluteGrowth: growth.toString(),
percentGrowth: growthPercent,
dataPoints: data.length
};
}

return report;
}
}

Performance Optimization

1. Efficient Portfolio Polling

class OptimizedPortfolioFetcher {
constructor(client) {
this.client = client;
this.cache = new Map();
this.cacheTimeout = 30000; // 30 seconds
}

async getBalancesWithCache(address) {
const cacheKey = address;
const cached = this.cache.get(cacheKey);

if (cached && (Date.now() - cached.timestamp) < this.cacheTimeout) {
return cached.balances;
}

const balances = await this.client.getAllBalances({ owner: address });

this.cache.set(cacheKey, {
balances,
timestamp: Date.now()
});

return balances;
}

async batchGetBalances(addresses) {
const promises = addresses.map(address =>
this.getBalancesWithCache(address).catch(error => ({
address,
error: error.message
}))
);

const results = await Promise.all(promises);
return results;
}

clearCache() {
this.cache.clear();
}
}

2. Smart Update Detection

async function detectPortfolioUpdates(address, lastKnownBalances) {
const currentBalances = await client.getAllBalances({ owner: address });

// Quick check - compare array lengths and coin types
if (currentBalances.length !== lastKnownBalances.length) {
return { hasUpdates: true, reason: 'coin_count_changed' };
}

const currentTypes = new Set(currentBalances.map(b => b.coinType));
const lastTypes = new Set(lastKnownBalances.map(b => b.coinType));

if (currentTypes.size !== lastTypes.size ||
![...currentTypes].every(type => lastTypes.has(type))) {
return { hasUpdates: true, reason: 'coin_types_changed' };
}

// Check individual balances
for (let i = 0; i < currentBalances.length; i++) {
const current = currentBalances[i];
const last = lastKnownBalances.find(b => b.coinType === current.coinType);

if (!last || current.totalBalance !== last.totalBalance) {
return {
hasUpdates: true,
reason: 'balance_changed',
changedCoin: current.coinType
};
}
}

return { hasUpdates: false };
}

Error Handling and Edge Cases

1. Comprehensive Error Handling

async function safeGetAllBalances(address) {
try {
// Validate address format
if (!/^0x[a-fA-F0-9]{64}$/.test(address)) {
throw new Error('Invalid Sui address format');
}

const balances = await client.getAllBalances({ owner: address });

// Validate response structure
if (!Array.isArray(balances)) {
throw new Error('Invalid response: expected array of balances');
}

// Filter out invalid entries
const validBalances = balances.filter(balance =>
balance.coinType &&
typeof balance.totalBalance === 'string' &&
typeof balance.coinObjectCount === 'number'
);

if (validBalances.length !== balances.length) {
console.warn(`Filtered ${balances.length - validBalances.length} invalid balance entries`);
}

return {
success: true,
balances: validBalances,
metadata: {
totalTypes: validBalances.length,
hasLockedBalances: validBalances.some(b => b.lockedBalance),
timestamp: Date.now()
}
};

} catch (error) {
return {
success: false,
error: error.message,
balances: [],
metadata: {
timestamp: Date.now()
}
};
}
}

2. Handle Edge Cases

function processBalanceEdgeCases(balances) {
const processed = {
valid: [],
zeroBalances: [],
dustBalances: [],
lockedOnly: [],
issues: []
};

balances.forEach((balance, index) => {
const amount = parseInt(balance.totalBalance);

// Check for zero balances
if (amount === 0) {
processed.zeroBalances.push(balance);
return;
}

// Check for dust (very small amounts)
if (amount < 1000) { // Less than 0.000001 for 9-decimal coins
processed.dustBalances.push(balance);
}

// Check locked-only balances
if (balance.lockedBalance &&
parseInt(balance.lockedBalance.number) >= amount) {
processed.lockedOnly.push(balance);
}

// Check for potential issues
if (balance.coinObjectCount === 0 && amount > 0) {
processed.issues.push({
index,
issue: 'positive_balance_zero_objects',
balance
});
}

if (balance.coinObjectCount > 100) {
processed.issues.push({
index,
issue: 'too_many_coin_objects',
balance
});
}

processed.valid.push(balance);
});

return processed;
}

Best Practices

1. Efficient Data Processing

  • Filter zero balances when displaying portfolio views
  • Cache coin metadata to avoid repeated RPC calls
  • Use pagination for addresses with many coin types
  • Implement progressive loading for better user experience

2. Portfolio Management

  • Track historical snapshots for growth analysis
  • Set up balance alerts for important thresholds
  • Monitor locked balances for staking and DeFi positions
  • Aggregate small balances to reduce UI clutter

3. Performance Optimization

  • Cache results for frequently queried addresses
  • Batch multiple address queries when possible
  • Use WebSocket subscriptions for real-time updates
  • Implement smart update detection to minimize unnecessary calls

4. Error Resilience

  • Validate address format before making requests
  • Handle network timeouts gracefully
  • Retry failed requests with exponential backoff
  • Filter invalid response data to prevent application errors

5. User Experience

  • Display loading states during data fetching
  • Show meaningful error messages to users
  • Format balances according to coin decimals
  • Highlight significant changes in portfolio values

Need help? Contact our support team or check the Sui documentation.