Skip to content
Developers Milestone 5

The Rust SDK, the JavaScript SDK and the nuvex CLI ship today. They derive protocol addresses and prove a VRF output locally. network can read the configured API. None of them submits a transaction.

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 development

prove_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
prove.rs
// Rust SDK, secret stays local
let proof = nuvex_sdk::prove_vrf(
&secret, &request, JobType::Vrf, &input,
)?;
 
// proof.proof: [u8; 80], proof.output: [u8; 64]

JavaScript SDK @nuvex/sdk

In development

requestPda(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
request.ts
// TypeScript SDK
import { requestPda } from "@nuvex/sdk";
 
const [request] = requestPda(
coreProgramId, requester, requestId,
);

Command line nuvex

In development

Five 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
terminal
$ nuvex network
NUVEX_API_URL is unset
 
$ nuvex --help
node 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 reference
Callback
accounts passed0
EXECUTED

Every line below runs against the published API. Nothing here reaches a cluster.

prove.rs

rust
use nuvex_job_types::JobType;
use nuvex_sdk::{node_pda, prove_vrf};

let (node, _bump) = node_pda(&registry_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

typescript
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

bash
nuvex --help
# node  request  registry  staking  network

nuvex network
# NUVEX_API_URL is unset. The CLI does not invent network status.

consumer.rs

rust
#[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.