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

# delegatedSignTransaction

> Signs a Solana transaction using delegated access on behalf of a user

## Function Signature

```typescript theme={"system"}
delegatedSignTransaction(
  client: DelegatedSvmWalletClient,
  params: {
    walletId: string;
    walletApiKey: string;
    keyShare: ServerKeyShare | ServerKeyShare[];
    transaction: VersionedTransaction | Transaction;
    shareSetId?: string;
    signerAddress?: string;
    derivationPath?: Uint32Array;
  }
): Promise<VersionedTransaction | Transaction>
```

## Description

Signs a Solana transaction on behalf of a user who has granted delegation permission. This function supports both legacy `Transaction` and `VersionedTransaction` types from `@solana/web3.js`.

The function returns the signed transaction object with the signature added, ready to be sent to the Solana network.

For gasless transactions where a separate fee payer covers gas, set `transaction.feePayer` to the fee payer's public key and pass `signerAddress` to identify the actual signer.

## Parameters

### Required Parameters

* **`client`** (`DelegatedSvmWalletClient`) - The delegated client instance created with [`createDelegatedSvmWalletClient()`](/node/reference/svm/create-delegated-svm-wallet-client)
* **`walletId`** (`string`) - The wallet ID from the delegation webhook
* **`walletApiKey`** (`string`) - The wallet-specific API key from the delegation webhook
* **`keyShare`** (`ServerKeyShare | ServerKeyShare[]`) - The server key share(s) from the delegation webhook
* **`transaction`** (`VersionedTransaction | Transaction`) - The Solana transaction to sign

### Optional Parameters

* **`shareSetId`** (`string`) - The `shareSetId` from the `wallet.delegation.created` webhook payload. If omitted, the server resolves the correct share set by `walletId` and share-set type.
* **`signerAddress`** (`string`) - The address that should sign the transaction. If not provided, defaults to the first signer (`VersionedTransaction`) or fee payer (`Transaction`). Use this for gasless transactions where a separate fee payer pays the fees.
* **`derivationPath`** (`Uint32Array`) - Custom derivation path for the signing key.

## Returns

**`Promise<VersionedTransaction | Transaction>`** - The signed transaction with the signature added

## Example

### Basic Transaction Signing

```typescript theme={"system"}
import {
  createDelegatedSvmWalletClient,
  delegatedSignTransaction
} from '@dynamic-labs-wallet/node-svm';
import { Transaction, SystemProgram, PublicKey, Connection } from '@solana/web3.js';

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

const connection = new Connection('https://api.mainnet-beta.solana.com');

const transaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(senderAddress),
    toPubkey: new PublicKey(recipientAddress),
    lamports: 1000000,
  })
);

transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = new PublicKey(senderAddress);

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

console.log('Transaction signed:', signedTx);
```

### Gasless Transaction with Separate Fee Payer

When a separate wallet pays the gas fees, set `feePayer` to the sponsor and pass `signerAddress` so the delegated wallet signs only the instruction:

```typescript theme={"system"}
import {
  createDelegatedSvmWalletClient,
  delegatedSignTransaction,
} from '@dynamic-labs-wallet/node-svm';
import { Transaction, SystemProgram, PublicKey, Connection, Keypair, VersionedTransaction } from '@solana/web3.js';
import bs58 from 'bs58';
import nacl from 'tweetnacl';

const delegatedClient = createDelegatedSvmWalletClient({
  environmentId: process.env.DYNAMIC_ENVIRONMENT_ID!,
  apiKey: process.env.DYNAMIC_API_KEY!,
});

const connection = new Connection(process.env.SOLANA_RPC_URL || 'https://api.devnet.solana.com');
const feePayer = Keypair.fromSecretKey(bs58.decode(process.env.FEE_PAYER_PRIVATE_KEY!));

const credentials = await getDelegationCredentials(userId);
const sender = new PublicKey(credentials.publicKey);

const transaction = new Transaction();
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
transaction.recentBlockhash = blockhash;
transaction.lastValidBlockHeight = lastValidBlockHeight;
transaction.feePayer = feePayer.publicKey; // Sponsor pays fees

transaction.add(
  SystemProgram.transfer({
    fromPubkey: sender,
    toPubkey: new PublicKey(recipientAddress),
    lamports: 1000000,
  })
);

// Sign with delegated wallet — signerAddress identifies the sender
let signedTx = await delegatedSignTransaction(delegatedClient, {
  walletId: credentials.walletId,
  walletApiKey: credentials.walletApiKey,
  keyShare: credentials.keyShare,
  transaction,
  signerAddress: sender.toString(),
});

// Add fee payer signature
if (signedTx instanceof VersionedTransaction) {
  signedTx.sign([feePayer]);
} else {
  const message = signedTx.serializeMessage();
  const feePayerSig = nacl.sign.detached(message, feePayer.secretKey);
  signedTx.addSignature(feePayer.publicKey, Buffer.from(feePayerSig));
}

const signature = await connection.sendRawTransaction(signedTx.serialize());
await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight });
console.log('Gasless transaction confirmed:', signature);
```

### Complete Transaction Flow

```typescript theme={"system"}
import {
  createDelegatedSvmWalletClient,
  delegatedSignTransaction
} from '@dynamic-labs-wallet/node-svm';
import {
  Transaction,
  SystemProgram,
  PublicKey,
  Connection,
  sendAndConfirmTransaction
} from '@solana/web3.js';

const delegatedClient = createDelegatedSvmWalletClient({
  environmentId: process.env.DYNAMIC_ENVIRONMENT_ID!,
  apiKey: process.env.DYNAMIC_API_KEY!,
});

const connection = new Connection('https://api.mainnet-beta.solana.com');

async function sendPayment(
  userId: string,
  recipientAddress: string,
  amount: number
) {
  const credentials = await getDelegationCredentials(userId);
  const senderAddress = credentials.publicKey;

  const transaction = new Transaction().add(
    SystemProgram.transfer({
      fromPubkey: new PublicKey(senderAddress),
      toPubkey: new PublicKey(recipientAddress),
      lamports: amount,
    })
  );

  const { blockhash } = await connection.getLatestBlockhash();
  transaction.recentBlockhash = blockhash;
  transaction.feePayer = new PublicKey(senderAddress);

  const signedTx = await delegatedSignTransaction(delegatedClient, {
    walletId: credentials.walletId,
    walletApiKey: credentials.walletApiKey,
    keyShare: credentials.keyShare,
    transaction,
  });

  const signature = await connection.sendRawTransaction(
    signedTx.serialize()
  );

  await connection.confirmTransaction(signature);

  console.log('Transaction confirmed:', signature);
  return signature;
}
```

### Versioned Transaction

```typescript theme={"system"}
import { VersionedTransaction, TransactionMessage } from '@solana/web3.js';

const message = new TransactionMessage({
  payerKey: new PublicKey(senderAddress),
  recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
  instructions: [
    SystemProgram.transfer({
      fromPubkey: new PublicKey(senderAddress),
      toPubkey: new PublicKey(recipientAddress),
      lamports: 1000000,
    })
  ],
}).compileToV0Message();

const versionedTx = new VersionedTransaction(message);

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

const signature = await connection.sendTransaction(signedTx);
```

## Type Definitions

```typescript theme={"system"}
type ServerKeyShare = {
  pubkey: {
    pubkey: Uint8Array;
  };
  secretShare: string;
};
```

## Error Handling

The function throws an error if:

* Any required parameter is missing or invalid
* The transaction is malformed
* The delegation credentials are expired or revoked
* The MPC signing operation fails
* Network communication with Dynamic services fails

```typescript theme={"system"}
try {
  const signedTx = await delegatedSignTransaction(delegatedClient, {
    walletId: credentials.walletId,
    walletApiKey: credentials.walletApiKey,
    keyShare: credentials.keyShare,
    transaction,
  });

  const signature = await connection.sendTransaction(signedTx);
  console.log('Transaction sent:', signature);
} catch (error) {
  if (error.message.includes('key share')) {
    console.error('Invalid or expired delegation credentials');
  } else if (error.message.includes('transaction')) {
    console.error('Invalid transaction format');
  } else {
    console.error('Transaction signing failed:', error);
  }
}
```

## Security Considerations

* **Transaction Validation**: Always validate transaction contents before signing
* **Recipient Verification**: Verify recipient addresses to prevent sending to wrong addresses
* **Amount Validation**: Implement checks for transaction amounts to prevent accidental large transfers
* **Audit Logging**: Log all transaction signing operations for security auditing
* **Credential Storage**: Never log or expose wallet API keys or key shares
* **Rate Limiting**: Implement rate limiting to prevent abuse

## Common Use Cases

### Automated Payments

```typescript theme={"system"}
async function processAutomatedPayment(
  userId: string,
  recipient: string,
  amount: number
) {
  const credentials = await getDelegationCredentials(userId);

  const transaction = new Transaction().add(
    SystemProgram.transfer({
      fromPubkey: new PublicKey(credentials.publicKey),
      toPubkey: new PublicKey(recipient),
      lamports: amount,
    })
  );

  const { blockhash } = await connection.getLatestBlockhash();
  transaction.recentBlockhash = blockhash;
  transaction.feePayer = new PublicKey(credentials.publicKey);

  const signedTx = await delegatedSignTransaction(delegatedClient, {
    walletId: credentials.walletId,
    walletApiKey: credentials.walletApiKey,
    keyShare: credentials.keyShare,
    transaction,
  });

  return await connection.sendTransaction(signedTx);
}
```

### Batch Transactions

```typescript theme={"system"}
async function signMultipleTransactions(
  userId: string,
  transactions: Transaction[]
): Promise<Transaction[]> {
  const credentials = await getDelegationCredentials(userId);

  const signedTransactions = await Promise.all(
    transactions.map(transaction =>
      delegatedSignTransaction(delegatedClient, {
        walletId: credentials.walletId,
        walletApiKey: credentials.walletApiKey,
        keyShare: credentials.keyShare,
        transaction,
      })
    )
  );

  return signedTransactions;
}
```

## Related Functions

* [`createDelegatedSvmWalletClient()`](/node/reference/svm/create-delegated-svm-wallet-client) - Create the client for delegated operations
* [`delegatedSignMessage()`](/node/reference/svm/delegated-sign-message) - Sign messages instead of transactions
* [Sponsor Gas with Delegated Access (SVM)](/node/wallets/server-wallets/gas-sponsorship-svm) - Full guide on gasless transactions with a separate fee payer
