@molpha-oracle/sdk (v0.4.0) is the recommended way to integrate Molpha. MolphaSDK wires the gateway client and the Solana client together behind a single wallet, and the package also ships framework-agnostic EVM/Starknet argument builders.
Installation
Install the package along with the optional Solana peer dependencies (required for MolphaSDK / MolphaSolanaClient):
pnpm add @molpha-oracle/sdk @solana/web3.js @coral-xyz/anchor @solana/spl-token bn.js
npm install @molpha-oracle/sdk @solana/web3.js @coral-xyz/anchor @solana/spl-token bn.js
yarn add @molpha-oracle/sdk @solana/web3.js @coral-xyz/anchor @solana/spl-token bn.js
- ESM, browser-first, with
"sideEffects": false
- Tree-shakeable Solana path — gateway-only or read-only apps that skip the Solana imports can tree-shake the Anchor-heavy path entirely
- Node.js
>=18
- Node-only helpers (e.g.
walletFromKeypairFile) live under the @molpha-oracle/sdk/utils subpath so they never enter browser bundles
Initialize
import { Connection } from "@solana/web3.js";
import { MolphaSDK } from "@molpha-oracle/sdk";
import { walletFromKeypairFile } from "@molpha-oracle/sdk/utils";
const sdk = new MolphaSDK({
connection: new Connection("https://api.devnet.solana.com", "confirmed"),
wallet: walletFromKeypairFile("~/.config/solana/id.json"),
});
walletFromKeypairFile is Node.js-only. In the browser, pass a MolphaWallet backed by a wallet adapter:
import type { MolphaWallet } from "@molpha-oracle/sdk";
const wallet: MolphaWallet = {
publicKey: adapter.publicKey,
signTransaction: (tx) => adapter.signTransaction(tx),
signAllTransactions: (txs) => adapter.signAllTransactions(txs),
signAuthMessage: async (msg) => new Uint8Array(await adapter.signMessage(msg)),
};
Without a signAuthMessage-capable wallet (or a keypair-backed wallet), gateway execution falls back to an all-zero authSig. That path is for development only — production jobs should authenticate gateway execution.
Facade surface
| Member | Purpose |
|---|
sdk.requestAndSubmit(jobId, { apiConfig }) | Run a gateway round against the current registry version and submit the signed result to Solana in one call. Returns { result, signature }. |
sdk.gateway | The gateway client: requestSignedData, prepareContext, … |
sdk.solana | The Solana client (below): getPlan, subscribe, createJob, submitDataUpdate, readFeed, verifyDataUpdate, … |
requestAndSubmit is equivalent to:
const result = await sdk.gateway.requestSignedData({ jobId, apiConfig });
const { signature } = await sdk.solana.submitDataUpdate(result);
Solana client (sdk.solana)
All methods target the Molpha program (MoLFeTRpDZgckPjjbLwW1wB9n85bQiqboPnvw9RwoG8 on devnet); PDAs are derived internally from the documented seeds.
Plans and subscriptions
import { PlanType } from "@molpha-oracle/sdk";
const plan = await sdk.solana.getPlan(PlanType.Basic);
const { pricePaid } = await sdk.solana.subscribe(PlanType.Basic, {
maxPriceUsdc: plan.subscriptionPrice,
});
maxPriceUsdc is a safety bound: the transaction aborts if the on-chain price is higher than what the user approved. PlanType ordinals are stable: Basic = 0, Standard = 1, Professional = 2, Enterprise = 3.
Jobs
import { deriveApiConfigHash } from "@molpha-oracle/sdk";
const { jobId } = await sdk.solana.createJob({
apiConfigHash: deriveApiConfigHash(apiConfig),
signaturesRequired: 3,
decimals: 8,
});
Request
// Optional, but recommended before repeated rounds for the same job
await sdk.gateway.prepareContext(jobId);
// Run a gateway signing round (or receive a cached result)
const result = await sdk.gateway.requestSignedData({ jobId, apiConfig });
result.fresh indicates whether the value was fetched this round (false means cached). Gateway execution is authenticated via signAuthMessage; wallets without signing support fall back to an all-zero authSig for development only.
Submission and reads
// Verify + write the signed result to the Feed account
const { signature } = await sdk.solana.submitDataUpdate(result);
// Read the finalized on-chain feed value
const feed = await sdk.solana.readFeed(jobId);
console.log(feed.value, feed.canonicalTimestamp);
submit_data_update is permissionless on-chain — the program re-verifies the aggregate signature on every write and only accepts a value whose canonical_timestamp is strictly greater than the stored one.
Stateless verification
// Verify a signed result via simulation without writing state
const { value, canonicalTimestamp } = await sdk.solana.verifyDataUpdate(result);
Simulates the verify_data_update instruction and decodes the 72-byte return data — see Read and Verify on Solana for the underlying mechanics.