Load the SDK
Load the SDK for mainnet, replace any of its endpoints, and handle what it checks before it returns.
loadNimbusSdk is the first call your app makes. It reads the settings the SDK ships for mainnet,
checks the browser, and loads the SDK's WebAssembly. Every other function takes the
NimbusSdk it returns, directly or through a session.
Load it once per page. One SDK serves any number of sessions, and it holds no keys.
Load it
import { } from "@umbra/nimbus-solana-web";
const = await (
{ : "mainnet" },
{ : "/nimbus/" },
);assetsBaseUrl is the directory your app serves the SDK's files from, ending with /.
Serve the SDK's files shows how to put them there.
Loading asks no wallet for anything. It fetches only the SDK's WebAssembly. Nimbus's services are first reached when a session opens or a payment runs.
The mainnet preset
The SDK ships a preset for mainnet. It holds the programs, the tokens, every service endpoint and
the proving keys, the large files each proof is built from. So your app passes only
assetsBaseUrl.
These are the mainnet preset's endpoints, read from the SDK when this site was built:
| Option | mainnet preset | Gateway |
|---|---|---|
endpoints.rpc | https://api.mainnet-beta.solana.com | No |
endpoints.indexer | https://data.api-v2.umbraprivacy.com | No |
endpoints.context | https://context.api-v2.umbraprivacy.com | No |
endpoints.guardians | 1: https://gateway.api-v2.umbraprivacy.com/guardian-share-node-relay-12: https://gateway.api-v2.umbraprivacy.com/guardian-share-node-relay-23: https://gateway.api-v2.umbraprivacy.com/guardian-share-node-relay-3 | Yes |
endpoints.screeners | 0: https://gateway.api-v2.umbraprivacy.com/screener | Yes |
endpoints.dataEndorsers | 0: https://gateway.api-v2.umbraprivacy.com/data-endorser | Yes |
endpoints.feeEnclave | https://gateway.api-v2.umbraprivacy.com/fee-enclave | Yes |
endpoints.relayer | https://gateway.api-v2.umbraprivacy.com/relayer | Yes |
endpoints.coordinator | https://gateway.api-v2.umbraprivacy.com/process-coordinator | Yes |
endpoints.primitivesWasm | Your app supplies it | No |
provingKeys | https://assets.api-v2.umbraprivacy.com/zk/ | No |
primitivesWasm comes from assetsBaseUrl, so you rarely pass it yourself.
Replace an endpoint
Pass endpoints to replace any of the preset's, one at a time. The rest keep their preset values.
The most common case is your own Solana RPC:
import { } from "@umbra/nimbus-solana-web";
const = await (
{ : "mainnet" },
{
: "/nimbus/",
: { : "https://rpc.example.com" },
},
);The example app does the same when its settings name an RPC.
Endpoints shows how to point the SDK at services you run yourself.
If you replace an endpoint the gateway fronts, your replacement receives the session's gateway token. Point it only at a host you trust.
What your app reads from it
Treat every field of the SDK as read-only. These are the ones an app usually reads:
| Field | What it holds |
|---|---|
cluster | The cluster you loaded, "mainnet". |
deployment.chain | The chain wallets sign for, such as solana:mainnet. |
mints | The tokens the preset lists, with their decimals. See Tokens. |
settings.endpoints | Every endpoint, after your replacements. |
settings.gatewayEndpoints | The services the gateway fronts, each with its URL. The gateway token goes only to these. |
settings.assetPinning | "pinned" when the SDK checks its own files before running them, "unpinned" when it does not. |
Refuse an unpinned build
A packed copy of the package, the kind a registry serves, is always pinned. A copy built from
source can be unpinned, and then runs its files unchecked. Refuse to go on in production if you
see it:
if (.. !== "pinned") {
throw new ("This build runs the SDK's files unchecked.");
}What it checks
Before it returns, loadNimbusSdk makes sure the SDK can run safely on this page. Each failed check
throws a NimbusSdkError:
| What it checks | Reason when it fails | How to fix it |
|---|---|---|
Every endpoint and the proving keys are set, and assetsBaseUrl ends with / | misconfigured | Pass what the message names. |
The browser has fetch, Web Crypto, IndexedDB, Web Locks, storage and WebAssembly | unsupported-browser | Ask the user for a current browser. |
| The page is cross-origin isolated | unsupported-browser | Send the two headers. |
| The WebAssembly file can be fetched | service-unavailable | Check assetsBaseUrl and that the files are served. |
| The file's SHA-256 is the one the package pins | dependency-nonconforming | Serve the files that shipped with this copy of the package. |
| The WebAssembly gives the right answers to its known-answer self-tests | dependency-nonconforming | The same. |
| The file is WebAssembly at all | unreadable | Check that assetsBaseUrl names the right directory. |
| The browser opens the SDK's cache in IndexedDB | unsupported-browser | Some private windows refuse it. |
The prover worker is checked the same way when the first proof starts. Its script, and each file it loads, must match the SHA-256 the package pins.
Turn each reason into a message your user can act on:
import { } from "@umbra/nimbus-solana-web";
function (: unknown): string {
if (!()) return "The private balance could not load.";
switch (.) {
case "unsupported-browser":
return "This browser cannot run private payments. Try a current Chrome, Firefox or Safari.";
case "service-unavailable":
return "The app's files could not be fetched. Try again.";
case "misconfigured":
case "dependency-nonconforming":
case "unreadable":
return "This app is set up wrongly. Please tell its developers.";
case "wallet-unsupported":
case "unauthorized":
case "recipient-unregistered":
case "account-unregistered":
return "The private balance could not load.";
}
}Log thrown.message as well. It names the endpoint, file or browser feature at fault.
Next
Last updated