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.

The Rust SDK is stateless. It does not hold wallet state between calls. After create_wallet_account(), you receive two distinct pieces of state — each belongs in a different storage tier:
Returned valueSensitivityWhere to storeHow it’s used
WalletPropertiesNon-sensitiveNormal cache: Redis, Postgres, etc. Read on every request.Identifies the wallet; passed to every sign / export operation.
Vec<ServerKeyShare>Sensitive (MPC key material)Secrets vault: HSM, KMS-wrapped DB column, AWS Secrets Manager, etc.The customer-side half of MPC signing. Combined with your Dynamic API key, provides signing authority.
Both must be persisted from creation. The SDK provides no compatibility shim — every subsequent operation requires WalletProperties explicitly, and operations without cached Vec<ServerKeyShare> (and without backup fallback) will fail.

Persisting WalletProperties

WalletProperties is non-sensitive identity + backup-pointer metadata. It’s serde::Serialize / Deserialize, so cache it like any other per-user record:
let (wallet_properties, external_server_key_shares) = evm
    .create_wallet_account(
        ThresholdSignatureScheme::TwoOfTwo,
        Some("user-password".to_string()),
        /* back_up_to_dynamic */ true,
    )
    .await?;

// Cache the full struct — including external_server_key_shares_backup_info.
redis.set(
    format!("wallet:{}", wallet_properties.account_address),
    serde_json::to_string(&wallet_properties)?,
).await?;
Cache the full struct. The external_server_key_shares_backup_info field on WalletProperties is not recoverable via SDK-scoped endpoints — fetch_wallet_metadata(account_address) returns identity only. Operations that need it (password verification, share recovery) will fail with Error::StaleWalletProperties if it’s missing.

Storing Vec<ServerKeyShare>

When you set back_up_to_dynamic: false during wallet creation, you are responsible for securely storing the Vec<ServerKeyShare> returned by create_wallet_account. These key shares, combined with your Dynamic developer API key, provide signing authority and must be protected with defense-in-depth strategies. ServerKeyShare is serde::Serialize / Deserialize — serialize to JSON or your vault’s native format before persisting.
Use the google-cloud-secretmanager crate (or gcloud-sdk) — same pattern as AWS KMS, integrated with Google Cloud’s IAM and audit logging.
Use the azure_security_keyvault crate — Azure-managed secrets with Managed Identity auth.
Use the vaultrs crate to read/write secrets to a Vault KV mount. Works well if your stack already runs Vault.

Security Requirements Checklist

Regardless of your storage method, follow these requirements:
  • Never log plaintext key shares — redact external_server_key_shares from all logs, error messages, and monitoring. The SDK’s tracing instrumentation already skips these args; do the same in your own code.
  • Encrypt at rest — use AES-256-GCM or equivalent; ensure database/storage has encryption enabled
  • Encrypt in transit — all communication must use TLS 1.3
  • Implement access controls — restrict which services and roles can decrypt key shares
  • Enable audit logging — track all access to encrypted materials with timestamps and actor identity
  • Separate encryption keys — don’t reuse keys across environments (dev/staging/prod)
  • Use unique encryption per record — generate new IVs for each encryption operation
  • Implement key rotation — rotate encryption keys periodically (e.g., every 90 days)
  • Plan for key compromise — document incident response for key material exposure
  • Secure deletionzeroize::Zeroize your decrypted shares after use

Storage Schema Example

CREATE TABLE server_wallet_key_shares (
  id UUID PRIMARY KEY,
  wallet_id VARCHAR(255) NOT NULL,
  account_address VARCHAR(255) NOT NULL,

  -- Encrypted with KMS/Vault
  encrypted_key_shares BYTEA NOT NULL,

  -- Metadata for key management
  encryption_key_id VARCHAR(255) NOT NULL,
  encryption_algorithm VARCHAR(50) DEFAULT 'AES-256-GCM',

  -- Audit fields
  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  last_accessed_at TIMESTAMP,
  access_count INTEGER DEFAULT 0
);

What NOT to Do

  • Never store plaintext key shares in databases, files, or environment variables
  • Never commit encryption keys or key shares to version control
  • Never use the same encryption key across all wallets
  • Never rely solely on database encryption without application-level encryption
  • Never expose key shares through APIs or logs