@navalabs/sdk-core
v0.17.0
Published
Shared primitives for the Nava SDK — chain and protocol registries, Nava API client, wallet services, and crypto utilities.
Readme
@navalabs/sdk-core
Shared primitives that power Nava SDK packages. A
dependency-light entry point for consumers who only need the base Nava client,
chain and protocol registries, or wallet/crypto utilities, without the Guardian
verification client, agent-execution runtime, CLI, and MCP server that live in
@navalabs/sdk, or the protocol tooling in the adapter packages.
When to use which package
| Need | Package |
|---|---|
| Chain/protocol registries, Nava HTTP client, wallet adapters | @navalabs/sdk-core |
| Full SDK (NavaClient, Guardian verification and management, the nava CLI, the nava-mcp server, agent-execution bootstrap) | @navalabs/sdk |
| Uniswap V3/V4 swap and pool tooling | @navalabs/uniswap-adapter |
| Hyperliquid perps tooling | @navalabs/hyperliquid-adapter |
A protocol operation needs that protocol's adapter. Each adapter depends on @navalabs/sdk and ships its own nava and nava-mcp binaries, so installing the adapter alone is enough. Adapters remain optional peer dependencies of @navalabs/sdk, never bundled into it.
@navalabs/sdk and both adapters depend on @navalabs/sdk-core, so you do not need to install @navalabs/sdk-core explicitly unless you want just the primitives.
Install
pnpm add @navalabs/sdk-core
# or: npm install @navalabs/sdk-core
# or: yarn add @navalabs/sdk-coreRequires Node.js >= 22.12 (@privy-io/node loads the ESM-only jose@6 via
require(), which Node supports natively only from 22.12).
Quick start: Nava API client
Identical client surface to @navalabs/sdk, but without the escrow orchestration layer.
NavaClient has two modes, chosen by the config you pass.
Agent key. One agent API key bound to one wallet:
import { NavaClient } from '@navalabs/sdk-core';
const nava = new NavaClient({
apiKey: 'nava_live_...',
walletAddress: '0xYourAgentWallet',
// Omit `baseUrl` to use https://internal.navalabs.dev/api
});
// `proposedTx.chainId` is required and must be a chain the registry supports;
// `requestVerification` throws at the SDK boundary otherwise.
const created = await nava.requestVerification({
prompt: 'Send 0.1 ETH to Alice',
proposedTx: {
chainId: 11155111,
to: '0x00000000000000000000000000000000000a11ce', // Alice
value: '100000000000000000',
data: '0x',
},
});
const status = await nava.waitForVerification(created.requestHash!);
if (!status.canExecute) throw new Error(status.message);When baseUrl is omitted, the client talks to
https://internal.navalabs.dev/api. Set baseUrl for another environment
(devnet is https://devnet.navalabs.dev/nava-service).
Integration key (partner backend). The wallet address on each call selects
the agent and policy server-side, so one client serves many users' wallets.
Integration keys are server-only; the constructor throws in a browser or a
web/service worker unless allowBrowser: true is set.
import { randomUUID } from 'node:crypto';
import { NavaClient } from '@navalabs/sdk-core';
const nava = new NavaClient({
integration: {
appId: process.env.NAVA_APP_ID!, // integration app ID (UUID)
apiKey: process.env.NAVA_INTEGRATION_KEY!,
},
// Required in this mode; no default host serves /integrator/*.
baseUrl: 'https://devnet.navalabs.dev/nava-service',
});
const walletAddress = '0x...'; // one of the policy editor's stored walletAddresses
const idempotencyKey = randomUUID(); // persist it with the request before sending
const created = await nava.requestVerification({
escrowAddress: walletAddress,
prompt: 'Send 0.1 ETH to Alice',
proposedTx: {
chainId: 11155111,
to: '0x00000000000000000000000000000000000a11ce', // Alice
value: '100000000000000000',
data: '0x',
},
idempotencyKey, // replay with the same key to recover an unknown outcome
});
const status = await nava.waitForVerification(created.id);
if (!status.canExecute) throw new Error(status.message);
// After executing: nava.submitUserExecutionTxHash(created.id, txHash).
// If nothing executed: nava.cancelTransaction(created.id).baseUrl is required in integration mode and has no default; devnet is
https://devnet.navalabs.dev/nava-service. Any scheme is accepted so local
stacks can use http, but use https everywhere else, because every request
carries the key. For a client that serves one wallet, set the top-level
walletAddress; a separately declared config needs the
WalletBoundIntegrationKeyConfig type (or satisfies IntegrationKeyConfig)
for getWalletAddress() to return string. getPolicy({ walletAddress })
reads the wallet's saved policy. Every approval reserves spend until it is
reported or cancelled. Failures are NavaFetchErrors with a code, for
example unauthorized, wallet_not_found, rate_limited, network_error
or report_unconfirmed. See packages/sdk/docs/integration-guide.md for
the action to take on each code and packages/sdk/examples/partner-backend.ts
in the SDK repository for the full flow.
The request field is prompt and the action field is proposedTx
(RequestVerificationParams). A verdict applies only to the exact action
submitted. Nava never signs or broadcasts; the calling application owns
execution, and only after an approved verdict.
Getting an agent API key
Agents authenticate with a long-lived agent x-api-key. Obtain one through the
Nava UI at https://app.navalabs.dev via
OAuth consent or the interactive connect flow, then pass it to NavaClient.
SIWE sign-in is no longer exposed by the SDK.
Registries
ChainRegistry and ProtocolRegistry expose chain metadata (RPC URLs, block explorers, native tokens) and protocol descriptors (nava, uniswap, hyperliquid, polymarket) with typed token and pool entries. The registry is data only: a descriptor existing here does not imply a published adapter. polymarket has no published adapter and is not reachable from the nava CLI or nava-mcp.
import {
ChainRegistry,
ProtocolRegistry,
CHAIN_REGISTRY_ENTRIES,
PROTOCOL_REGISTRY_ENTRIES,
} from '@navalabs/sdk-core';
const sepolia = ChainRegistry.getByChainId(11155111);
const uniswap = ProtocolRegistry.get('uniswap', 1);Wallet services
Unified WalletServiceFactory produces signers for different custody backends via runtime-typed configs:
import {
WalletServiceFactory,
isPrivyWalletConfig,
isFireblocksWalletConfig,
type WalletConfig,
} from '@navalabs/sdk-core';
const wallet = WalletServiceFactory.create(config); // PrivyWalletConfig | FireblocksWalletConfigSupported backends: Privy (@privy-io/node), Fireblocks (@fireblocks/ts-sdk) including JWT auth, and KMS signing (@aws-sdk/client-kms).
Crypto utilities
PGP and P-256 key generation and format validation:
import {
generatePgpKeyPair,
generateP256KeyPair,
validatePgpKey,
validateP256PublicKey,
generateNonce,
getCurrentEnvironment,
} from '@navalabs/sdk-core';Exports summary
- HTTP client & errors:
NavaClient,NavaFetchError,NavaTimeoutError,navaFetchJson,navaFetchRaw - Registries:
ChainRegistry,ProtocolRegistry, and their*_ENTRIESarrays - Wallet services:
WalletServiceFactory,IWalletService,PrivyWalletConfig,FireblocksWalletConfig,FireblocksAuthMethod,FireblocksBasePath - Platform services:
BlockchainService,StorageService,EncryptionService,NavaApiClient,PublicNonceService,FireblocksService,FireblocksJWTService,KMSService,KMSSigningService - Crypto:
generatePgpKeyPair,generateP256KeyPair,validatePgpKey,validateP256PublicKey,generateNonce - Utilities:
Logger,logger,mcpLogger,TransactionGenerator - Types:
TransactionSchema,TransactionRequest,AgentContext,ExecutionResult,VerificationStatusResponse,ApprovalDecision,ChainRegistryEntry,ProtocolRegistryEntry, and more; the package's type declarations (dist/index.d.ts) are the full list.
License
MIT
