Skip to content

Repository files navigation

Pyth Oracle Guard for Stacks sBTC Vaults

A small, open-source Clarinet/Vitest test kit for testing the consumer side of Pyth-style BTC/USD oracle data in Stacks DeFi contracts. It ships a deliberately unsafe sample sBTC vault that omits common oracle checks, a fixed vault that adds them, mock price fixtures, and a reusable test suite that fails against the unsafe contract and passes against the fixed one.

The value here is not "how to read a price feed." It is what your contract must do after it reads one — reject stale prices, reject zero/invalid prices, scale by the reported exponent, and bound the confidence interval — and a way to test that behaviour locally.

What this is — and is not

This is a consumer-side oracle test kit: reusable fixtures and tests for common oracle-consumer failure cases, demonstrated on one sample sBTC collateral/vault flow.

This is not a new oracle, a replacement for Pyth or Clarinet, a security audit, formal verification, or a DeFi protocol. See docs/non-goals.md.

The six checks

# Check Unsafe vault Fixed vault
1 Stale price (now - publish-time <= MAX-AGE) ignores age ERR-STALE (u300)
2 Missing freshness / max-age no max-age at all enforces MAX-AGE (1h)
3 Zero / invalid price (price > 0) uses it ERR-INVALID-PRICE (u301)
4 Exponent / decimal scaling assumes expo -8, mis-scales scales by 10^expo
5 Confidence bound (conf/price) ignores conf ERR-CONF-TOO-WIDE (u302)
6 Collateral-ratio edge case "healthy" on unsafe data holds only on a valid, scaled price

Quick start

npm install
npm test            # default target: fixed-sbtc-vault  -> all pass (14 tests)
npm run test:unsafe # target: unsafe-sbtc-vault          -> oracle checks fail (the demo)
clarinet check      # type-check all contracts

The unsafe → fail / fixed → pass output is captured in docs/demo-output.md.

How it works

The vaults read a Pyth-style price from a mock oracle contract via contract-call?, the same pattern a real consumer uses:

fixture JSON ─► Vitest test ─► mock-pyth.clar ─► (un)safe-sbtc-vault.clar ─► assert

Fixtures (fixtures/btc-usd.*.json) carry real Pyth-shaped price / conf / expo plus an ageSeconds freshness knob; the test helper publishes them as publish-time = now - ageSeconds, so staleness is deterministic.

Layout

contracts/
  mock-pyth.clar              test-only Pyth-style BTC/USD price store
  unsafe-sbtc-vault.clar      consumer without the safety checks
  fixed-sbtc-vault.clar       consumer with the safety checks
fixtures/                     valid / stale / zero / bad-exponent / high-confidence
tests/
  support/                    fixtures, oracle, vault, and the reusable guard suite
  oracle-guard.test.ts        guard suite entry (GUARD_TARGET-selectable)
  unsafe-demo.test.ts         documents the unsafe vault's flaws
  mock-pyth.test.ts           mock oracle round-trip
docs/
  non-goals.md
  integration-guide.md
  demo-output.md

Adapt it to your own contract

See docs/integration-guide.md for swapping the mock oracle for a real Pyth-on-Stacks source and reusing the Oracle Guard expectations against your own consuming contract.

Requirements

Node.js 20+, npm, and Clarinet 3.x. Tests run in-process via @stacks/clarinet-sdk and Vitest; clarinet check (the CLI) type-checks the contracts.

About

Pyth Oracle Guard for Stacks sBTC Vaults is a small open-source Clarinet/Vitest test kit that helps Stacks DeFi builders test common oracle-consumer failure cases before deploying contracts that depend on BTC/USD price data.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages