Loading...
Loading...
This skill should be used when the user asks to 'check my wallet balance', 'show my token holdings', 'how much ETH do I have', 'what tokens do I have', 'check my portfolio value', 'view my assets', 'how much is my portfolio worth', 'what\'s in my wallet', or mentions checking wallet balance, total assets, token holdings, portfolio value, remaining funds, DeFi positions, or multi-chain balance lookup. Supports Solana, Ethereum, Base, BSC, Polygon, Arbitrum, and 20+ other chains. Do NOT use for general programming questions about balance variables or API documentation. Do NOT use when the user is asking how to build or integrate a balance feature into code.
npx skill4agent add okx/onchainos-skills okx-wallet-portfoliohttps://web3.okx.com/api/v6/dex/balanceOK-ACCESS-KEYOK-ACCESS-SIGNOK-ACCESS-PASSPHRASEOK-ACCESS-TIMESTAMPOKX_API_KEYOKX_SECRET_KEYOKX_PASSPHRASEimport crypto from 'crypto';
const BASE = 'https://web3.okx.com';
// Signature rule:
// GET → body = "", requestPath includes query string (e.g., "/api/v6/dex/balance/all-token-balances-by-address?address=0x...&chains=1,56")
// POST → body = JSON string of request body, requestPath is path only (e.g., "/api/v6/dex/balance/token-balances-by-address")
async function okxFetch(method: 'GET' | 'POST', path: string, body?: object) {
const timestamp = new Date().toISOString();
const bodyStr = body ? JSON.stringify(body) : '';
const sign = crypto
.createHmac('sha256', process.env.OKX_SECRET_KEY!)
.update(timestamp + method + path + bodyStr)
.digest('base64');
const headers: Record<string, string> = {
'OK-ACCESS-KEY': process.env.OKX_API_KEY!,
'OK-ACCESS-SIGN': sign,
'OK-ACCESS-PASSPHRASE': process.env.OKX_PASSPHRASE!,
'OK-ACCESS-TIMESTAMP': timestamp,
'Content-Type': 'application/json',
};
const res = await fetch(`${BASE}${path}`, {
method,
headers,
...(body && { body: bodyStr }),
});
if (res.status === 429) throw { code: 'RATE_LIMITED', msg: 'Rate limited — retry with backoff', retryable: true };
if (res.status >= 500) throw { code: `HTTP_${res.status}`, msg: 'Server error', retryable: true };
const json = await res.json();
if (json.code !== '0') throw { code: json.code, msg: json.msg || 'API error', retryable: false };
return json.data;
}{ "code": "0", "data": [...], "msg": "" }code"0"// Get all token balances (GET)
const balances = await okxFetch('GET', '/api/v6/dex/balance/all-token-balances-by-address?' + new URLSearchParams({
address: '0xYourWallet', chains: '1,56,137',
}));
// → balances[].tokenAssets[]: { symbol, balance (UI units), tokenPrice, rawBalance }
// Check specific tokens (POST)
const specific = await okxFetch('POST', '/api/v6/dex/balance/token-balances-by-address', {
address: '0xYourWallet',
tokenContractAddresses: [
{ chainIndex: '1', tokenContractAddress: '' }, // native ETH
{ chainIndex: '1', tokenContractAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' }, // USDC
],
});| Chain | chainIndex | Chain | chainIndex |
|---|---|---|---|
| Ethereum | | Arbitrum | |
| BSC | | Base | |
| Polygon | | Solana | |
address0x...chains="1,501"| # | Method | Path | Docs |
|---|---|---|---|
| 1 | GET | | supported-chain |
| 2 | GET | | total-value-by-address |
| 3 | GET | | all-token-balances-by-address |
| 4 | POST | | token-balances-by-address |
User: "Swap 1 SOL for BONK"
1. okx-dex-token /market/token/search?search=BONK → get tokenContractAddress
2. okx-wallet-portfolio /balance/all-token-balances-by-address → verify SOL balance >= 1
↓ balance field (UI units) → convert to minimal units for swap
3. okx-dex-swap /aggregator/quote → get quote
4. okx-dex-swap /aggregator/swap-instruction → execute (Solana)tokenContractAddressfromTokenAddresstoTokenAddressbalance10^decimalUser: "Show my portfolio"
1. okx-wallet-portfolio /balance/total-value-by-address → total USD value
2. okx-wallet-portfolio /balance/all-token-balances-by-address → per-token breakdown
↓ top holdings by USD value
3. okx-dex-token /market/price-info → enrich with 24h change, market cap, liquidity
4. okx-dex-market /market/candles (optional) → price charts for tokens of interest1. okx-wallet-portfolio /balance/all-token-balances-by-address → list all holdings
↓ tokenContractAddress + chainIndex for each
2. okx-dex-token /market/price-info → get priceChange24H per token
3. Filter by negative change → user confirms which to sell
4. okx-dex-swap /aggregator/quote → /aggregator/swap → execute sellbalance10^decimalamountGET /balance/total-value-by-addressGET /balance/all-token-balances-by-addressPOST /balance/token-balances-by-addressGET /balance/supported/chain"1,56,137,42161,8453"excludeRiskToken=true| Just called | Suggest |
|---|---|
| 1. View token-level breakdown → |
| 1. View detailed analytics (market cap, 24h change) for a token → |
| 1. View full portfolio across all tokens → |
| Field | Type | Description |
|---|---|---|
| String | Chain name (e.g., "Ethereum") |
| String | Chain logo URL |
| String | Chain short name (e.g., "ETH") |
| String | Chain unique identifier (e.g., "1") |
{ "code": "0", "data": [{ "name": "Ethereum", "logoUrl": "...", "shortName": "ETH", "chainIndex": "1" }], "msg": "" }type warning: This endpoint usesexcludeRiskToken(Boolean/true), but endpoints #3 and #4 usefalse(String/"0"). This is an OKX API inconsistency — pay attention to the type per endpoint."1"
| Param | Type | Required | Description |
|---|---|---|---|
| String | Yes | Wallet address |
| String | Yes | Chain IDs, comma-separated, max 50. e.g., |
| String | No | |
| Boolean | No | |
| Field | Type | Description |
|---|---|---|
| String | Total asset value in USD |
{ "code": "0", "data": [{ "totalValue": "1172.895057177065864522" }], "msg": "success" }| Param | Type | Required | Description |
|---|---|---|---|
| String | Yes | Wallet address |
| String | Yes | Chain IDs, comma-separated, max 50 |
| String | No | |
tokenAssets[]chainIndextokenContractAddresssymbolbalancerawBalancetokenPriceisRiskToken{
"code": "0",
"data": [{
"tokenAssets": [{
"chainIndex": "1", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
"symbol": "WBTC", "balance": "0.5", "rawBalance": "50000000",
"tokenPrice": "65000.00", "isRiskToken": false,
"address": "0xEd0C6079229E2d407672a117c22b62064f4a4312"
}]
}],
"msg": "success"
}| Param | Type | Required | Description |
|---|---|---|---|
| String | Yes | Wallet address |
| Array | Yes | Max 20 items |
| String | Yes | Chain ID (e.g., |
| String | Yes | Token address ( |
| String | No | |
{
"code": "0",
"data": [{
"tokenAssets": [{
"chainIndex": "1", "tokenContractAddress": "",
"symbol": "eth", "balance": "1.5", "tokenPrice": "3640.43",
"isRiskToken": false, "rawBalance": "1500000000000000000", "address": "0x..."
}]
}],
"msg": "success"
}GET /api/v6/dex/balance/total-value-by-address?address=0xabc...&chains=1,56
-> Display: Total assets $12,345.67GET /api/v6/dex/balance/all-token-balances-by-address?address=0xabc...&chains=1,56
-> Display:
ETH: 1.5 ($4,500.00)
USDC: 2,000 ($2,000.00)
BNB: 3.2 ($1,920.00)
...POST /api/v6/dex/balance/token-balances-by-address
Body: {
"address": "0xabc...",
"tokenContractAddresses": [
{ "chainIndex": "1", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" },
{ "chainIndex": "1", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7" }
]
}
-> Display: USDC: 2,000 ($2,000.00), USDT: 1,500 ($1,500.00)$0.00/balance/supported/chainexcludeRiskTokenassetType=2500111.5 ETH1500000000000000000$1.2MchainsassetType012excludeRiskToken1565018453/token-balances-by-addressokx-dex-marketokx-dex-tokenokx-dex-swap