Skip to main content

Documentation Index

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

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

WalletMetadata describes a wallet’s non-sensitive identity and backup-pointer state. It is returned alongside externalServerKeyShares from wallet-creation methods and must be passed as an explicit argument to every subsequent sign, export, backup, refresh, reshare, and password operation. The Node SDK is stateless — it does not hold wallet state between calls. Persist walletMetadata in a cache (Redis, Postgres, etc.) and externalServerKeyShares in a secrets vault (HSM, KMS-wrapped DB column, Secret Manager). See Storage Best Practices for the recommended split.

Interface Definition

interface WalletMetadata {
  walletId: string;
  accountAddress: string;
  chainName: string;
  thresholdSignatureScheme: ThresholdSignatureScheme;
  derivationPath?: string;
  addressType?: string; // BTC only
  externalServerKeySharesBackupInfo?: KeyShareBackupInfo;
}

Properties

Required Properties

  • walletId (string) — Unique identifier for the wallet
  • accountAddress (string) — The wallet’s account address
  • chainName (string) — SDK-internal chain name (EVM, SVM, BTC, TON)
  • thresholdSignatureScheme (ThresholdSignatureScheme) — The threshold signature scheme used for this wallet

Optional Properties

  • derivationPath (string) — Derivation path for the wallet (e.g. EVM uses a BIP-44 path; encoded as a JSON object)
  • addressType (string) — Bitcoin address type (taproot or native_segwit). Required for BTC operations; absent for other chains.
  • externalServerKeySharesBackupInfo (KeyShareBackupInfo) — Per-share pointer metadata describing where each share is backed up. Required for signMessage, signTransaction, signTypedData, exportKey, exportPrivateKey, password verification, share recovery, refreshWalletAccountShares, reshare, and updatePassword whenever you pass caller-held externalServerKeyShares. Operations that need it throw a descriptive error when it’s missing. Caching the full walletMetadata returned from createWalletAccount() / importPrivateKey() ensures you have it.

How to obtain WalletMetadata

There are two paths to obtain a walletMetadata value, with different completeness guarantees:
SourceIncludes backupInfo?Includes addressType?Use when
createWalletAccount() / importPrivateKey() return value✅ Yes✅ YesWallet creation. Persist the full object in your cache.
client.fetchWalletMetadata(accountAddress)❌ No❌ NoRecovery path: you have the address but lost the cached metadata. Returns identity only.
The recommended flow is to persist the full walletMetadata from creation. The backup-pointer metadata (externalServerKeySharesBackupInfo) is not recoverable via SDK-scoped endpoints — there is no server-side fallback if you lose it.
fetchWalletMetadata(accountAddress) is not a recovery path for signing or exporting. It returns identity only (no externalServerKeySharesBackupInfo, no addressType). signMessage, signTransaction, signTypedData, exportKey, and exportPrivateKey all throw when called with caller-supplied externalServerKeyShares and a walletMetadata that lacks externalServerKeySharesBackupInfo. If you lose the cached object, you cannot sign — only re-identify.

Example

import { DynamicEvmWalletClient } from '@dynamic-labs-wallet/node-evm';
import { ThresholdSignatureScheme } from '@dynamic-labs-wallet/node';

const client = new DynamicEvmWalletClient({ environmentId, baseApiUrl });
await client.authenticateApiToken(apiKey);

// 1. Create the wallet — returns walletMetadata + externalServerKeyShares.
const { walletMetadata, externalServerKeyShares } = await client.createWalletAccount({
  thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
  backUpToDynamic: true,
  password: 'user-password',
});

// 2. Persist both — to your cache and your vault respectively.
await redis.set(
  `wallet:${walletMetadata.accountAddress}`,
  JSON.stringify(walletMetadata)
);
await vault.write(
  `wallet:${walletMetadata.accountAddress}/shares`,
  externalServerKeyShares
);

// 3. Later, in any process / pod, pass walletMetadata back in.
const cached = JSON.parse(await redis.get(`wallet:${accountAddress}`));
const shares = await vault.read(`wallet:${accountAddress}/shares`);

const signature = await client.signMessage({
  walletMetadata: cached,
  externalServerKeyShares: shares,
  message: 'Hello',
  password: 'user-password',
});

Updating cached walletMetadata after mutating operations

updatePassword, refreshWalletAccountShares, and reshare all return a new backupInfo reflecting the new backup state. You must merge it into your cached walletMetadata — otherwise the next operation reads stale metadata and either silently misbehaves or surfaces a “stale walletMetadata” error.
const { backupInfo } = await client.updatePassword({
  walletMetadata,
  externalServerKeyShares,
  existingPassword: 'old-password',
  newPassword: 'new-password',
  backUpToDynamic: true,
});

const updated = {
  ...walletMetadata,
  externalServerKeySharesBackupInfo: backupInfo,
};
await redis.set(
  `wallet:${updated.accountAddress}`,
  JSON.stringify(updated)
);