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

importPrivateKey brings an externally-managed private key into the Dynamic MPC system. The imported wallet is stored as a standard MPC wallet with the canonical share layout (client + Dynamic + optional backup) — there is no insecure “key copy”, and the raw private key is never persisted in plaintext after the import ceremony. Use this for:
  • Migrating wallets from another custody system
  • Bringing a wallet you previously exported back into MPC
  • Onboarding existing on-chain accounts to Dynamic
The Java SDK exposes three flavors:
  • DynamicEvmWalletClient::importPrivateKey — EVM, takes raw 32 bytes
  • DynamicSvmWalletClient::importPrivateKey — SVM, takes the 32-byte Ed25519 seed (the seed half of a 64-byte keypair)
  • DynamicWalletClient::importRawPrivateKey — chain-agnostic, takes a ChainName enum and lets you tune the threshold scheme

Prerequisites

  • Set up your Dynamic project
  • An authenticated client (DynamicEvmWalletClient, DynamicSvmWalletClient, or the base DynamicWalletClient)
  • The raw private key bytes (handle them as byte[] and zero the array after import)

EVM Import

import xyz.dynamic.waas.KeygenResult;
import xyz.dynamic.waas.evm.opts.ImportPrivateKeyOpts;

byte[] privateKey = /* 32 raw bytes — e.g. Numeric.hexStringToByteArray("0x...") */;

KeygenResult wallet = evmClient.importPrivateKey(ImportPrivateKeyOpts.builder()
    .privateKey(privateKey)
    .build()
).join();

String address = wallet.walletProperties().accountAddress();   // EIP-55 hex
System.out.println("Imported EVM wallet: " + address);

// Zero the source bytes immediately.
java.util.Arrays.fill(privateKey, (byte) 0);

SVM Import

import xyz.dynamic.waas.KeygenResult;
import xyz.dynamic.waas.svm.opts.ImportPrivateKeyOpts;

byte[] solanaSeed = /* 32 raw bytes — the seed half of a 64-byte Solana keypair */;

KeygenResult wallet = svmClient.importPrivateKey(ImportPrivateKeyOpts.builder()
    .privateKey(solanaSeed)
    .build()
).join();

String address = wallet.walletProperties().accountAddress();   // base58
System.out.println("Imported Solana wallet: " + address);

java.util.Arrays.fill(solanaSeed, (byte) 0);
Solana’s native Keypair is 64 bytes (seed || pubkey). Pass only the first 32 bytes — importPrivateKey derives the public key itself and would reject a 64-byte input.

Chain-Agnostic Import

When you want a single code path that handles both EVM and Solana, use DynamicWalletClient::importRawPrivateKey:
import xyz.dynamic.waas.DynamicWalletClient;
import xyz.dynamic.waas.KeygenResult;
import xyz.dynamic.waas.core.types.ChainName;
import xyz.dynamic.waas.core.types.ThresholdSignatureScheme;
import xyz.dynamic.waas.opts.ImportRawPrivateKeyOpts;

KeygenResult wallet = baseClient.importRawPrivateKey(
    ChainName.EVM,                                       // or ChainName.SVM
    ImportRawPrivateKeyOpts.builder()
        .privateKey(privateKey)
        .thresholdSignatureScheme(ThresholdSignatureScheme.TWO_OF_TWO)
        .build()
).join();

Backup After Import

importPrivateKey does not back up to Dynamic automatically. After a successful import:
  1. Persist the returned wallet.externalServerKeyShares() to your secrets vault.
  2. If you also want Dynamic-backed storage, call backupKeyShares(...) on the base client with the password you want to use.
// 1) Vault the local shares.
vault.write(
    "wallet:" + wallet.walletProperties().accountAddress() + "/shares",
    ServerKeyShare.toJsonList(wallet.externalServerKeyShares())
);

// 2) Optional: also back up to Dynamic.
baseClient.backupKeyShares(BackupKeySharesOpts.builder()
    .walletProperties(wallet.walletProperties())
    .externalServerKeyShares(wallet.externalServerKeyShares())
    .password("user-password")
    .build()
).join();

Best Practices

  • Treat the source private key as compromised after import. Anyone who held the key before import still has signing power — rotate any on-chain authority that depends on it.
  • Zero the source bytes immediately after the import ceremony returns (Arrays.fill(privateKey, (byte) 0)).
  • Never log the raw key — redact it from all logs, error messages, and exception payloads.
  • Run the import inside try-with-resources so the wallet client and its native handles are released even if vault writes fail.

Next Steps