> For the complete documentation index, see [llms.txt](https://docs.onre.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.onre.finance/technical-resources/onchain-market-data.md).

# Onchain Market Data

ONyc market data is published on-chain through the `MarketStats` PDA. It provides the current NAV, APY, circulating supply, NAV adjustment, TVL, and freshness metadata.

Integrations that need ONyc accounting data can read `MarketStats` directly without relying on the OnRe REST API or an oracle.

```mermaid
flowchart LR
    A[OnRe program state] --> B[MarketStats PDA]
    B --> C[Direct program integrations]
    B --> D[OnRe REST API]
    B --> E[Oracle publication layers]
    F[Secondary-market venues] --> G[Spot-price feeds]
```

### Market Data vs Spot Price

`MarketStats` and secondary-market price feeds serve different purposes. `MarketStats.nav` represents ONyc's program accounting value, while a spot-price feed reflects the price at which ONyc trades on a secondary market.

Risk systems may use both, but should treat them as separate inputs.

### Mainnet Reference

| Property              | Value                                                                                                   |
| --------------------- | ------------------------------------------------------------------------------------------------------- |
| Network               | Solana Mainnet                                                                                          |
| Program ID            | `onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe`                                                           |
| PDA seed              | `market_stats`                                                                                          |
| MarketStats PDA       | `BuPMet2URHuTVKSHpj32AjsXxHgdsqeA1i82dr1b4Mi5`                                                          |
| Account discriminator | `[240, 45, 182, 233, 92, 118, 209, 83]`                                                                 |
| IDL                   | [target/idl/onreapp.json](https://github.com/onre-finance/onre-sol/blob/master/target/idl/onreapp.json) |

For integrations that support multiple environments, derive the `MarketStats` address rather than hard-coding it:

```tsx
import { PublicKey } from "@solana/web3.js";

const ONRE_PROGRAM_ID = new PublicKey(
  "onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe"
);

const [marketStatsPda] = PublicKey.findProgramAddressSync(
  [Buffer.from("market_stats")],
  ONRE_PROGRAM_ID
);
```

### Account Layout

All integer fields in the raw account data use little-endian encoding.

| Field                | Type       | Scale and Meaning                                                                                              |
| -------------------- | ---------- | -------------------------------------------------------------------------------------------------------------- |
| `apy`                | `u64`      | Fixed point with scale `1_000_000 = 100%`. Divide by `1_000_000` for a ratio, or by `10_000` for a percentage. |
| `circulating_supply` | `u64`      | ONyc base units. ONyc has 9 decimals.                                                                          |
| `nav`                | `u64`      | USD NAV with 9 decimals. `1_000_000_000 = $1.00`.                                                              |
| `nav_adjustment`     | `i64`      | Signed NAV adjustment with the same 9-decimal price scale.                                                     |
| `tvl`                | `u64`      | `circulating_supply × nav / 1_000_000_000`, stored with 9 decimals.                                            |
| `last_updated_at`    | `i64`      | Unix timestamp of the last successful recomputation.                                                           |
| `last_updated_slot`  | `u64`      | Solana slot of the last successful recomputation.                                                              |
| `bump`               | `u8`       | PDA bump.                                                                                                      |
| `reserved`           | `[u8; 95]` | Reserved for forward-compatible expansion. Do not interpret.                                                   |

Keep raw values as `BN` or `bigint` until formatting, as ONyc supply and TVL can exceed JavaScript's safe integer range.

### Reading MarketStats

#### With Anchor

Use the IDL from the same release as the deployed program:

```tsx
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
import { Connection, PublicKey } from "@solana/web3.js";
import idl from "./onreapp.json";

const connection = new Connection(process.env.SOLANA_RPC_URL!);
const provider = new AnchorProvider(connection, wallet, {});
const program = new Program(idl, provider);

const [marketStatsPda] = PublicKey.findProgramAddressSync(
  [Buffer.from("market_stats")],
  program.programId
);

const stats = await program.account.marketStats.fetch(marketStatsPda);

const nav = stats.nav as BN;
const apy = stats.apy as BN;
const circulatingSupply = stats.circulatingSupply as BN;
const tvl = stats.tvl as BN;

console.log({
  navRaw: nav.toString(),
  apyRaw: apy.toString(),
  circulatingSupplyRaw: circulatingSupply.toString(),
  tvlRaw: tvl.toString(),
  lastUpdatedAt: stats.lastUpdatedAt.toString(),
  lastUpdatedSlot: stats.lastUpdatedSlot.toString(),
});
```

Depending on the Anchor client and generated types, decoded field names may remain `snake_case` rather than `camelCase`. Treat the release IDL as authoritative.

#### Without Anchor

When reading the account directly, validate the account owner and discriminator before decoding:

```tsx
import { Connection, PublicKey } from "@solana/web3.js";

const PROGRAM_ID = new PublicKey(
  "onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe"
);
const connection = new Connection(process.env.SOLANA_RPC_URL!);
const DISCRIMINATOR = Buffer.from([240, 45, 182, 233, 92, 118, 209, 83]);

const [marketStatsPda] = PublicKey.findProgramAddressSync(
  [Buffer.from("market_stats")],
  PROGRAM_ID
);

const account = await connection.getAccountInfo(marketStatsPda, "confirmed");
if (!account) throw new Error("MarketStats account not found");
if (!account.owner.equals(PROGRAM_ID)) throw new Error("Unexpected account owner");
if (!account.data.subarray(0, 8).equals(DISCRIMINATOR)) {
  throw new Error("Unexpected MarketStats discriminator");
}

const data = account.data;
const stats = {
  apy: data.readBigUInt64LE(8),
  circulatingSupply: data.readBigUInt64LE(16),
  nav: data.readBigUInt64LE(24),
  navAdjustment: data.readBigInt64LE(32),
  tvl: data.readBigUInt64LE(40),
  lastUpdatedAt: data.readBigInt64LE(48),
  lastUpdatedSlot: data.readBigUInt64LE(56),
  bump: data.readUInt8(64),
};
```

### Formatting Fixed-Point Values

Avoid converting raw values to JavaScript `number`. Format fixed-point values directly from `bigint`:

```tsx
function formatFixed(value: bigint, decimals: number): string {
  const negative = value < 0n;
  const absolute = negative ? -value : value;
  const scale = 10n ** BigInt(decimals);
  const whole = absolute / scale;
  const fraction = (absolute % scale)
    .toString()
    .padStart(decimals, "0")
    .replace(/0+$/, "");

  return `${negative ? "-" : ""}${whole}${fraction ? `.${fraction}` : ""}`;
}

const navUsd = formatFixed(stats.nav, 9);
const apyPercent = formatFixed(stats.apy, 4); // 115411 -> 11.5411%
const supplyOnyc = formatFixed(stats.circulatingSupply, 9);
const tvlUsd = formatFixed(stats.tvl, 9);
```

### Freshness

`MarketStats` is a cached on-chain snapshot rather than a streaming feed. Protocol activity refreshes the account, and any signer can call `refresh_market_stats` when a newer snapshot is required.

Consumers should:

1. Read `last_updated_at` or `last_updated_slot` alongside the market data.
2. Apply a freshness threshold appropriate to the integration.
3. Reject, warn, or refresh when the snapshot exceeds that threshold.

Freshness requirements should reflect the use case. A user interface, lending market, and liquidation engine may require different thresholds.

### Permissionless Refresh

`refresh_market_stats` can be called by any signer. The signer pays the transaction fee and, if the PDA has not yet been created in that environment, the associated rent.

The instruction recomputes `MarketStats` using `state.main_offer`, the canonical ONyc mint, and the cached circulating-supply exclusion balance.

```tsx
import { SystemProgram } from "@solana/web3.js";

await program.methods
  .refreshMarketStats()
  .accounts({
    mainOffer,
    tokenInMint,
    state,
    onycMint,
    circulatingSupplyExcludedBalance,
    marketStats: marketStatsPda,
    signer: wallet.publicKey,
    systemProgram: SystemProgram.programId,
  })
  .rpc();
```

`main_offer` must match `state.main_offer`, and its output mint must be the canonical ONyc mint.

### Read-only Views

The program also exposes read-only views:

* `get_nav`
* `get_apy`
* `get_nav_adjustment`
* `get_tvl_v2`
* `get_circulating_supply_v2`

For integrations that need the full market state, a single `MarketStats` fetch is simpler and keeps all values internally consistent. Read-only views are useful when a single value is needed during transaction construction or should be recomputed from supplied accounts.

**Legacy:** New integrations should use `get_tvl_v2` and `get_circulating_supply_v2` rather than `get_tvl` or `get_circulating_supply`. The legacy instructions use the pre-v5 supply-exclusion path.

### Emergency Stop Behavior

The global kill switch pauses guarded value-moving instructions but does not affect access to `MarketStats`. Direct account reads and unguarded read-only views remain available.

Applications should continue displaying the latest available snapshot and its timestamp while indicating that execution is paused.

### REST APIs and Oracle Feeds

The OnRe REST API provides convenience endpoints for off-chain consumers:

* <https://core.api.onre.finance/data/live-nav>
* <https://core.api.onre.finance/data/live-apy>
* <https://core.api.onre.finance/data/live-tvl>

Oracle feeds can be used by protocols that standardize on an oracle interface or require secondary-market pricing. They provide distribution and market-observation layers rather than a separate source of ONyc accounting data.

### Integration Guidance

For new Solana integrations:

* Use `MarketStats` for NAV, APY, circulating supply, and TVL.
* Use an appropriate market feed when a tradable spot price is required.
* Define how the integration should behave when spot price and NAV diverge.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.onre.finance/technical-resources/onchain-market-data.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
