What you need on your machine
- Rust
- TypeScript
- Anchor
- Solana CLI
- LiteSVM
- Cargo
- pnpm
Each surface does the part that can be done without a cluster, and says so where it stops.
Rust SDK nuvex-sdk
In developmentprove_vrf(&secret, &request, JobType, &input) builds the alpha binding and returns an 80-byte proof with a 64-byte output. node_pda derives a node account. The secret stays with the caller, and submit_request returns NotImplemented.
Rust reference// Rust SDK, secret stays locallet proof = nuvex_sdk::prove_vrf(&secret, &request, JobType::Vrf, &input,)?;// proof.proof: [u8; 80], proof.output: [u8; 64]
JavaScript SDK @nuvex/sdk
In developmentrequestPda(programId, requester, requestId) and protocolPda derive the same addresses from the shared seed list. submitRequest throws on purpose, because building a transaction for an instruction this client cannot send would be a stub.
TypeScript reference// TypeScript SDKimport { requestPda } from "@nuvex/sdk";const [request] = requestPda(coreProgramId, requester, requestId,);
Command line nuvex
In developmentFive commands: node, request, registry, staking and network. network reads NUVEX_API_URL and refuses to invent status if it is unset. The other operational commands still exit with the milestone that implements them.
CLI reference$ nuvex networkNUVEX_API_URL is unset$ nuvex --helpnode request registry staking network
CPI from your consumer program
Oracle core calls verify_vrf on the verification program, then invokes the callback you named. Your program implements an Anchor instruction called callback that takes the 64-byte output and a byte vector, with no accounts.
CPI referenceEvery line below runs against the published API. Nothing here reaches a cluster.
prove.rs
use nuvex_job_types::JobType;
use nuvex_sdk::{node_pda, prove_vrf};
let (node, _bump) = node_pda(®istry_program_id, &node_authority);
// The secret never leaves the caller.
let proved = prove_vrf(&secret, &request, JobType::Vrf, &input)?;
// proved.proof is [u8; 80], proved.output is [u8; 64]request.ts
import { protocolPda, requestPda, submitRequest } from "@nuvex/sdk";
const [protocol] = protocolPda(coreProgramId);
const [request] = requestPda(coreProgramId, requester, requestId);
// submitRequest throws. It does not build a transaction.
submitRequest({ jobType: "vrf", maxFeeLamports: 0n });terminal
nuvex --help
# node request registry staking network
nuvex network
# NUVEX_API_URL is unset. The CLI does not invent network status.consumer.rs
#[program]
pub mod consumer {
use super::*;
pub fn callback(_ctx: Context<Callback>, output: [u8; 64], data: Vec<u8>) -> Result<()> {
msg!("nuvex-callback {}", output[0]);
let _ = data.len();
Ok(())
}
}
// The callback receives no accounts.
#[derive(Accounts)]
pub struct Callback {}make check is the gate. It runs on a laptop and never deploys anything.
Formatting and Clippy
Rust and JavaScript formatting are checked, and Clippy runs across the workspace with warnings denied.
cargo build-sbf
The three programs and the test callback consumer are built as SBF binaries before any program test runs.
Rust and SDK tests
The Rust workspace tests and the JavaScript SDK tests both run. LiteSVM 0.17 loads the programs from target/deploy/*.so.
Copy the example file
cp env/.env.local.example .env.local before you point any process at a cluster. Leave the secrets empty.
Program ids come from the environment
The JavaScript SDK reads the three program ids from NUVEX_ORACLE_CORE_PROGRAM_ID and its siblings. A missing variable stays undefined, and nothing substitutes the ids from Anchor.toml.
Keys stay out of the tree
RPC URLs and key paths are variables too. Development program keypairs live in keys/program/ and are gitignored.