> ## 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.

# Delegated Access for SVM Wallets

> Sign messages on behalf of users on Solana using delegated key shares with Dynamic's Python SDK

## Overview

Delegated access allows your server to perform Solana wallet operations on behalf of users with their permission. Dynamic sends delegation credentials to your webhook, and your server uses them to sign without the user being online.

This guide covers the server-side implementation using the Python SDK. For conceptual background on the delegation workflow, see [Delegated Access Overview](/overview/wallets/embedded-wallets/mpc/delegated-access).

## Prerequisites

* A Dynamic environment with embedded wallets (MPC) enabled
* Server API key from the [Dynamic Dashboard](/overview/developer-dashboard/tokens-api-keys)
* [Delegated access configured](/overview/wallets/embedded-wallets/mpc/delegated-access)

## How Delegation Works

1. User approves delegation in your application (client-side)
2. Dynamic sends delegation credentials to your webhook:
   * `walletId` — the user's wallet ID
   * `encryptedWalletApiKey` — temporary API key, encrypted with your RSA public key
   * `encryptedDelegatedShare` — the server key share, encrypted with your RSA public key
3. Your server decrypts the credentials and stores them securely
4. Your server uses the credentials to sign on the user's behalf

## Step 1: Decrypt the Webhook Payload

Dynamic encrypts delegation credentials with your RSA public key. The decrypt helper is chain-agnostic — the same function used for EVM works for SVM:

```python theme={"system"}
from dynamic_wallet_sdk.delegated.decrypt import decrypt_delegated_webhook_data

# webhook_body is the parsed JSON from Dynamic's webhook POST
decrypted = decrypt_delegated_webhook_data(
    private_key_pem=your_rsa_private_key_pem,  # str or bytes
    encrypted_delegated_key_share=webhook_body["encryptedDelegatedShare"],
    encrypted_wallet_api_key=webhook_body["encryptedWalletApiKey"],
)

wallet_api_key = decrypted.decrypted_wallet_api_key
key_share = decrypted.decrypted_delegated_share["secretShare"]
```

Store `wallet_api_key` and `key_share` encrypted in your database alongside the `walletId`.

## Step 2: Create a Delegated Client

```python theme={"system"}
from dynamic_wallet_sdk.delegated.client import create_delegated_svm_client

client = await create_delegated_svm_client(
    environment_id="your-environment-id",
    api_key="your-server-api-key",
)
```

The returned client is an authenticated `DynamicSvmWalletClient`.

## Step 3: Sign a Message

```python theme={"system"}
from dynamic_wallet_sdk.delegated.client import delegated_sign_message

sig_bytes = await delegated_sign_message(
    client,
    wallet_id="wallet-id-from-webhook",
    wallet_api_key=wallet_api_key,
    key_share=key_share,
    message="0x...",   # hex-encoded message hash
    chain_name="SVM",
    is_formatted=True,
)
```

For SVM, `delegated_sign_message` returns the **raw 64-byte Ed25519 signature** as `bytes` — not a string. Convert it to your preferred encoding:

```python theme={"system"}
import base58

signature_b58 = base58.b58encode(sig_bytes).decode()
signature_hex = sig_bytes.hex()
```

**`is_formatted`:**

* `True` — `message` is already a hash (typical Solana flow: pass the hashed transaction message)
* `False` — `message` is a plain string; the SDK formats and hashes it for you

## Complete Webhook Handler Example

```python theme={"system"}
import os
import base58
from dynamic_wallet_sdk.delegated.client import create_delegated_svm_client, delegated_sign_message
from dynamic_wallet_sdk.delegated.decrypt import decrypt_delegated_webhook_data

RSA_PRIVATE_KEY = os.environ["RSA_PRIVATE_KEY_PEM"]


async def handle_delegation_webhook(webhook_body: dict):
    """Store delegation credentials received from Dynamic."""
    decrypted = decrypt_delegated_webhook_data(
        private_key_pem=RSA_PRIVATE_KEY,
        encrypted_delegated_key_share=webhook_body["encryptedDelegatedShare"],
        encrypted_wallet_api_key=webhook_body["encryptedWalletApiKey"],
    )

    await db.store_delegation(
        wallet_id=webhook_body["walletId"],
        wallet_api_key=encrypt(decrypted.decrypted_wallet_api_key),
        key_share=encrypt(decrypted.decrypted_delegated_share["secretShare"]),
    )


async def sign_on_behalf_of_user(wallet_id: str, message_hash_hex: str) -> str:
    """Sign on Solana using stored delegation credentials. Returns base58 signature."""
    credentials = await db.get_delegation(wallet_id)

    client = await create_delegated_svm_client(
        environment_id=os.environ["DYNAMIC_ENV_ID"],
        api_key=os.environ["DYNAMIC_API_KEY"],
    )

    sig_bytes = await delegated_sign_message(
        client,
        wallet_id=wallet_id,
        wallet_api_key=decrypt(credentials.wallet_api_key),
        key_share=decrypt(credentials.key_share),
        message=message_hash_hex,
        chain_name="SVM",
        is_formatted=True,
    )

    return base58.b58encode(sig_bytes).decode()
```

## Security Considerations

* **Never log** delegation credentials (wallet API key, key share)
* Store credentials **encrypted at rest** — treat them like passwords
* Use **secure environment variables** for your RSA private key and server API key
* The RSA private key used for decryption should never leave your server

## Next Steps

* [Sign messages](/python/svm/sign-messages)
* [Sign transactions](/python/svm/sign-transactions)
