Accounts: HD vs PK
The two account kinds — HD (one BIP-39 mnemonic, many derivation slots) and PK (individually imported private keys) — and the capability differences between them.
An account is a named, password-protected key holder inside a workspace. Every account is one of two kinds, fixed at creation and exposed as account.organizationType:
- HD — backed by a single BIP-39 mnemonic. Each derivation slot yields one EVM address and one Solana address from independent BIP-44 paths, so the same mnemonic drives an unbounded number of wallets.
- PK — backed by individually imported private keys. Each
importPrivateKey()call adds one wallet; there is no shared mnemonic.
Accounts are created through ws.accounts.create(...). The kind is inferred from the secret you pass — a valid mnemonic makes an HD account, a recognizable private key makes a PK account — or forced with opts.kind.
Creating an account
import { Workspace } from "wative-core";
const ws = await Workspace.open({ path: "./my-wallet", password: "wsp-pwd" });
// HD: the secret is a BIP-39 mnemonic
const hd = await ws.accounts.create("Desk", "wsp-pwd", mnemonic);
// PK: the secret is a private key; force the kind to be explicit
const pk = await ws.accounts.create(
"External Hot Wallet",
"wsp-pwd",
"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
undefined,
{ kind: "PK" },
);Signature
ws.accounts.create(
displayName: string,
password: string,
secret: string,
defaultNetwork?: NetworkLike,
opts?: { kind?: AccountOrgType; hasOwnPassword?: boolean },
): Promise<Account>| Parameter | Type | Notes |
|---|---|---|
displayName | string | 4–64 characters. The on-disk slug (account.slug) is derived from it. |
password | string | The password the account's secrets are sealed under (see passwords below). |
secret | string | A BIP-39 mnemonic (HD) or a private key (PK). The kind is inferred from its shape unless opts.kind overrides it. |
defaultNetwork | NetworkLike | Optional. A network slug, chain id, hex chain id, or Network instance. Defaults to ethereum. See Account Reference. |
opts.kind | AccountOrgType | "HD" or "PK". Forces the kind instead of inferring it from secret. |
opts.hasOwnPassword | boolean | Defaults to true. See passwords below. |
An account is never born empty. An HD account derives wallet 0 during create(); a PK account auto-imports the secret you passed as wallet 0.
Capability differences
| Capability | HD | PK |
|---|---|---|
| Backing secret | one BIP-39 mnemonic | individually imported private keys |
| Wallet 0 at create | derived from the mnemonic | the imported secret |
deriveWallets(n) | yes | no — throws UNSUPPORTED_OP |
sliceWallets(n) | yes | no — throws UNSUPPORTED_OP |
importPrivateKey() | no | yes |
dumpMnemonic() | yes | no — throws |
setDisabledSlots() / setDisabledAddressNos() | yes | no — throws UNSUPPORTED_OP |
wallets.drop() | yes (retires the freed BIP-32 index) | yes |
| Addresses per wallet | one EVM + one Solana, from independent BIP-44 paths | the imported key plus its cross-curve sibling |
The two kinds share the whole session and password surface — tryUnlock, resetPassword, lock, setDefaultNetwork, rename, drop, filterAddress. Those live in Account Reference.
The addresses on an HD wallet come from two different BIP-44 paths (m/44'/60'/… for EVM and m/44'/501'/… for Solana), so their private keys are independent. A PK wallet's two addresses are derived from the same 32 secret bytes reused across both curves — whoever learns that key holds both chains. See PK Accounts.
Per-account vs shared passwords
Each account carries its own encryption password by default (hasOwnPassword: true). You unlock it with tryUnlock(itsPassword).
Pass hasOwnPassword: false to make the account share the workspace password instead. Its secrets are then sealed under the workspace password, so it must be created with that same password, and it unlocks with a no-argument tryUnlock() that falls back to the workspace password.
// Own password — unlock with its own credential
const sub = await ws.accounts.create("SubAccount", "sub-pwd", mnemonic, undefined, {
hasOwnPassword: true,
});
await sub.tryUnlock("sub-pwd");
// Shared password — must be created with the workspace password
const shared = await ws.accounts.create("Shared", "wsp-pwd", mnemonic, undefined, {
hasOwnPassword: false,
});
await shared.tryUnlock(); // falls back to the workspace passwordPassword rotation, the hasOwnPassword field, and checkPassword are covered in Account Reference.