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

# Delegated Access for EVM Wallets

> Learn how to use delegated access to sign messages and transactions on behalf of users with their permission

## Overview

Delegated access allows your server to perform wallet operations (signing messages and transactions) on behalf of users with their permission. This is useful for automating workflows while maintaining security through user-approved delegation.

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

## Prerequisites

Before implementing delegated access, you need:

* A Dynamic environment with embedded wallets (MPC) enabled
* Server API key from the [Dynamic dashboard](/overview/developer-dashboard/tokens-api-keys)
* [Access to delegated shares, wallet API etc. via Delegated Access](/overview/wallets/embedded-wallets/mpc/delegated-access)

## How Delegation Works

1. User approves delegation request in your application (client-side)
2. Dynamic sends delegation credentials to your webhook endpoint:
   * `walletId`: The user's wallet ID
   * `walletApiKey`: Temporary API key for this wallet
   * `keyShare`: Server key share for signing operations
3. Your server stores these credentials securely
4. Your server uses these credentials to perform signing operations

## Creating the Delegated Client

First, create a delegated EVM wallet client using your server API key:

```typescript theme={"system"}
import { createDelegatedEvmWalletClient } from '@dynamic-labs-wallet/node-evm';

const delegatedClient = createDelegatedEvmWalletClient({
  environmentId: 'your-environment-id',
  apiKey: 'your-server-api-key',
});
```

### Configuration Options

```typescript theme={"system"}
const delegatedClient = createDelegatedEvmWalletClient({
  environmentId: 'your-environment-id', // Required
  apiKey: 'your-server-api-key', // Required
  baseMPCRelayApiUrl: 'https://mpc-relay.dynamic.xyz', // Optional: custom MPC relay URL
});
```

## Signing Messages

Use the delegated client to sign messages on behalf of users. You'll need the delegation credentials received from your webhook.

### Basic Message Signing

```typescript theme={"system"}
import { delegatedSignMessage } from '@dynamic-labs-wallet/node-evm';

const signature = await delegatedSignMessage(delegatedClient, {
  walletId: 'wallet-id-from-webhook',
  walletApiKey: 'wallet-api-key-from-webhook',
  keyShare: keyShareFromWebhook, // ServerKeyShare object
  message: 'Hello, World!',
});

console.log('Message signed:', signature);
```

## Signing Transactions

Sign EVM transactions using delegated access. The transaction must be a valid Viem `TransactionSerializable` object.

### Basic Transaction Signing

```typescript theme={"system"}
import { delegatedSignTransaction } from '@dynamic-labs-wallet/node-evm';
import type { TransactionSerializable } from 'viem';

const transaction: TransactionSerializable = {
  to: '0xRecipientAddress',
  value: BigInt('1000000000000000000'), // 1 ETH in wei
  chainId: 1
};

const signedTx = await delegatedSignTransaction(delegatedClient, {
  walletId: 'wallet-id-from-webhook',
  walletApiKey: 'wallet-api-key-from-webhook',
  keyShare: keyShareFromWebhook,
  transaction,
});

console.log('Signed transaction:', signedTx);
```

### Complete Transaction Flow

```typescript theme={"system"}
import { delegatedSignTransaction } from '@dynamic-labs-wallet/node-evm';
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';

const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(),
});

const transaction = {
  to: '0xRecipientAddress',
  value: BigInt('1000000000000000000'),
  chainId: 1,
};

const nonce = await publicClient.getTransactionCount({
  address: walletAddress,
});

const gasEstimate = await publicClient.estimateGas({
  account: walletAddress,
  to: transaction.to,
  value: transaction.value,
});

const fullTransaction = {
  ...transaction,
  nonce,
  gasLimit: gasEstimate,
  maxFeePerGas: BigInt('20000000000'),
  maxPriorityFeePerGas: BigInt('1000000000'),
};

const signedTx = await delegatedSignTransaction(delegatedClient, {
  walletId: 'wallet-id-from-webhook',
  walletApiKey: 'wallet-api-key-from-webhook',
  keyShare: keyShareFromWebhook,
  transaction: fullTransaction,
});

const txHash = await publicClient.sendRawTransaction({
  serializedTransaction: signedTx as `0x${string}`,
});

console.log('Transaction hash:', txHash);
```

## Security Considerations

### Credential Storage

* **Never log or expose** delegation credentials (wallet API key, key share)
* Store credentials encrypted at rest in your database
* Use secure environment variables for server API keys
* Implement credential rotation policies

### Best Practices

```typescript theme={"system"}
class DelegatedWalletService {
  private client: DelegatedEvmWalletClient;

  constructor() {
    this.client = createDelegatedEvmWalletClient({
      environmentId: process.env.DYNAMIC_ENVIRONMENT_ID!,
      apiKey: process.env.DYNAMIC_API_KEY!,
      debug: process.env.NODE_ENV === 'development',
    });
  }

  async signMessage(userId: string, message: string): Promise<string> {
    const credentials = await this.getEncryptedCredentials(userId);

    if (!credentials) {
      throw new Error('No delegation credentials found');
    }

    try {
      const signature = await delegatedSignMessage(this.client, {
        walletId: credentials.walletId,
        walletApiKey: credentials.walletApiKey,
        keyShare: credentials.keyShare,
        message,
      });

      await this.auditLog({
        userId,
        action: 'sign_message',
        message,
        timestamp: new Date(),
      });

      return signature;
    } finally {
      this.clearSensitiveData(credentials);
    }
  }

  private async getEncryptedCredentials(userId: string) {
    // Implementation (important-comment)
  }

  private clearSensitiveData(credentials: any) {
    // Implementation (important-comment)
  }

  private async auditLog(data: any) {
    // Implementation (important-comment)
  }
}
```

## Related

If you want to sponsor gas for delegated transactions from your server, see [Sponsor Gas for Server Wallets (EVM)](/node/wallets/server-wallets/gas-sponsorship).
