Starknet-native, Cairo-based oracle that leverages provable computation to make price aggregation and TWAP fully trustless on-chain. Provides Spot, Perp/Future, and Generic data types; expanding to other zk-VMs as a 'network of zk-truth machines'.
- 01Starknet DeFi (perps, lending, AMMs)
- 02provable on-chain TWAP / VWAP / median computation
- 03Cairo-native data feeds without trusting an off-chain aggregator
- 04Madara appchains and other Cairo / zk-VM deployments
- 05publisher-signed data with on-chain aggregation
- scarb add pragma_lib
- pnpm add @pragmaoracle/sdk
| Variable | Scope | Description |
|---|---|---|
| PRAGMA_ORACLE_ADDRESS | Client | Pragma Oracle contract address on the target Starknet network (mainnet vs Sepolia differ). See docs.pragma.build/starknet/resources/contracts. |
In Cairo, add `pragma_lib` to `Scarb.toml` and import `use pragma_lib::abi::{IPragmaABIDispatcher, IPragmaABIDispatcherTrait}` plus `use pragma_lib::types::{DataType, PragmaPricesResponse, AggregationMode}`. Build the dispatcher with `IPragmaABIDispatcher { contract_address: PRAGMA_ORACLE_ADDRESS }` then call `let response: PragmaPricesResponse = dispatcher.get_data_median(DataType::SpotEntry(asset_id))` — `response.price` is `u128`, `response.decimals` is `u32`, `response.last_updated_timestamp` is the publisher timestamp, and `response.num_sources_aggregated` is the median's sample count. For TWAP use `dispatcher.calculate_twap(DataType::SpotEntry(asset_id), AggregationMode::Median, duration, start_time)`. Asset IDs are felt252 hashes of the symbol (e.g. `'BTC/USD'`).
- ⚑Decimal scaling: `response.decimals` is per-asset (typically 8 for crypto, 18 for stablecoins); HARDCODING 18 in arithmetic produces silent off-by-1e10 errors when consuming non-stablecoin pairs.
- ⚑Always staleness-check `response.last_updated_timestamp` against `starknet::get_block_timestamp()` — Pragma is push-based with publisher-driven heartbeats, so a quiet asset can have a multi-minute-old median that still passes naive sanity checks.
- ⚑Always validate `response.num_sources_aggregated >= MIN_SOURCES` (recommend `>= 3`) — a single-source median is one publisher away from manipulation; the dispatcher does NOT enforce a minimum on your behalf.
- ⚑Asset ID encoding: `DataType::SpotEntry(asset_id)` expects a felt252 of the EXACT symbol (e.g. `'ETH/USD'`, all caps with slash) — passing `'eth/usd'` or `'ETH-USD'` returns an empty / zero entry, not an error.
- ⚑Network fees: reads are free (just Starknet gas) but Starknet's gas accounting differs from EVM — TWAP calls iterate historical entries and can be expensive; cache results when reading the same window repeatedly.
- ⚑Mainnet vs Sepolia have different oracle addresses, different publisher sets, and different feed coverage — never reuse a Sepolia address on mainnet.
- ⚑Pragma is Starknet/Cairo-native; the EVM and Solana ecosystems use different Pragma deployments (zk-VM expansion is in progress) — verify chain support before assuming portability.
- ⚑TWAP windows that exceed the on-chain checkpoint history revert; check the feed's available history depth at docs.pragma.build before requesting a long duration.