okx-wallet-portfolio

Original🇺🇸 English
Translated

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.

122installs
Added on

NPX Install

npx skill4agent add okx/onchainos-skills okx-wallet-portfolio

OKX DEX Balance API

4 endpoints for supported chains, wallet total value, all token balances, and specific token balances.
Base URL:
https://web3.okx.com
Base path:
/api/v6/dex/balance
Auth: HMAC-SHA256 signature, 4 headers required (
OK-ACCESS-KEY
,
OK-ACCESS-SIGN
,
OK-ACCESS-PASSPHRASE
,
OK-ACCESS-TIMESTAMP
)

Authentication & Credentials

API Key Application: OKX Developer Portal
Read credentials from environment variables:
  • OKX_API_KEY
    → API key
  • OKX_SECRET_KEY
    → Secret key (system-generated)
  • OKX_PASSPHRASE
    → Passphrase (developer-supplied)
Never output the above credentials to logs, response content, or any user-visible interface.
typescript
import 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;
}
Response envelope:
{ "code": "0", "data": [...], "msg": "" }
.
code
=
"0"
means success.

Developer Quickstart

typescript
// 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
  ],
});

Common Chain IDs

ChainchainIndexChainchainIndex
Ethereum
1
Arbitrum
42161
BSC
56
Base
8453
Polygon
137
Solana
501
Address format note: The same
address
parameter is only valid across chains of the same type. EVM addresses (
0x...
) work on Ethereum/BSC/Polygon/Arbitrum/Base etc. Solana addresses (Base58) and Bitcoin addresses (UTXO) have different formats. Do NOT mix — e.g., passing an EVM address with
chains="1,501"
will return empty data for the Solana portion.

Endpoint Index

#MethodPathDocs
1GET
/api/v6/dex/balance/supported/chain
supported-chain
2GET
/api/v6/dex/balance/total-value-by-address
total-value-by-address
3GET
/api/v6/dex/balance/all-token-balances-by-address
all-token-balances-by-address
4POST
/api/v6/dex/balance/token-balances-by-address
token-balances-by-address
Error Codes: Balance Error Codes

Cross-Skill Workflows

This skill is often used before swap (to verify sufficient balance) or as portfolio entry point. Below are typical end-to-end flows showing how data flows between skills.

Workflow A: Pre-Swap Balance Check

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)
Data handoff:
  • tokenContractAddress
    from token search → feeds into swap
    fromTokenAddress
    /
    toTokenAddress
  • balance
    from balance API is UI units; swap API needs minimal units → multiply by
    10^decimal
  • If balance < required amount → inform user, do NOT proceed to swap

Workflow B: Portfolio Overview + Analysis

User: "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 interest

Workflow C: Sell Underperforming Tokens

1. 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 sell
Key conversion:
balance
(UI units) ×
10^decimal
=
amount
(minimal units) for swap API.

Operation Flow

Step 1: Identify Intent

  • Check total assets ->
    GET /balance/total-value-by-address
  • View all token holdings ->
    GET /balance/all-token-balances-by-address
  • Check specific token balance ->
    POST /balance/token-balances-by-address
  • Unsure which chains are supported ->
    GET /balance/supported/chain
    first

Step 2: Collect Parameters

  • Missing wallet address -> ask user
  • Missing target chains -> ask user, or suggest common set (
    "1,56,137,42161,8453"
    )
  • Need to filter risky tokens -> set
    excludeRiskToken=true
    (only works on ETH/BSC/SOL/BASE)

Step 3: Call and Display

  • Total value: display USD amount
  • Token balances: show token name, amount (UI units), USD value
  • Sort by USD value descending

Step 4: Suggest Next Steps

After displaying results, suggest 2-3 relevant follow-up actions based on the endpoint just called:
Just calledSuggest
/balance/total-value-by-address
1. View token-level breakdown →
/balance/all-token-balances-by-address
(this skill) 2. Check price trend for top holdings →
okx-dex-market
/balance/all-token-balances-by-address
1. View detailed analytics (market cap, 24h change) for a token →
okx-dex-token
2. Swap a token →
okx-dex-swap
3. View price chart for a token →
okx-dex-market
/balance/token-balances-by-address
1. View full portfolio across all tokens →
/balance/all-token-balances-by-address
(this skill) 2. Swap this token →
okx-dex-swap
Present conversationally, e.g.: "Would you like to see the price chart for your top holding, or swap any of these tokens?" — never expose skill names or endpoint paths to the user.

API Reference

1. GET /balance/supported/chain

No request parameters.
Response:
FieldTypeDescription
data[].name
StringChain name (e.g., "Ethereum")
data[].logoUrl
StringChain logo URL
data[].shortName
StringChain short name (e.g., "ETH")
data[].chainIndex
StringChain unique identifier (e.g., "1")
json
{ "code": "0", "data": [{ "name": "Ethereum", "logoUrl": "...", "shortName": "ETH", "chainIndex": "1" }], "msg": "" }

2. GET /balance/total-value-by-address

excludeRiskToken
type warning
: This endpoint uses
Boolean
(
true
/
false
), but endpoints #3 and #4 use
String
(
"0"
/
"1"
). This is an OKX API inconsistency — pay attention to the type per endpoint.
ParamTypeRequiredDescription
address
StringYesWallet address
chains
StringYesChain IDs, comma-separated, max 50. e.g.,
"1,56"
assetType
StringNo
0
=all (default),
1
=tokens only,
2
=DeFi only
excludeRiskToken
BooleanNo
true
=filter risky tokens (default),
false
=include. Only ETH/BSC/SOL/BASE
Response:
FieldTypeDescription
data[].totalValue
StringTotal asset value in USD
json
{ "code": "0", "data": [{ "totalValue": "1172.895057177065864522" }], "msg": "success" }

3. GET /balance/all-token-balances-by-address

ParamTypeRequiredDescription
address
StringYesWallet address
chains
StringYesChain IDs, comma-separated, max 50
excludeRiskToken
StringNo
0
=filter out (default),
1
=do not filter. Only ETH/BSC/SOL/BASE
Response key fields:
tokenAssets[]
chainIndex
,
tokenContractAddress
,
symbol
,
balance
(UI units),
rawBalance
(base units),
tokenPrice
(USD),
isRiskToken
. Full fields: see docs.
json
{
  "code": "0",
  "data": [{
    "tokenAssets": [{
      "chainIndex": "1", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
      "symbol": "WBTC", "balance": "0.5", "rawBalance": "50000000",
      "tokenPrice": "65000.00", "isRiskToken": false,
      "address": "0xEd0C6079229E2d407672a117c22b62064f4a4312"
    }]
  }],
  "msg": "success"
}

4. POST /balance/token-balances-by-address

ParamTypeRequiredDescription
address
StringYesWallet address
tokenContractAddresses
ArrayYesMax 20 items
tokenContractAddresses[].chainIndex
StringYesChain ID (e.g.,
"1"
)
tokenContractAddresses[].tokenContractAddress
StringYesToken address (
""
for native token)
excludeRiskToken
StringNo
0
=filter out (default),
1
=do not filter
Response: Same schema as endpoint #3.
json
{
  "code": "0",
  "data": [{
    "tokenAssets": [{
      "chainIndex": "1", "tokenContractAddress": "",
      "symbol": "eth", "balance": "1.5", "tokenPrice": "3640.43",
      "isRiskToken": false, "rawBalance": "1500000000000000000", "address": "0x..."
    }]
  }],
  "msg": "success"
}

Input / Output Examples

User says: "Check my wallet 0xABC... total assets on Ethereum and BSC"
GET /api/v6/dex/balance/total-value-by-address?address=0xabc...&chains=1,56
-> Display: Total assets $12,345.67
User says: "Show all tokens in my wallet"
GET /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)
  ...
User says: "Only check USDC and USDT balances"
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)

Edge Cases

  • Zero balance: valid state — display
    $0.00
    , not an error
  • Unsupported chain: call
    /balance/supported/chain
    first to confirm
  • chains exceeds 50: split into batches, max 50 per request
  • excludeRiskToken
    not working
    : only supported on ETH/BSC/SOL/BASE
  • DeFi positions: use
    assetType=2
    to query DeFi holdings separately
  • 429 rate limit: exponential backoff with jitter. See Rate Limit & Fee Docs for tier-specific RPS limits (Trial: 1 RPS, Start-up: 2-50 RPS, Enterprise: custom).
  • Cross-skill pipeline rate limit: when chaining calls across multiple skills (e.g., token search → balance → swap), add 300-500ms delay between requests to avoid triggering rate limit (error code
    50011
    ).
  • Network error: retry once
  • Request timeout: all API calls must set a 10-second timeout limit

Amount Display Rules

  • Token amounts in UI units (
    1.5 ETH
    ), never base units (
    1500000000000000000
    )
  • USD values with 2 decimal places
  • Large amounts in shorthand (
    $1.2M
    )
  • Sort by USD value descending

Global Notes

  • chains
    supports up to 50 chain IDs (comma-separated strings)
  • assetType
    :
    0
    =all
    1
    =tokens only
    2
    =DeFi only
  • excludeRiskToken
    only works on ETH(
    1
    )/BSC(
    56
    )/SOL(
    501
    )/BASE(
    8453
    )
  • /token-balances-by-address
    is the only POST endpoint in this family
  • Total value is returned as a USD string — handle type conversion
  • For token prices / K-lines -> use
    okx-dex-market
  • For token search / metadata -> use
    okx-dex-token
  • For swap execution -> use
    okx-dex-swap