npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@titon-network/phoebe-sdk

v0.5.0

Published

TypeScript SDK for Phoebe — TON-native price oracle. One BLS_VERIFY + one cell-walk per pull, for any feed in a 256-feed BLS-aggregated Merkle snapshot. Verifier consumer of Atlas (group key) + ForgeTON (operator stake). Ships sandbox fixture, event decod

Downloads

110

Readme

@titon-network/phoebe-sdk

TypeScript SDK for Phoebe — TON's price oracle. One BLS_VERIFY + one cell-walk per pull, for any feed in a 256-feed BLS-aggregated Merkle snapshot. Verifier consumer of Atlas (group key) + ForgeTON (operator stake). Built on the TSA-audited @titon-network/atlas-sdk + @titon-network/forgeton-sdk.

npm version License: MIT

Audit status

🛡️ TSA-audited — zero findings. Full report: AUDIT.md.

| Layer | Result | |---|---| | TSA symbolic execution (8 checks: 3 standard + 3 single-contract custom + 2 inter-contract custom vs Atlas + ForgeTON) | 0 findings — every check returned empty SARIF | | Manual review against references/vulnerabilities.md | 52 / 52 confirmed defenses; no critical / high / medium / low / informational issues | | Contract test suite (pnpm run test) | 316 / 316 passing | | SDK test suite (pnpm run test:sdk) | 172 / 172 passing | | Cross-contract ABI byte-shape pin | tests/Integration.spec.ts + tests/SchemaEvolution.spec.ts green against real Atlas + ForgeTON SDK fixtures | | Pool-side foundation | Built on the TSA-audited @titon-network/forgeton-sdk and @titon-network/atlas-sdk — Phoebe inherits both zero-findings postures and adds no new economic-security layer. |

Live deployments: testnet (2026-05-13) and mainnet (2026-05-18, multi-op n=2). The SDK's PHOEBE_TESTNET + PHOEBE_MAINNET constants track the canonical addresses.

npm install @titon-network/phoebe-sdk @ton/core @ton/ton
# optional — pull these in only if you're sandbox-testing:
npm install --save-dev @ton/sandbox @titon-network/atlas-sdk @titon-network/forgeton-sdk

Connect — testnet vs mainnet (the only difference)

The SDK is network-agnostic. You pick the network in two lines: the TonClient endpoint and which deployment constant you import.

// ── testnet ──────────────────────────────────────────────────────────
import { TonClient } from '@ton/ton';
import { Phoebe, PHOEBE_TESTNET } from '@titon-network/phoebe-sdk';

const tonClient = new TonClient({
    endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});
const phoebe = tonClient.open(Phoebe.createFromAddress(PHOEBE_TESTNET.phoebe));

const cfg = await phoebe.getConfig();
console.log(`connected to testnet — pullFee ${cfg.pullFee} nano-TON`);

For mainnet, change exactly two lines:

// ── mainnet ──────────────────────────────────────────────────────────
import { TonClient } from '@ton/ton';
import { Phoebe, PHOEBE_MAINNET } from '@titon-network/phoebe-sdk';

const tonClient = new TonClient({
    endpoint: 'https://toncenter.com/api/v2/jsonRPC',                  // ← no `testnet.`
});
const phoebe = tonClient.open(
    Phoebe.createFromAddress(PHOEBE_MAINNET.phoebe),                   // ← was PHOEBE_TESTNET
);

That's it. The same npm package, same bytecode, same code paths work on either network — only the TonClient endpoint and the deployment constant change. Pointing at a custom deployment (your own fork, sandbox, a private chain) is just Phoebe.createFromAddress(Address.parse('EQ...')) — no constant required.

💡 Drift check. Call assertDeployment('mainnet') (or 'testnet') instead of dereferencing PHOEBE_MAINNET / PHOEBE_TESTNET directly — the helper throws an actionable error if the constant is null and exposes expectedCodeHash + expectedSchema so you can diff against the live contract's codeHash and getSchemaVersions().

30-second integration — pull a price

Phoebe is live. This block reads feed 42 directly from the deployed mainnet contract — copy, paste, run.

import { TonClient } from '@ton/ton';
import {
    Phoebe, PhoebeMerkleTree, PHOEBE_MAINNET, PHOEBE_DEFAULTS,
    estimatePullValue,
} from '@titon-network/phoebe-sdk';

const tonClient = new TonClient({
    endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});
const phoebe = tonClient.open(Phoebe.createFromAddress(PHOEBE_MAINNET.phoebe));

// 1. Receive the signed snapshot leaf from your operator / indexer.
const myLeaf = {
    feedId:   42,
    mantissa: 6_543_210n * 100_000_000n,    // $65,432.10
    expo:     -8,
    confBps:  50,
    pubTime:  Math.floor(Date.now() / 1000),
};

// 2. Build the Merkle proof off-chain (~417 B pruned-branch exotic cell).
const tree  = PhoebeMerkleTree.fromSparseLeaves(new Map([[42, myLeaf]]));
const proof = tree.proof(42);

// 3. RequestPrice — mode A (cached fast-path, ~16k gas).
await phoebe.sendRequestPrice(yourConsumerSender, {
    value:        estimatePullValue({ pullFee: PHOEBE_DEFAULTS.pullFee }),
    queryId:      1n,
    feedId:       42,
    proof,
    leaf:         myLeaf,
    maxStaleness: 0,                    // accept any cached snapshot
});

Phoebe verifies proof.hash() == lastRoot, walks the proof to slot 42, asserts the walked-leaf hash matches myLeaf.toCell().hash(), then sends FulfillPrice { queryId, leaf } to your consumer at opcode 0x72.

For the target consumer contract pattern (the receiver-safety banner

  • wire-shape discipline every Phoebe consumer must follow), see skills/phoebe-integrate-consumer.md or run npx phoebe scaffold consumer --out contracts/my-consumer.tolk to drop the canonical template into your project.

What this gives you

  • Phoebe contract wrapper — every send* + every get* mirroring the on-chain ABI
  • PhoebeMerkleTree — off-chain proof generator, byte-identical to the on-chain walker
  • BLS primitives (signMessage / aggregateSignatures / computeSnapshotHash) — operator-side signing helpers, with BLS_DST_G2_POP baked in (avoids the #1 cause of E_INVALID_BLS_SIGNATURE)
  • Event decoder (decodeEvent / decodeEvents) — typed PhoebeEvent discriminated union, switch on kind
  • Error explainer (explainError / PhoebeError) — every exit code → { origin, name, message, hint }
  • Bundled artifact (loadPhoebeCode) — no separate compile step
  • Sandbox testing (@titon-network/phoebe-sdk/testing subpath) — deployPhoebeFixture() stands up the full real-stack (Atlas + Phoebe + mock-ForgeTON + bootstrapped operator) in one call
  • CLI (npx phoebe) — explain, decode, hash, schema, estimate pull/push, scaffold consumer, deployments
  • Five persona-grouped agent skills under skills/ — load one per task

Quickstart — consumer

You're a TON dapp. You want to read a price.

1. Scaffold a consumer contract

npx phoebe scaffold consumer --out contracts/my-consumer.tolk

Customize handleFulfillPrice for your business logic. The template includes the canonical receiver-safety banner + wire-shape discipline.

2. Build a Merkle proof off-chain

You receive a signed snapshot from an operator (or your indexer). To pull feed 42:

import {
    PhoebeMerkleTree,
    estimatePullValue,
    PHOEBE_DEFAULTS,
} from '@titon-network/phoebe-sdk';

const myLeaf = {
    feedId:   42,
    mantissa: 6_543_210n * 100_000_000n,    // $65,432.10
    expo:     -8,
    confBps:  50,
    pubTime:  Math.floor(Date.now() / 1000),
};

// Build a tree containing your slots; the root must match what the
// operator signed.
const tree = PhoebeMerkleTree.fromSparseLeaves(new Map([[42, myLeaf]]));
// `tree.proof()` returns a pruned-branch merkle_proof exotic cell (~417 B
// per pull). Use `tree.fullTreeProof(feedId)` for the legacy ~8.5 KB
// full-tree shape if your tooling can't construct exotic cells.
const proof = tree.proof(42);

3. Send RequestPrice

import { Phoebe, newPhoebe, assertDeployment } from '@titon-network/phoebe-sdk';

// PHOEBE_TESTNET / PHOEBE_MAINNET resolve to canonical addresses where
// available; for sandbox testing or pre-mainnet use your own deployed
// Phoebe address.
const phoebe = tonClient.open(Phoebe.createFromAddress(myPhoebeAddr));

await phoebe.sendRequestPrice(myConsumerSender, {
    value:        estimatePullValue({ pullFee: PHOEBE_DEFAULTS.pullFee }),
    queryId:      1n,
    feedId:       42,
    proof,
    leaf:         myLeaf,
    maxStaleness: 0,    // accept any cached snapshot
});

Phoebe verifies proof.hash() == lastRoot, walks the proof to slot 42, asserts the walked-leaf hash matches myLeaf.toCell().hash(), then sends FulfillPrice { queryId, leaf } to your consumer at opcode 0x72.

4. Decode the callback in your consumer

import { parseFulfillPrice } from '@titon-network/phoebe-sdk';

// In your contract's receiver (or your wrapper's getter for the latest callback):
const { queryId, leaf } = parseFulfillPrice(rawCallbackBody);
console.log(`feed ${leaf.feedId}: ${leaf.mantissa}e${leaf.expo} (conf ±${leaf.confBps}bps)`);

Quickstart — sandbox tests

import { Blockchain } from '@ton/sandbox';
import { deployPhoebeFixture } from '@titon-network/phoebe-sdk/testing';

const blockchain = await Blockchain.create();
const fx = await deployPhoebeFixture(blockchain);
//   ↳ Deploys real Atlas + mock-ForgeTON + Phoebe, admits Phoebe at Atlas,
//     mirrors a solo operator. Ready for push + pull immediately.

const sampleLeaf = { feedId: 42, mantissa: 100n, expo: 0, confBps: 50,
                     pubTime: 2_000_000_000 };
const { tree } = await fx.pushSnapshot({ leaves: new Map([[42, sampleLeaf]]) });
const { result } = await fx.requestPrice({ tree, feedId: 42, leaf: sampleLeaf });

// Now assert on `result.transactions` to verify the FulfillPrice landed.

Full tutorial: skills/phoebe-integrate-consumer.md.


Quickstart — operator

You stake at ForgeTON, register a pkShare at Atlas, and push BLS-signed Merkle snapshots to Phoebe every ~30s.

import {
    PhoebeMerkleTree,
    computeSnapshotHash,
    signMessage,
    estimatePushValue,
    Phoebe,
} from '@titon-network/phoebe-sdk';

// 1. Build the snapshot tree from your latest aggregated prices
const tree = PhoebeMerkleTree.fromSparseLeaves(new Map([
    [0,  { feedId: 0,  ...btcPrice }],
    [1,  { feedId: 1,  ...ethPrice }],
    // ... up to 256 slots
]));

// 2. Sign (timestamp, root) with the operator's pkShare secret
const timestamp = Math.floor(Date.now() / 1000);
const root = tree.rootAsBigint();
const sigInput = computeSnapshotHash(phoebe.address, timestamp, root);
const aggSig = signMessage(operatorSk, sigInput);

// 3. Submit to Phoebe — `value` covers gas + slack; excess refunds.
const phoebe = tonClient.open(Phoebe.createFromAddress(myPhoebeAddr));
await phoebe.sendPushSnapshot(operatorSender, {
    value:     estimatePushValue(),     // 0.1 TON default
    timestamp,
    root,
    aggSig,
});

Full operator-setup playbook: skills/phoebe-operator-setup.md.


Quickstart — owner

Deploy + admit + tune.

import { newPhoebe } from '@titon-network/phoebe-sdk';

// 1. Deploy
const phoebe = tonClient.open(newPhoebe({
    owner:    ownerAddr,
    forgeton: forgetonAddr,
    atlas:    atlasAddr,
}));
await phoebe.sendDeploy(ownerSender, toNano('1'));

// 2. Atlas owner admits Phoebe as a verifier (triggers GroupKeySync bootstrap)
await atlas.sendSetVerifier(atlasOwnerSender, {
    value: toNano('0.5'),
    contract: phoebe.address,
    isActive: true,
});

// 3. ForgeTON owner admits Phoebe as a consumer (operators get mirrored)
await forgeton.sendSetConsumer(forgetonOwnerSender, {
    value: toNano('0.1'),
    contract: phoebe.address,
    isActive: true,
});

// 4. Tune over time
await phoebe.sendUpdateConfig(ownerSender, { value: toNano('0.05'), pullFee: toNano('0.02') });

// 5. Withdraw accumulated fees
await phoebe.sendWithdrawFees(ownerSender, { value: toNano('0.05'), to: treasuryAddr, amount: toNano('5') });

Full deploy + owner-ops playbooks: skills/phoebe-deploy.md + skills/phoebe-owner-ops.md.


Public surface

import {
    // Contract
    Phoebe, newPhoebe, PhoebeMerkleTree,
    PHOEBE_DEFAULTS, MIN_RESERVE_FLOOR, MIN_UPGRADE_DELAY, DEFAULT_MAX_PUSH_DRIFT,

    // Constants — opcodes, error codes, schema, BLS, protocol
    OP, ERR,
    PHOEBE_STORAGE_VERSION, PHOEBE_CONFIG_BLOB_VERSION,
    BLS_PUBKEY_BYTES, BLS_SIG_BYTES, BLS_DST_G2_POP,
    DEFAULT_GROUP_ID, MIN_UPGRADE_DELAY_SECONDS,
    MAX_FEED_COUNT, TREE_DEPTH, MAX_MAX_INACTIVITY_SECONDS,
    CAUSE_FIRST_SYNC, CAUSE_ACTIVATION_CHANGE,

    // BLS primitives
    randomBlsSecret, blsPublicKey, aggregateGroupPublicKey,
    signMessage, aggregateSignatures, computeSnapshotHash,

    // Wire-format codecs
    priceLeafToCell, priceLeafFromSlice, parseFulfillPrice,
    phoebeConfigToCell,

    // Events — typed union + per-event interfaces + decoders
    decodeEvent, decodeEvents, tryDecodeEvent,
    type PhoebeEvent, type EventKind,
    type SnapshotPushedEvent, type PricePulledEvent,
    type GroupKeyCachedEvent, type OperatorMirroredEvent,
    // ... and 8 more event types

    // Errors
    explainError, PhoebeError,
    type ErrorCode, type ErrorOrigin, type ErrorExplanation,

    // Diagnostics — collapse a `Transaction` for logging / tests
    summarizeTx, summarizeTxs, formatTxSummary,
    QueryIdStream, estimatePullValue, estimatePushValue,
    type TxSummary,

    // Compiled artifact
    loadPhoebeCode, loadPriceConsumerCode,
    phoebeCodeHash, priceConsumerCodeHash, PHOEBE_CODE_HASH,
    type CompiledArtifact,

    // Live deployment addresses
    PHOEBE_TESTNET, PHOEBE_MAINNET, PHOEBE_EXPECTED_SCHEMA, assertDeployment,
    type PhoebeDeployment,
} from '@titon-network/phoebe-sdk';
// Sandbox testing subpath — peer-deps @ton/sandbox + @titon-network/atlas-sdk
import {
    deployPhoebeFixture,
    type PhoebeFixture,
    type DeployPhoebeFixtureOpts,
    type FulfillPriceResult,
} from '@titon-network/phoebe-sdk/testing';

Full reference: AGENTS.md (the AI navigator).


CLI — one-off introspection

phoebe explain 161                    # describe an exit code
phoebe decode <hex|base64>            # decode an external-out event body
phoebe hash                           # bundled Phoebe code hash
phoebe schema                         # SDK-expected schema versions + BLS suite
phoebe estimate pull --pull-fee 0.01  # recommended RequestPrice value
phoebe estimate push                  # recommended PushSnapshot value
phoebe scaffold consumer              # drop a Tolk consumer template
phoebe init                           # write PHOEBE.md (agent context) into cwd
phoebe deployments                    # list known live Phoebe addresses
phoebe info <addr> --testnet          # pretty-print live state
phoebe verify --testnet               # drift check vs PHOEBE_TESTNET

Run with --json for machine-readable output.


AI-assistant integration

This SDK is AI-first. Every published doc is structured for direct LLM ingestion:

  • AGENTS.md — agent navigator: type map, opcode/error ranges, skill index
  • llms.txtllmstxt.org-format short context (single page)
  • llms-full.txt — full prose digest (multiple pages, deep dive)
  • ERRORS.md + OPCODES.md — flat tables for grep-friendly lookups
  • GUARANTEES.md — what the SDK guarantees vs. what's the consumer's responsibility
  • skills/ — five persona-grouped task playbooks (consumer / deploy / operator / owner / debug)

Drop them into your AI assistant's context window:

# Claude Code — write the agent context into the consumer repo
npx phoebe init
# → writes PHOEBE.md alongside your existing CLAUDE.md

Or load node_modules/@titon-network/phoebe-sdk/llms-full.txt directly into your chat.


Status

Phoebe contract is TSA static-analysis cleared, zero findings, audited at the same posture as Atlas / Fortuna / ForgeTON / Kronos. 316 contract tests + 172 SDK tests green. RequestPrice supports an optional freshUpdate field (Pyth-style "update + read" combined into one op): two operating modes — cached fast-path (~16k gas) for routine reads, fresh-update path (~73k gas) for sub-heartbeat freshness.

PHOEBE_TESTNET is populated (2026-05-13 deploy, solo operator, epoch 1, threshold 1/1). PHOEBE_MAINNET is populated (2026-05-18 bootstrap, multi-op n=2, epoch 1, threshold 2). Code-hash ba7893206a69524d845c7d7cd1406fec28c91dabcf91ba87505502f45d16f395. Use assertDeployment(network) to retrieve the canonical address + expected schema + code-hash for drift checks.


Versioning

This SDK follows SemVer. Breaking changes to the public surface bump the major; new features bump the minor; bug fixes bump the patch. The deployed contract's PHOEBE_STORAGE_VERSION + PHOEBE_CONFIG_BLOB_VERSION track the on-chain schema separately — assertDeployment(network) will surface drift between the two.


License

MIT © 2026 Titon Network