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.
npm install @open-wallet-standard/coreThe package includes prebuilt native binaries for macOS (arm64, x64) and Linux (x64, arm64). No Rust toolchain required.
import {
generateMnemonic,
createWallet,
listWallets,
signMessage,
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);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
}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
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", "sui", "bitcoin", "cosmos", "tron", "filecoin" |
index |
number |
0 |
Account index in derivation path |
Returns: string
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: "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
List all wallets in the vault.
const wallets = listWallets();
console.log(wallets.length); // => 1Returns: WalletInfo[]
Look up a wallet by name or UUID.
const wallet = getWallet("agent-treasury");Returns: WalletInfo
Delete a wallet from the vault.
deleteWallet("agent-treasury");Rename a wallet.
renameWallet("old-name", "new-name");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 a wallet from a BIP-39 mnemonic. Derives all 8 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 8 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); // => 8
// 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
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
Sign EIP-712 typed structured data (EVM only).
Current implementations support typed-data signing for owner-mode credentials. API-token typed-data signing is not yet supported.
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
Sign a raw transaction (hex-encoded bytes).
const result = signTransaction("agent-treasury", "evm", "02f8...");
console.log(result.signature);Returns: SignResult
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
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 |
List all registered policies.
const policies = listPolicies();
console.log(policies); // => [{ id: "base-only", name: "Base only until April", ... }]Returns: object[]
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
Delete a policy by ID.
deletePolicy("base-only");| Param | Type | Default | Description |
|---|---|---|---|
id |
string |
— | Policy ID |
vaultPath |
string |
~/.ows |
Custom vault directory root |
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 }
List all API keys. Tokens are never returned.
const keys = listApiKeys();
keys.forEach((k) => console.log(k.id, k.name));Returns: object[]
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 |
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 });