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.

Overview

Two related pieces of wallet lifecycle live on the base DynamicWalletClient:
  1. updatePassword — Rotate the password protecting the wallet’s backup. Local re-encrypt only, no MPC ceremony.
  2. State predicatesisPasswordEncrypted, requiresPasswordForOperation, requiresRestoreBackupSharesForOperation. Pure-local static helpers that tell you what inputs the next operation will need.
Use the predicates in UI code to decide whether to prompt the user for a password or trigger a backup-shares recovery before the underlying signing / export call. Use updatePassword to rotate the AES-256-GCM password that wraps the backup shares Dynamic stores on your behalf.

State Predicates

All three predicates are pure-local — no MPC, no network. They inspect the WalletProperties.externalServerKeySharesBackupInfo field and return a boolean.
import xyz.dynamic.waas.DynamicWalletClient;
import xyz.dynamic.waas.core.types.WalletOperation;
import xyz.dynamic.waas.core.types.WalletProperties;

// Is the wallet's backup protected by a password?
boolean encrypted    = DynamicWalletClient.isPasswordEncrypted(walletProperties);

// Will the next signMessage call need a password input from the user?
boolean needsPw      = DynamicWalletClient.requiresPasswordForOperation(
    walletProperties,
    WalletOperation.SIGN_MESSAGE
);

// Will the next refresh call need a backup-shares recovery first?
boolean needsRestore = DynamicWalletClient.requiresRestoreBackupSharesForOperation(
    walletProperties,
    WalletOperation.REFRESH
);

WalletOperation enum

The operation argument is one of:
  • SIGN_MESSAGE / SIGN_TYPED_DATA / SIGN_TRANSACTION / SEND_TRANSACTION
  • EXPORT_PRIVATE_KEY
  • REFRESH / RESHARE
  • UPDATE_PASSWORD
The predicates encode the minimum input the SDK will demand for that operation given the wallet’s current state — feed them into your UI gating so users only see the password prompt when it’s actually required.

Use in UI Gating

if (DynamicWalletClient.requiresRestoreBackupSharesForOperation(
        walletProperties, WalletOperation.SIGN_MESSAGE)) {
    // No cached shares + backup exists → trigger recovery flow first.
    promptForBackupRecovery();
} else if (DynamicWalletClient.requiresPasswordForOperation(
        walletProperties, WalletOperation.SIGN_MESSAGE)) {
    // Have shares but the wallet is password-protected.
    promptForPassword();
} else {
    // Free to sign.
    proceedToSign();
}

Rotate the Backup Password

updatePassword is a local re-encrypt only (no MPC ceremony). It decrypts the existing backup shares with existingPassword, re-encrypts with newPassword, and POSTs the new ciphertext. The MPC secret-share material inside the shares is unchanged — only the AES key wrapping it.
import xyz.dynamic.waas.core.types.UpdatePasswordResult;
import xyz.dynamic.waas.opts.UpdatePasswordOpts;

UpdatePasswordResult result = client.updatePassword(UpdatePasswordOpts.builder()
    .walletProperties(walletProperties)
    .existingPassword(currentPassword)
    .newPassword(newPassword)
    .externalServerKeyShares(externalServerKeyShares)
    .build()
).join();

// Persist result.backupInfo() — the backup metadata has been updated.
// Merge it into your cached WalletProperties via withBackupInfo(...).
WalletProperties updated = walletProperties.withBackupInfo(result.backupInfo());
redis.set("wallet:" + updated.accountAddress(), updated.toJson());

Skipping the recovery round-trip

When the caller already has plaintext externalServerKeyShares cached client-side, existingPassword can be omitted — the SDK skips the recovery round-trip entirely:
UpdatePasswordResult result = client.updatePassword(UpdatePasswordOpts.builder()
    .walletProperties(walletProperties)
    .newPassword(newPassword)
    .externalServerKeyShares(externalServerKeyShares)   // already plaintext
    .build()
).join();
This is the common case for active wallets that have cached shares — pay the recovery round-trip only when shares have been evicted.

Why Both Predicates and updatePassword Are Local

Both fall in the same conceptual bucket: the SDK already has everything it needs to answer / perform them client-side, so there’s no MPC ceremony involved. This matters for:
  • Throughput — no Dynamic backend round-trip on the hot path (predicates)
  • RecoveryupdatePassword works the same in disaster scenarios as it does in steady state
  • Cost — no MPC compute consumed for a password rotation
The trade-off is that you must hold the existing password (or plaintext shares) to call updatePassword. If both are lost, the wallet’s MPC shares are recoverable only through the standard refresh / reshare flows (not yet exposed in v0.1.0).

Next Steps