Node.js SDK
April 17, 2026 · View on GitHub
Native bindings for Node.js via NAPI. No CLI, no server, no subprocess — the Rust core runs in-process.
This document is non-normative reference implementation documentation. Package names and function signatures here do not define the OWS standard.
Install
npm install @open-wallet-standard/core
The package includes prebuilt native binaries for macOS (arm64, x64) and Linux (x64, arm64). No Rust toolchain required.
For viem, @solana/web3.js, or Tether WDK integrations, install @open-wallet-standard/adapters alongside this package — it wraps an OWS wallet as a framework-native signer without exposing private keys.
Quick Start
import {
generateMnemonic,
createWallet,
listWallets,
signMessage,
signHash,
signAuthorization,
signTypedData,
deleteWallet,
} from "@open-wallet-standard/core";
const mnemonic = generateMnemonic(12);
const wallet = createWallet("my-wallet");
const sig = signMessage("my-wallet", "evm", "hello");
console.log(sig.signature);
API Reference
Types
interface AccountInfo {
chainId: string; // CAIP-2 chain ID (e.g. "eip155:1")
address: string; // Chain-native address
derivationPath: string; // BIP-44 path (e.g. "m/44'/60'/0'/0/0")
}
interface WalletInfo {
id: string; // UUID v4
name: string;
accounts: AccountInfo[];
createdAt: string; // ISO 8601
}
interface SignResult {
signature: string; // Hex-encoded signature
recoveryId?: number; // EVM/Tron recovery ID (v value)
}
interface SendResult {
txHash: string; // Transaction hash
}
Mnemonic
generateMnemonic(words?)
Generate a new BIP-39 mnemonic phrase.
const phrase = generateMnemonic(12); // or 24
// => "goose puzzle decorate much stable beach ..."
| Param | Type | Default | Description |
|---|---|---|---|
words | number | 12 | Word count (12 or 24) |
Returns: string
deriveAddress(mnemonic, chain, index?)
Derive an address from a mnemonic without creating a wallet.
const addr = deriveAddress(mnemonic, "evm");
// => "0xCc1e2c3D077b7c0f5301ef400bDE30d0e23dF1C6"
const solAddr = deriveAddress(mnemonic, "solana");
// => "DzkqyvQrBvLqKSMhCoXoGK65e9PvyWjb6YjS4BqcxN2i"
| Param | Type | Default | Description |
|---|---|---|---|
mnemonic | string | — | BIP-39 mnemonic phrase |
chain | string | — | "evm", "solana", "xrpl", "sui", "bitcoin", "cosmos", "tron", "filecoin" |
index | number | 0 | Account index in derivation path |
Returns: string
Wallet Management
createWallet(name, passphrase?, words?, vaultPath?)
Create a new wallet. Generates a mnemonic and derives addresses for the current auto-derived chain set.
const wallet = createWallet("agent-treasury");
console.log(wallet.accounts);
// => [
// { chainId: "eip155:1", address: "0x...", derivationPath: "m/44'/60'/0'/0/0" },
// { chainId: "solana:5eykt4...", address: "7Kz9...", derivationPath: "m/44'/501'/0'/0'" },
// { chainId: "bip122:000...", address: "bc1q...", derivationPath: "m/84'/0'/0'/0/0" },
// { chainId: "cosmos:cosmoshub-4", address: "cosmos1...", derivationPath: "m/44'/118'/0'/0/0" },
// { chainId: "tron:mainnet", address: "TKLm...", derivationPath: "m/44'/195'/0'/0/0" },
// { chainId: "ton:mainnet", address: "UQ...", derivationPath: "m/44'/607'/0'" },
// { chainId: "sui:mainnet", address: "0x...", derivationPath: "m/44'/784'/0'/0'/0'" },
// { chainId: "xrpl:mainnet", address: "r...", derivationPath: "m/44'/144'/0'/0/0" },
// { chainId: "fil:mainnet", address: "f1...", derivationPath: "m/44'/461'/0'/0/0" },
// ]
| Param | Type | Default | Description |
|---|---|---|---|
name | string | — | Wallet name |
passphrase | string | undefined | Encryption passphrase |
words | number | 12 | Mnemonic word count |
vaultPath | string | ~/.ows | Custom vault directory root |
Returns: WalletInfo
listWallets(vaultPath?)
List all wallets in the vault.
const wallets = listWallets();
console.log(wallets.length); // => 1
Returns: WalletInfo[]
getWallet(nameOrId, vaultPath?)
Look up a wallet by name or UUID.
const wallet = getWallet("agent-treasury");
Returns: WalletInfo
deleteWallet(nameOrId, vaultPath?)
Delete a wallet from the vault.
deleteWallet("agent-treasury");
renameWallet(nameOrId, newName, vaultPath?)
Rename a wallet.
renameWallet("old-name", "new-name");
exportWallet(nameOrId, passphrase?, vaultPath?)
Export a wallet's secret.
- Mnemonic wallets return the phrase string.
- Private key wallets return a JSON string with both curve keys:
// Mnemonic wallet
const phrase = exportWallet("mn-wallet");
// => "goose puzzle decorate much ..."
// Private key wallet
const keysJson = exportWallet("pk-wallet");
const keys = JSON.parse(keysJson);
// => { secp256k1: "4c0883a6...", ed25519: "9d61b19d..." }
Returns: string
Import
importWalletMnemonic(name, mnemonic, passphrase?, index?, vaultPath?)
Import a wallet from a BIP-39 mnemonic. Derives all 9 chain accounts via HD paths.
const wallet = importWalletMnemonic("imported", "goose puzzle decorate ...");
Returns: WalletInfo
importWalletPrivateKey(name, privateKeyHex, passphrase?, vaultPath?, chain?, secp256k1Key?, ed25519Key?)
Import a wallet from a hex-encoded private key. All 9 chains are supported: the provided key is used for its curve's chains, and a random key is generated for the other curve.
The optional chain parameter specifies which chain the key originates from to determine the curve. Defaults to "evm" (secp256k1).
Alternatively, provide explicit keys for each curve via secp256k1Key and ed25519Key. When both are given, privateKeyHex and chain are ignored.
// Import an EVM private key — generates a random Ed25519 key for Solana/Sui/TON
const wallet = importWalletPrivateKey("from-evm", "4c0883a691...");
console.log(wallet.accounts.length); // => 9
// Import a Solana private key — generates a random secp256k1 key for EVM/BTC/etc.
const wallet2 = importWalletPrivateKey(
"from-solana", "9d61b19d...", undefined, undefined, "solana"
);
console.log(wallet2.accounts.length); // => 8
// Import explicit keys for both curves
const wallet3 = importWalletPrivateKey(
"both-keys", "", undefined, undefined, undefined,
"4c0883a691...", // secp256k1 key
"9d61b19d..." // ed25519 key
);
console.log(wallet3.accounts.length); // => 8
| Param | Type | Default | Description |
|---|---|---|---|
name | string | — | Wallet name |
privateKeyHex | string | — | Hex-encoded private key (with or without 0x prefix). Ignored when both curve keys are provided. |
passphrase | string | undefined | Encryption passphrase |
vaultPath | string | ~/.ows | Custom vault directory root |
chain | string | "evm" | Source chain: "evm", "bitcoin", "cosmos", "tron", "filecoin" (secp256k1) or "solana", "sui", "ton" (Ed25519) |
secp256k1Key | string | undefined | Explicit secp256k1 private key (hex). Overrides random generation for secp256k1 chains. |
ed25519Key | string | undefined | Explicit Ed25519 private key (hex). Overrides random generation for Ed25519 chains. |
Returns: WalletInfo
Signing
signMessage(wallet, chain, message, passphrase?, encoding?, index?, vaultPath?)
Sign a message with chain-specific formatting.
const result = signMessage("agent-treasury", "evm", "hello world");
console.log(result.signature); // hex string
console.log(result.recoveryId); // 0 or 1
| Param | Type | Default | Description |
|---|---|---|---|
wallet | string | — | Wallet name or ID |
chain | string | — | Chain family |
message | string | — | Message to sign |
passphrase | string | undefined | Decryption passphrase |
encoding | string | "utf8" | "utf8" or "hex" |
index | number | 0 | Account index |
vaultPath | string | ~/.ows | Custom vault directory root |
Returns: SignResult
signHash(wallet, chain, hashHex, passphrase?, index?, vaultPath?)
Sign a raw 32-byte hash without adding a message prefix.
This operation is only supported on secp256k1-backed chains. For EVM, the returned recoveryId is the raw yParity value (0 or 1).
const result = signHash(
"agent-treasury",
"base",
"11".repeat(32),
);
console.log(result.signature);
console.log(result.recoveryId); // 0 or 1
signAuthorization(wallet, chain, address, nonce, passphrase?, index?, vaultPath?)
Sign an EIP-7702 authorization tuple. This is equivalent to:
signHash(wallet, chain, keccak256(0x05 || rlp([eip155_chain_id(chain), address, nonce])))
chain must resolve to an EVM chain. nonce accepts decimal or 0x-prefixed hex. If you need a nonstandard authorization tuple, such as chain ID 0, precompute the digest and call signHash.
const result = signAuthorization(
"agent-treasury",
"base",
"0x1111111111111111111111111111111111111111",
"7",
);
console.log(result.signature);
console.log(result.recoveryId); // 0 or 1
signTypedData(wallet, chain, typedDataJson, passphrase?, index?, vaultPath?)
Sign EIP-712 typed structured data (EVM only).
const typedData = JSON.stringify({
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "chainId", type: "uint256" },
],
Transfer: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
},
primaryType: "Transfer",
domain: { name: "MyDApp", chainId: "1" },
message: { to: "0xabc...", amount: "1000" },
});
const result = signTypedData("agent-treasury", "evm", typedData);
console.log(result.signature); // hex string
console.log(result.recoveryId); // 27 or 28
| Param | Type | Default | Description |
|---|---|---|---|
wallet | string | — | Wallet name or ID |
chain | string | — | Must be an EVM chain |
typedDataJson | string | — | JSON string of EIP-712 typed data |
passphrase | string | undefined | Decryption passphrase |
index | number | 0 | Account index |
vaultPath | string | ~/.ows | Custom vault directory root |
Returns: SignResult
signTransaction(wallet, chain, txHex, passphrase?, index?, vaultPath?)
Sign a raw transaction (hex-encoded bytes).
const result = signTransaction("agent-treasury", "evm", "02f8...");
console.log(result.signature);
Returns: SignResult
signAndSend(wallet, chain, txHex, passphrase?, index?, rpcUrl?, vaultPath?)
Sign and broadcast a transaction. If rpcUrl is omitted, OWS resolves it from explicit config overrides or built-in defaults.
const result = signAndSend(
"agent-treasury", "evm", "02f8...",
undefined, undefined, "https://mainnet.infura.io/v3/..."
);
console.log(result.txHash);
Returns: SendResult
Policy Management
createPolicy(policyJson, vaultPath?)
Register a policy from a JSON string.
const policy = JSON.stringify({
id: "base-only",
name: "Base only until April",
version: 1,
created_at: "2026-03-22T00:00:00Z",
rules: [
{ type: "allowed_chains", chain_ids: ["eip155:8453"] },
{ type: "expires_at", timestamp: "2026-04-01T00:00:00Z" },
],
action: "deny",
});
createPolicy(policy);
| Param | Type | Default | Description |
|---|---|---|---|
policyJson | string | — | JSON string of the policy definition |
vaultPath | string | ~/.ows | Custom vault directory root |
listPolicies(vaultPath?)
List all registered policies.
const policies = listPolicies();
console.log(policies); // => [{ id: "base-only", name: "Base only until April", ... }]
Returns: object[]
getPolicy(id, vaultPath?)
Get a single policy by ID.
const policy = getPolicy("base-only");
console.log(policy.name); // => "Base only until April"
| Param | Type | Default | Description |
|---|---|---|---|
id | string | — | Policy ID |
vaultPath | string | ~/.ows | Custom vault directory root |
Returns: object
deletePolicy(id, vaultPath?)
Delete a policy by ID.
deletePolicy("base-only");
| Param | Type | Default | Description |
|---|---|---|---|
id | string | — | Policy ID |
vaultPath | string | ~/.ows | Custom vault directory root |
API Key Management
createApiKey(name, walletIds, policyIds, passphrase, expiresAt?, vaultPath?)
Create an API key for agent access to wallets. Returns the raw token (shown once — caller must save it) and key metadata.
const key = createApiKey(
"claude-agent",
["my-wallet"],
["base-only"],
"my-passphrase",
);
console.log(key.token); // => "ows_key_a1b2c3d4..." (save this)
console.log(key.id);
console.log(key.name);
| Param | Type | Default | Description |
|---|---|---|---|
name | string | — | Human-readable key name |
walletIds | string[] | — | Wallet names or IDs this key can access |
policyIds | string[] | — | Policy IDs to enforce on this key |
passphrase | string | — | Vault passphrase (needed to re-encrypt wallet secrets for the key) |
expiresAt | string | undefined | ISO 8601 expiry timestamp |
vaultPath | string | ~/.ows | Custom vault directory root |
Returns: ApiKeyResult — { token: string, id: string, name: string }
listApiKeys(vaultPath?)
List all API keys. Tokens are never returned.
const keys = listApiKeys();
keys.forEach((k) => console.log(k.id, k.name));
Returns: object[]
revokeApiKey(id, vaultPath?)
Revoke (delete) an API key by ID.
revokeApiKey("key-id");
| Param | Type | Default | Description |
|---|---|---|---|
id | string | — | API key ID |
vaultPath | string | ~/.ows | Custom vault directory root |
Custom Vault Path
Every function accepts an optional vaultPath parameter. When omitted, the default vault root at ~/.ows/ is used. This is useful for testing or running isolated environments:
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const tmpVault = mkdtempSync(join(tmpdir(), "ows-test-"));
const wallet = createWallet("test-wallet", undefined, 12, tmpVault);
// ... use wallet ...
rmSync(tmpVault, { recursive: true, force: true });