Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.peaq.xyz/llms.txt

Use this file to discover all available pages before exploring further.

peaqOS supports the Open Wallet Standard v1.3 for wallet generation, encrypted storage, signing, and display. The current raw-key flow uses hex private keys in .env files, protected only by file permissions. That works, but it has limits:
  • No encryption at rest
  • No mnemonic backup or recovery
  • No multi-chain visibility. One secp256k1 key derives addresses on every EVM chain, Cosmos, Solana, Bitcoin, Tron, and more, but nothing surfaces them
  • No standard import / export to wallets like MetaMask or hardware devices
  • No audit log of key creation, signing, or export events
OWS solves all of these with an encrypted local vault, BIP-39 derivation, CAIP-2 chain identifiers, and an append-only audit log: fully local, no cloud, no remote services. OWS is optional. Use the SDK helpers below to manage wallets. The raw-key path keeps working unchanged.

Multi-chain accounts from one mnemonic

A mnemonic-derived wallet generates accounts across every OWS-supported chain family from a single 12- or 24-word phrase.
FamilyCurveCoin TypeDefault PathAddress Format
EVM (peaq, Base, Ethereum, Polygon, etc.)secp256k160m/44'/60'/0'/0/{index}EIP-55 checksummed hex
Solanaed25519501m/44'/501'/{index}'/0'Base58 public key
Bitcoinsecp256k10m/84'/0'/0'/0/{index}Bech32 native segwit
Cosmossecp256k1118m/44'/118'/0'/0/{index}Bech32
Tronsecp256k1195m/44'/195'/0'/0/{index}Base58Check
TONed25519607m/44'/607'/{index}'Base64url wallet v5r1
Suied25519784m/44'/784'/{index}'/0'/0'0x + BLAKE2b-256 hex
XRPLsecp256k1144m/44'/144'/0'/0/{index}Base58Check
Sparksecp256k18797555m/84'/0'/0'/0/{index}spark: + compressed pubkey
Filecoinsecp256k1461m/44'/461'/0'/0/{index}f1 + base32
The SDK guarantees an account entry for every protocol-recognized EVM chain (SUPPORTED_CHAIN_IDS). If OWS doesn’t return one, it’s synthesized from the wallet’s primary EVM address, which is identical across all EVM chains:
NetworkCAIP-2Chain ID
peaqeip155:33383338
ethereumeip155:11
baseeip155:84538453
polygoneip155:137137
arbitrumeip155:4216142161
optimismeip155:1010
Each account is exposed as a CAIP-10 account ID (eip155:3338:0x...), so a single peaqOS wallet can sign on peaq, Base (for bridgeNft), and any other supported chain without ever exporting the key.

Vault layout

The vault lives at ~/.ows/ (override with OWS_VAULT_PATH). Structure is set by OWS; peaqOS uses it as-is.
~/.ows/
├── config.json               # OWS settings (700)
├── wallets/                  # (700)
│   └── {uuid}.json           # one per wallet (600)
├── keys/                     # (700, future use)
├── policies/                 # (755, future use)
└── logs/
    └── audit.jsonl           # append-only operation log (600)
Each wallet file holds:
  • id (UUID v4) and name
  • key_type: "mnemonic" or "private_key"
  • accounts[] with one entry per supported chain (CAIP-10, address, derivation path)
  • crypto with aes-256-gcm ciphertext, scrypt KDF params, IV, salt, and auth tag
  • created_at (ISO 8601)

SDK methods

Wallet lifecycle is exposed through the SDKs.

JavaScript / TypeScript

Available as both module-level imports and static methods on PeaqosClient. Pick whichever matches your style.
import {
  PeaqosClient,
  createWallet,
  importWallet,
  importWalletMnemonic,
  listWallets,
  getWallet,
  exportWallet,
  deleteWallet,
} from "@peaqos/peaq-os-sdk";

// Create
const wallet = await createWallet("my-machine", passphrase, 12);
//   or:  await PeaqosClient.createWallet("my-machine", passphrase, 12);

// Import
await importWallet("my-machine", "0x...64hex", passphrase);
//   default chain: "evm". Pass a different OWS chain (e.g. "solana", "bitcoin", "cosmos")
//   when the private key is for that chain's curve and address format:
//   await importWallet("my-machine", "0x...64hex", passphrase, "solana");
await importWalletMnemonic("my-machine", "twelve words ...", passphrase);

// Inspect
const all = await listWallets();
const one = await getWallet("my-machine");

// Export / delete
const phrase = await exportWallet("my-machine", passphrase);
await deleteWallet("my-machine");
Every function takes an optional final WalletOptions arg with vaultPath to point at a vault directory other than ~/.ows/. Passphrase falls back to OWS_PASSPHRASE when omitted; if both are missing, the call throws PeaqosError. importWallet validates the hex shape eagerly and throws ValidationError for malformed keys; importWalletMnemonic accepts an optional index (default 0) before the WalletOptions arg to derive a non-default account. WalletInfo carries id, name, createdAt, keyType, peaqAddress (convenience), and accounts: readonly AccountInfo[] with every chain. AccountInfo has accountId (CAIP-10), address, chainId (CAIP-2), network (human-readable name like "peaq", "base", "solana"), and derivationPath. Both shapes are deep-frozen.

Building a client straight from a vault wallet

PeaqosClient.fromWallet skips the manual private-key plumbing. It loads a wallet from the vault and returns a configured client whose account is the wallet’s peaq address.
import { PeaqosClient } from "@peaqos/peaq-os-sdk";

// OWS-native signing (default): key is decrypted per-sign and wiped immediately.
// The passphrase is verified on the FIRST signTransaction call, not at construction.
const client = await PeaqosClient.fromWallet("my-machine", "s3cret", true, {
  rpcUrl: "https://peaq-rpc.example.com",
  contracts: { /* ... */ },
});

// Raw-key mode: decrypts the key once at construction (eager passphrase check)
// and signs through viem locally. Use this when you need viem features OWS
// doesn't expose (e.g. signMessage, signTypedData).
const eager = await PeaqosClient.fromWallet("my-machine", "s3cret", false, {
  rpcUrl: "https://peaq-rpc.example.com",
  contracts: { /* ... */ },
});
Signature: fromWallet(nameOrId, passphrase, owsSigning, config, options?). owsSigning defaults to true. In OWS-native mode the SDK never holds the private key: signMessage and signTypedData throw because OWS only exposes signTransaction. Switch to raw-key mode if you need either. OWS signing surfaces typed errors via OwsSigningErrorCode (WALLET_NOT_FOUND, INVALID_PASSPHRASE, INVALID_INPUT, POLICY_DENIED, CHAIN_NOT_SUPPORTED). INVALID_INPUT becomes a ValidationError; the rest become PeaqosError with the original error preserved as .cause.

Python

Available under peaq_os_sdk.wallet and as @staticmethods on PeaqosClient.
from peaq_os_sdk import PeaqosClient
from peaq_os_sdk.wallet import (
    create_wallet,
    import_wallet,
    import_wallet_mnemonic,
    list_wallets,
    get_wallet,
    export_wallet,
    delete_wallet,
)

# Create
info = create_wallet("my-machine", passphrase=passphrase, words=12)
#   or: PeaqosClient.create_wallet("my-machine", passphrase=passphrase, words=12)

# Import
import_wallet("my-machine", "0x...64hex", passphrase=passphrase)
#   default chain="evm". Pass a different OWS chain (e.g. "solana", "bitcoin", "cosmos")
#   when the private key is for that chain's curve and address format:
#   import_wallet("my-machine", "0x...64hex", passphrase=passphrase, chain="solana")
import_wallet_mnemonic("my-machine", "twelve words ...", passphrase=passphrase)

# Inspect
all_wallets = list_wallets()
one = get_wallet("my-machine")

# Export / delete
phrase = export_wallet("my-machine", passphrase=passphrase)
delete_wallet("my-machine")
Each function accepts a final vault_path keyword for a custom vault directory. Passphrase falls back to the OWS_PASSPHRASE env var when None; missing both raises PeaqosError. On the Python side, WalletInfo carries id, name, created_at, key_type, peaq_address (convenience), and accounts: list[AccountInfo] with every chain. AccountInfo has account_id (CAIP-10), address, chain_id (CAIP-2), network (human-readable name), and derivation_path.

Building a client straight from a vault wallet

PeaqosClient.from_wallet mirrors the JS factory above. It loads the wallet, verifies the passphrase, and returns a fully configured client.
from peaq_os_sdk import PeaqosClient

client = PeaqosClient.from_wallet(
    "my-machine",
    passphrase="s3cret",
    rpc_url="https://peaq-rpc.example.com",
    identity_registry="0x...",
    identity_staking="0x...",
    event_registry="0x...",
    machine_nft="0x...",
    did_registry="0x0000000000000000000000000000000000000800",
    batch_precompile="0x0000000000000000000000000000000000000805",
)

# Eager-decrypt: identical to PeaqosClient(private_key=...).
eager = PeaqosClient.from_wallet(
    "my-machine",
    passphrase="s3cret",
    ows_signing=False,
    rpc_url="https://peaq-rpc.example.com",
    # ...
)
Signature: from_wallet(name_or_id, passphrase=None, ows_signing=True, vault_path=None, **config_kwargs). passphrase falls back to OWS_PASSPHRASE. In OWS-native mode the SDK never holds the private key — OWSAccount decrypts it inside the OWS Rust FFI for each sign_transaction call and wipes it immediately. ows_signing=False exports and decrypts the key at construction time, behaving identically to a raw-key client. Each transaction’s chainId drives both the CAIP-2 OWS arg and the EIP-155 v, so the same client transparently signs both peaq (eip155:3338) and Base (eip155:8453) bridge transactions. OWS signing surfaces typed errors via 5 OWS error codes (WALLET_NOT_FOUND, INVALID_PASSPHRASE, INVALID_INPUT, POLICY_DENIED, CHAIN_NOT_SUPPORTED). INVALID_INPUT raises ValidationError; the rest raise PeaqosError. See SDK errors: OWS signing error codes.

Pulling the peaq address out of a wallet

peaq_address / peaqAddress is already populated by every wallet method, so most callers never need anything else. If you’re working with a raw accounts list (e.g. building a wallet response by hand in tests, or reading a vault file directly), use the helper:
import { extractPeaqAddress } from "@peaqos/peaq-os-sdk";
const address = extractPeaqAddress(wallet.accounts);
from peaq_os_sdk.wallet import extract_peaq_address
address = extract_peaq_address(wallet.accounts)
It returns the eip155:3338 account if present, otherwise the first eip155:* account (EVM addresses match across EVM chains), and raises PeaqosError when no EVM account exists.

From the CLI

Every SDK wallet helper is also exposed through peaqos wallet. Install the optional extra to get them:
pip install 'peaq-os-cli[ows]'
Then:
peaqos wallet create my-wallet              # mnemonic-backed, 12 words
peaqos wallet import my-wallet --mnemonic   # hidden prompt for the phrase
peaqos wallet list
peaqos wallet show my-wallet                # full multi-chain address table
peaqos wallet use my-wallet                 # writes PEAQOS_OWS_WALLET=my-wallet to .env
peaqos wallet export my-wallet              # reveals phrase / key after confirm
peaqos wallet delete my-wallet              # secure overwrite + unlink after confirm
peaqos init also offers wallet as a third Private key source choice and writes PEAQOS_OWS_WALLET instead of PEAQOS_PRIVATE_KEY. Once a wallet is active, peaqos activate, peaqos qualify event, and the rest of the command surface sign through it. See peaqOS CLI: wallet for the full command reference.

Security model

  • Vault encryption. AES-256-GCM with scrypt KDF (n=65536, r=8, p=1).
  • Passphrase handling. Sourced from the explicit argument or the OWS_PASSPHRASE env var; if neither is set, the SDK raises PeaqosError rather than prompting. Never stored on disk. In CI, pass via secret manager or env injection.
  • Mnemonic exposure. Never returned by createWallet / create_wallet. The WalletInfo response only carries addresses and metadata. To recover the seed phrase you must call exportWallet / export_wallet with the vault passphrase.
  • Single-mnemonic blast radius. One phrase controls accounts on every supported chain. Treat exported phrases accordingly: anyone with the phrase has access to every chain account.
  • Audit log. Every wallet operation (create, import, export, delete) appends to ~/.ows/logs/audit.jsonl.

See also

peaqOS CLI

The full peaqOS CLI command reference.

Install

The [ows] extra and the raw-key flow side-by-side.

OWS specification

Full upstream Open Wallet Standard v1.3 spec.