Developers

Balance endpoint

stridge.balance has one method. It returns a wallet's on-chain holdings — broken down per chain, including the native asset on each chain plus every ERC-20 the upstream feed knows about. Authenticated; goes through projectHttpClient.

MethodHTTPAuthReturns
balance.onchainGET /balance/onchain/{wallet_address}projectKey requiredOnchainBalanceResponse

balance.onchain

Returns the wallet's holdings, grouped by chain. Backed by the upstream Moralis token-balances feed; the Stridge proxy aggregates per-chain subtotals and a total_usd so callers don't need to roll their own math.

Signature

balance.onchain(
  walletAddress: string,
  options?: OnchainOptions,
): Promise<OnchainBalanceResponse>

interface OnchainOptions {
  /** Comma-separated chain filter. Accepts eip155 ids, slip44 ids, network names, or moralis slugs. */
  chains?: string

  /** Include tokens with zero balance. Default false. */
  includeZero?: boolean

  /** Include tokens flagged as spam by the upstream feed. Default false. */
  includeSpam?: boolean

  /** Minimum per-token USD value to include, decimal-string-encoded. Default "0". */
  minUsd?: string

  signal?: AbortSignal
}

walletAddress is treated as opaque — pass a 0x… EVM address for any EIP-155 chain or a Tron address for Tron-family chains. The gateway resolves the right upstream feed per chain.

Example — single call

const balance = await stridge.balance.onchain(walletAddress)

console.log(`${balance.wallet_address} — total $${balance.total_usd}`)
for (const chain of balance.chains) {
  console.log(`  ${chain.label}: $${chain.subtotal_usd}`)
  for (const token of chain.tokens) {
    console.log(`    ${token.symbol}  ${token.amount}  ($${token.amount_usd})`)
  }
}

Example — filtered

// Only Arbitrum + Base, hide tokens worth < $1, hide spam, hide zero balances.
const balance = await stridge.balance.onchain(walletAddress, {
  chains: "arbitrum,base",
  includeZero: false,
  includeSpam: false,
  minUsd: "1",
})

The filter is applied server-side — the response only carries the rows that survived. The chains field is forwarded verbatim to the upstream feed; the SDK doesn't parse or normalize the value.

Response shape

interface OnchainBalanceResponse {
  wallet_address: string             // lowercased server-side for 0x… values
  fetched_at: string                 // ISO-8601 of the most recent upstream pull
  total_usd: string                  // sum of chains[].subtotal_usd, decimal string
  chains: OnchainChainDto[]
}

interface OnchainChainDto {
  eip155_id: number                  // chain id (numeric)
  stridge_network_id: string         // stable Stridge id, e.g. "60" for Ethereum
  network_name: string               // slug, e.g. "ethereum"
  label: string                      // display, e.g. "Ethereum"
  scanner_url: string                // upstream block-explorer URL for the wallet
  native_symbol: string              // gas-token ticker, e.g. "ETH"
  subtotal_usd: string               // sum of tokens[].amount_usd on this chain
  tokens: OnchainTokenDto[]
}

interface OnchainTokenDto {
  token_address: string              // contract; empty string when is_native
  symbol: string                     // e.g. "USDC"
  name: string                       // display name
  decimals: number
  logo: string
  is_native: boolean
  is_spam: boolean                   // upstream-flagged spam — drivers skip in user-facing surfaces
  raw_amount: string                 // smallest-unit, string-encoded for precision
  amount: string                     // human-readable decimal string
  amount_usd: string                 // USD value of amount; may be "0" for unpriced tokens
  usd_price: string                  // per-unit USD price
  price_change_24h_pct: string       // 24h percentage change of usd_price
}

Every numeric amount is decimal-string-encoded so values exceeding 2^53 keep precision through JSON.parse. BigInt(raw_amount) is safe for on-chain math. For display, format the decimal string with a precision-preserving library — dnum, Decimal.js, big.js — instead of Number(amount). The Number() coercion silently rounds anything past ~15 significant digits, which is fine for casual UI but bites on full-precision balances, fees, or per-unit prices.

See Models & types for the canonical type imports.

Spam vs routability

The upstream feed flags some tokens as spam, and the SDK forwards that flag through OnchainTokenDto.is_spam. The feed doesn't catch every case, though — some airdropped tokens fabricate a usd_price to bypass the spam heuristic. If you're driving a deposit picker, layer a routability filter on top by intersecting balance.onchain(...) against gateway.assets() — only show tokens the gateway can actually route.

const [{ chains }, { assets: routable }] = await Promise.all([
  stridge.balance.onchain(walletAddress),
  stridge.gateway.assets(),
])

const routableByNetwork = new Map(
  routable.map((c) => [c.network_id, new Set(c.assets.map((a) => a.address.toLowerCase()))]),
)

const depositable = chains.flatMap((chain) =>
  chain.tokens.filter((token) => {
    if (token.is_spam) return false
    const allowed = routableByNetwork.get(chain.stridge_network_id)
    if (!allowed) return false
    return token.is_native || allowed.has(token.token_address.toLowerCase())
  }),
)

Errors

balance.onchain is a thin proxy in front of an upstream feed, so transient BackendErrors are normal — upstream rate limits, RPC hiccups, occasional 5xx. Treat any BackendError with statusCode >= 500 as retryable with exponential backoff; surface 4xx errors to the caller as-is. See Errors & retries for the recommended retry pattern.

Was this page helpful?