# useTokenMetadata

URL: https://docs.blux.cc/react/hooks/use-token-metadata

Read a SEP-41 token / Stellar Asset Contract's metadata in React, powered by TanStack Query.

`useTokenMetadata` is the React wrapper around [`getTokenMetadata`](/javascript/core/getTokenMetadata). It reads a SEP-41 token / Stellar Asset Contract's `decimals`, `name`, `symbol`, and `owner` by simulating the contract's read-only entrypoints — **no account, signing, or fees** — and exposes the result as a TanStack Query, so you get caching, refetching, and loading states for free.

The read works for a `C…` contract id or `.xlm`/SEP-2 name resolving to one.
`owner` is `undefined` for contracts without an `owner()` function (notably
Stellar Asset Contracts, which expose `admin()` instead). The query stays
**disabled until a non-empty `address`** is provided, which makes it easy to
chain after [`useSacAddress`](/react/hooks/use-sac-address). Invalid or
unregistered names surface through `error`; see [address resolution](/javascript/core/address-resolution).

## Import
```tsx
```

## Usage

Read a token contract directly:

<Tabs items={['index.tsx', 'config.ts']} defaultIndex={0}>
<Tab value="index.tsx">
```tsx

function TokenInfo() {
  const { data, isLoading, error } = useTokenMetadata(
    "token.xlm",
  );

  if (isLoading) return <p>Loading…</p>;
  if (error) return <p>{error.message}</p>;

  // data → { decimals: 7, name: "USD Coin", symbol: "USDC", owner?: "G…" }
  return <p>{data?.name} ({data?.symbol})</p>;
}
```
</Tab>
<Tab value="config.ts">
```tsx
root.render(
  <BluxProvider
    config={{
      appName: "MyApp",
      networks: [networks.testnet, networks.mainnet],
    }}
  >
    <App />
  </BluxProvider>
);
```
</Tab>
</Tabs>

### Derive a classic asset's SAC, then read it

Pair it with [`useSacAddress`](/react/hooks/use-sac-address) to read a classic asset's metadata. Keep the query disabled until the SAC id is known:

<Tabs items={['index.tsx', 'config.ts']} defaultIndex={0}>
<Tab value="index.tsx">
```tsx

function ClassicAsset() {
  const { data: sac } = useSacAddress("USDC:GA5Z....KZVN");
  const { data: meta } = useTokenMetadata(sac ?? "", undefined, {
    enabled: Boolean(sac),
  });

  return <p>{meta?.symbol} · {meta?.decimals} decimals</p>;
}
```
</Tab>
<Tab value="config.ts">
```tsx
root.render(
  <BluxProvider
    config={{
      appName: "MyApp",
      networks: [networks.testnet, networks.mainnet],
    }}
  >
    <App />
  </BluxProvider>
);
```
</Tab>
</Tabs>

You can pass core options (currently just `network`) and TanStack Query options as the second and third arguments:

```tsx

const { data } = useTokenMetadata(
  "CB64...N7OG",
  { network: networks.mainnet },        // core options
  { enabled: true, staleTime: 60000 },  // TanStack options
);
```

<Callout type="info">
  Always pass the address first, then core options, then TanStack Query options. The hook relies on this order to work correctly.
</Callout>

## Parameters

### `address` (required)
`string`

The token contract id (`C…`), e.g. a SAC from [`useSacAddress`](/react/hooks/use-sac-address) / [`getSacAddress`](/javascript/core/getSacAddress). The query is disabled while this is empty.

### `network`
`string | undefined`

Passed as `{ network }` in the second argument. The network to read from. Import `networks` from `@bluxcc/react` to select one. Omit to use the active network.

## Query Options

These are passed as the third argument and map directly to TanStack Query options.

| Option | Type | Default | Description |
|---|---|---|---|
| `enabled` | `boolean` | `true` | Set to `false` to disable automatic fetching. Also auto-disabled while `address` is empty. |
| `staleTime` | `number \| Infinity` | `0` | Time in ms before data is considered stale |
| `gcTime` | `number \| Infinity` | `300000` | Time in ms before inactive cache data is garbage collected |
| `retry` | `boolean \| number` | `3` | How many times to retry on failure |
| `retryDelay` | `number \| function` | — | Delay in ms between retry attempts |
| `refetchInterval` | `number \| false \| function` | — | Continuously refetch at this interval in ms |
| `refetchOnMount` | `boolean \| 'always'` | `true` | Refetch on component mount if data is stale |
| `refetchOnWindowFocus` | `boolean \| 'always'` | `true` | Refetch when the window regains focus |
| `refetchOnReconnect` | `boolean \| 'always'` | `true` | Refetch when network reconnects |
| `refetchIntervalInBackground` | `boolean` | — | Keep refetching even when tab is in background |
| `placeholderData` | `TokenMetadata \| function` | — | Placeholder data shown while query is pending (not persisted to cache) |
| `initialData` | `TokenMetadata \| function` | — | Initial data for the cache (persisted) |
| `initialDataUpdatedAt` | `number \| function` | — | Timestamp of when `initialData` was last updated |
| `select` | `function` | — | Transform or select a subset of the returned data |
| `notifyOnChangeProps` | `string[] \| 'all'` | — | Limit re-renders to specific property changes |
| `structuralSharing` | `boolean \| function` | `true` | Retain references from old data for performance |
| `networkMode` | `'online' \| 'always' \| 'offlineFirst'` | `'online'` | Controls when queries can run relative to network status |
| `meta` | `Record<string, unknown>` | — | Attach arbitrary metadata to the query cache entry |
| `queryClient` | `QueryClient` | — | Use a custom QueryClient instead of the nearest context one |

## Return Type

### `data`
`TokenMetadata | undefined`
```tsx
type TokenMetadata = {
  decimals: number;     // number of decimal places the token uses
  name: string;         // human-readable token name
  symbol: string;       // token symbol / code
  owner?: string;       // owner() when present; undefined for a SAC
};
```

### Status Booleans

| Property | Type | Description |
|---|---|---|
| `isPending` | `boolean` | No cached data and no completed fetch yet |
| `isSuccess` | `boolean` | Query resolved successfully |
| `isError` | `boolean` | Query failed |
| `isLoading` | `boolean` | First fetch in-flight (`isFetching && isPending`) |
| `isFetching` | `boolean` | Query function is currently executing |
| `isRefetching` | `boolean` | Background refetch in progress |
| `isFetched` | `boolean` | Query has been fetched at least once |
| `isFetchedAfterMount` | `boolean` | Query fetched after component mounted |
| `isStale` | `boolean` | Cached data is stale or older than `staleTime` |
| `isPlaceholderData` | `boolean` | Currently showing placeholder data |
| `isLoadingError` | `boolean` | Failed on the first fetch |
| `isRefetchError` | `boolean` | Failed during a background refetch |
| `isPaused` | `boolean` | Query wanted to fetch but was paused |

### Other Returns

| Property | Type | Description |
|---|---|---|
| `status` | `'pending' \| 'success' \| 'error'` | Current query status |
| `fetchStatus` | `'fetching' \| 'idle' \| 'paused'` | Current fetch status |
| `error` | `null \| Error` | Error object if the query failed |
| `dataUpdatedAt` | `number` | Timestamp of last successful fetch |
| `errorUpdatedAt` | `number` | Timestamp of last error |
| `errorUpdateCount` | `number` | Total number of errors |
| `failureCount` | `number` | Failures since last success |
| `failureReason` | `null \| Error` | Reason for last retry failure |
| `refetch` | `function` | Manually trigger a refetch |

<Callout type="info">
  This is a read-only simulation, so the user does not need to be connected. See [`getTokenMetadata`](/javascript/core/getTokenMetadata#errors) for the `BLUX:` errors that surface on `error`.
</Callout>