> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage Best Practices

> How to persist wallet state in your Rust backend — what to cache, what to vault.

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 value | Sensitivity | Where to store | How it's used |
| - | - | - | - |
| `WalletProperties` | Non-sensitive | Normal 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:

```rust theme={"system"}
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.

## Recommended Storage Approaches

> [accordion] 1. Envelope Encryption with Cloud KMS (Recommended)
>
> Use a cloud Key Management Service to encrypt the key shares before storing them in your database.
>
> **AWS KMS Example (using `aws-sdk-kms`):**
>
> ```rust theme={"system"}
> use aws_sdk_kms::{primitives::Blob, Client};
>
> async fn encrypt_with_kms(
>     kms: &Client,
>     key_id: &str,
>     plaintext: &[u8],
> ) -> anyhow::Result<Vec<u8>> {
>     let out = kms
>         .encrypt()
>         .key_id(key_id)
>         .plaintext(Blob::new(plaintext))
>         .send()
>         .await?;
>     Ok(out.ciphertext_blob.unwrap().into_inner())
> }
>
> async fn decrypt_with_kms(kms: &Client, ciphertext: &[u8]) -> anyhow::Result<Vec<u8>> {
>     let out = kms
>         .decrypt()
>         .ciphertext_blob(Blob::new(ciphertext))
>         .send()
>         .await?;
>     Ok(out.plaintext.unwrap().into_inner())
> }
> ```
>
> **Benefits:**
>
> * Centralized key management with automatic rotation
> * Hardware-backed security (FIPS 140-2 Level 3)
> * Audit logging of all encryption/decryption operations
> * Fine-grained IAM policies

> [accordion] 2. Google Cloud KMS & Secret Manager
>
> Use the `google-cloud-secretmanager` crate (or `gcloud-sdk`) — same pattern as AWS KMS, integrated with Google Cloud's IAM and audit logging.

> [accordion] 3. Azure Key Vault
>
> Use the `azure_security_keyvault` crate — Azure-managed secrets with Managed Identity auth.

> [accordion] 4. HashiCorp Vault
>
> 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 deletion** — `zeroize::Zeroize` your decrypted shares after use

## Storage Schema Example

```sql theme={"system"}
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

> [!WARNING]
>
> * **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**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.