ddd-oracle-sdk
v0.1.1
Published
TypeScript SDK for reading the Digital Dollar Dominance (DDD) oracle on Solana
Maintainers
Readme
ddd-oracle-sdk
TypeScript SDK for reading the Digital Dollar Dominance (DDD) oracle on Solana.
The DDD oracle publishes the ratio of US-stablecoin TVL to US M2 money supply on Solana mainnet, along with detailed breakdowns by chain, issuer, and individual token. Updates land roughly every 30 minutes.
Developed by @snowplow1337
- Site: https://digitaldollardominance.com
- Program:
AbjVyP3WaY9yMG8AT8vNcLHcNoFkT5dwT94SPQ8kddd - Source data: DefiLlama stablecoins + FRED M2SL
Install
npm install ddd-oracle-sdk @solana/web3.js
# or
pnpm add ddd-oracle-sdk @solana/web3.js
# or
yarn add ddd-oracle-sdk @solana/web3.js@solana/web3.js is a peer dependency.
Quick start
import { Connection } from "@solana/web3.js";
import { readDDD } from "ddd-oracle-sdk";
const connection = new Connection("https://api.mainnet-beta.solana.com");
const summary = await readDDD(connection);
console.log(`DDD = ${summary.dddPercent.toFixed(4)}%`);
console.log(`Stables = $${(Number(summary.totalStablesUsd) / 1e9).toFixed(2)}B`);
console.log(`M2 = $${(Number(summary.m2Usd) / 1e12).toFixed(2)}T`);
console.log(`Updated ${new Date(Number(summary.timestamp) * 1000).toISOString()}`);Output:
DDD = 1.4138%
Stables = $320.49B
M2 = $22.67T
Updated 2026-04-18T17:28:32.000ZAPI
Headline read
import { readDDD } from "ddd-oracle-sdk";
const summary = await readDDD(connection);
summary.dddPercent; // 1.4138
summary.dddRatio; // 0.014138
summary.totalStablesUsd; // 320489259476n (bigint, whole USD)
summary.m2Usd; // 22667300000000n
summary.timestamp; // 1745001234n (bigint, unix seconds)
summary.sequence; // 1n (monotonic, bumps each cycle)
summary.admin; // PublicKey
summary.authority; // PublicKeyFull snapshot (summary + all three books)
This is what most consumers want — one RPC call, atomic-ish read with a consistent flag.
import { readAll } from "ddd-oracle-sdk";
const snap = await readAll(connection);
if (!snap.consistent) {
console.warn("books are mid-cycle, retry in ~30s");
}
snap.summary.dddPercent; // 1.4138
snap.tokens?.entries[0]; // { name: "USDT", supplyUsd: 186…n, pctScaled: 58270000, pctPercent: 58.27 }
snap.issuers?.entries; // top 25 issuers
snap.chains?.entries; // top 20 chainsIf you want automatic retry on inconsistent reads:
import { readAllConsistent } from "ddd-oracle-sdk";
const snap = await readAllConsistent(connection, { maxRetries: 2, delayMs: 5000 });Individual book reads
import { readChains, readIssuers, readTokens } from "ddd-oracle-sdk";
const tokens = await readTokens(connection);
for (const t of tokens.entries) {
console.log(`${t.name.padEnd(8)} ${t.pctPercent.toFixed(2)}% $${t.supplyUsd}`);
}PDAs
import { derivePdas, deriveOraclePda } from "ddd-oracle-sdk";
const { oracle, chains, issuers, tokens } = derivePdas();
console.log(oracle.toBase58()); // NAtqEH6yLhMPjh6AwbWpiBHEgBw2mAVBB83jqte1Z7VManual decoding
If you already have the raw account data (e.g. from getProgramAccounts or your own RPC layer):
import {
decodeOracleSummary,
decodeChainBook,
decodeIssuerBook,
decodeTokenBook,
isStale,
} from "ddd-oracle-sdk";
const summary = decodeOracleSummary(oracleAccount.data);
const tokens = decodeTokenBook(tokenAccount.data);
if (isStale(summary, tokens)) {
// book hasn't caught up to the latest summary yet
}Reader protocol & consistency
The oracle writes its data in four separate transactions per cycle:
update_summary— bumpssequence, writesddd,total_stables_usd,m2_usd.update_chains— copies the latestsequenceinto theChainBook.update_issuers— same forIssuerBook.update_tokens— same forTokenBook.
Between (1) and (4) — typically a 5-10 second window — a reader could fetch the summary and one or more books that don't yet match. To guarantee an atomic view:
- Use
readAll(orgetMultipleAccountsInfodirectly) so all four accounts come from the same RPC slot. - Check
snap.consistent(orbook.sequence === summary.sequence). - If inconsistent, retry in ~30s or use your last cached snapshot.
readAllConsistent does this for you.
Scaling reference
| Field | Scale | To get a percent | To get a decimal ratio |
|-------|-------|-------------------|--------------------------|
| summary.ddd | (stables/m2) × 1e6 | ddd / 1e4 | ddd / 1e6 |
| entry.pctScaled | percent × 1e6 | pctScaled / 1e6 | pctScaled / 1e8 |
The convenience fields (dddPercent, dddRatio, pctPercent) handle the scaling for you.
Account sizes (for low-level integrators)
| Account | Bytes |
|---------|-------|
| OracleState | 252 |
| ChainBook | 638 |
| IssuerBook | 783 |
| TokenBook | 783 |
Layouts are documented in src/decode.ts and exported as ORACLE_STATE_SIZE, CHAIN_BOOK_SIZE, etc.
Custom networks
Default is mainnet. To point at devnet or a custom deployment:
import { PublicKey } from "@solana/web3.js";
import { readDDD } from "ddd-oracle-sdk";
const summary = await readDDD(connection, {
programId: new PublicKey("YourCustomProgramId..."),
commitment: "finalized",
});TypeScript
The package ships full types (.d.ts). All numeric fields wider than 32 bits use bigint.
Browser support
The SDK is dependency-free aside from @solana/web3.js. It works in Node 18+, modern browsers, Deno, Bun, and Cloudflare Workers — anywhere @solana/web3.js runs.
License
MIT
