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

# signTransaction

> Signs an SVM transaction using the specified wallet

## Function Signature

```typescript theme={"system"}
signTransaction(params: {
  walletMetadata: WalletMetadata;
  transaction: VersionedTransaction | Transaction | string;
  password?: string;
  externalServerKeyShares?: ServerKeyShare[];
  sponsor?: boolean;
}): Promise<string>
```

## Description

Signs an SVM transaction using the wallet identified by the supplied `walletMetadata`. The SDK is stateless — every call requires `walletMetadata`. Accepts a `Transaction`, `VersionedTransaction`, or hex string. Optionally requests gas sponsorship from Dynamic before signing.

<Warning>
  When you pass `externalServerKeyShares` (the caller-supplied path), `walletMetadata.externalServerKeySharesBackupInfo` must also be present — `signTransaction` throws if shares are supplied but backup metadata is missing. The full `walletMetadata` returned from `createWalletAccount` / `importPrivateKey` already includes it; identity-only metadata from `fetchWalletMetadata` will be rejected.
</Warning>

## Parameters

### Required Parameters

* **`walletMetadata`** ([`WalletMetadata`](/node/reference/types/wallet-metadata)) - Non-sensitive wallet metadata persisted from `createWalletAccount()` / `importPrivateKey()`. The signer address comes from `walletMetadata.accountAddress`.
* **`transaction`** (`VersionedTransaction | Transaction | string`) - The transaction to sign

### Optional Parameters

* **`password`** (`string`) - Required if the wallet was created with `backUpToDynamic: true`.
* **`externalServerKeyShares`** ([`ServerKeyShare[]`](/node/reference/types/server-key-share)) - Caller-supplied plaintext shares.
* **`sponsor`** (`boolean`) - If `true`, requests gas sponsorship from Dynamic before signing. Requires a `Transaction` or `VersionedTransaction` (not a hex string).

## Returns

* **`Promise<string>`** - A **base58-encoded Ed25519 signature** — exactly 88 characters, which decodes to 64 bytes.

<Warning>
  **This is the raw signature only, not the full signed transaction.**

  Verified return format:

  ```
  typeof: string
  length: 88 characters
  decoded bytes: 64  (Ed25519 signature)
  example: "5pkf7k6nDCtoohetqdWoMCJS9Vd..."
  ```

  Calling `VersionedTransaction.deserialize()` on the decoded bytes will throw "Reached end of buffer unexpectedly" — confirming the 64 bytes are a signature, not a serialized transaction.

  To broadcast: decode the signature and add it back to the transaction using `decodeBase58` and `addSignatureToTransaction` from `@dynamic-labs-wallet/node-svm`, then call `connection.sendRawTransaction(signedTx.serialize())`. See the example below.

  Passing the string directly to `connection.sendRawTransaction()` or the SDK's `sendTransaction()` will fail — `Buffer.from(base58string)` interprets the characters as UTF-8 bytes (not the decoded signature), producing a garbled payload.
</Warning>

## Example

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

const svmClient = await authenticatedSvmClient();

const walletMetadata = JSON.parse(await redis.get(`wallet:${accountAddress}`));
const externalServerKeyShares = await vault.read(`wallet:${accountAddress}/shares`);

const connection = new Connection(
  process.env.SOLANA_RPC_URL ?? 'https://api.mainnet-beta.solana.com',
  'confirmed'
);
const { blockhash } = await connection.getLatestBlockhash();

const transaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(walletMetadata.accountAddress),
    toPubkey: new PublicKey('11111111111111111111111111111112'),
    lamports: LAMPORTS_PER_SOL * 0.001,
  })
);
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(walletMetadata.accountAddress);

// Returns base58 signature (64 bytes), NOT the full signed transaction
const signatureBase58 = await svmClient.signTransaction({
  walletMetadata,
  externalServerKeyShares,
  transaction,
  password: 'user-password',
});

// Decode and attach the signature before broadcasting
const signatureBytes = decodeBase58(signatureBase58);
const signedTx = addSignatureToTransaction({
  transaction,
  signature: signatureBytes,
  signerPublicKey: new PublicKey(walletMetadata.accountAddress),
});

const txid = await connection.sendRawTransaction(signedTx.serialize());
await connection.confirmTransaction(txid, 'confirmed');
console.log('Transaction confirmed:', txid);
```

### With Gas Sponsorship

Pass `sponsor: true` to have Dynamic sponsor the transaction fees. Gas sponsorship must be enabled in the Dynamic dashboard.

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

const svmClient = await authenticatedSvmClient();

const walletMetadata = JSON.parse(await redis.get(`wallet:${accountAddress}`));
const externalServerKeyShares = await vault.read(`wallet:${accountAddress}/shares`);

const connection = new Connection(
  process.env.SOLANA_RPC_URL ?? 'https://api.mainnet-beta.solana.com',
  'confirmed'
);
const { blockhash } = await connection.getLatestBlockhash();

const transaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: new PublicKey(walletMetadata.accountAddress),
    toPubkey: new PublicKey('11111111111111111111111111111112'),
    lamports: LAMPORTS_PER_SOL * 0.001,
  })
);
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(walletMetadata.accountAddress);

// sponsor: true replaces the fee payer with the Dynamic sponsor
const signatureBase58 = await svmClient.signTransaction({
  walletMetadata,
  externalServerKeyShares,
  transaction,
  password: 'user-password',
  sponsor: true,
});

const signatureBytes = decodeBase58(signatureBase58);
const signedTx = addSignatureToTransaction({
  transaction,
  signature: signatureBytes,
  signerPublicKey: new PublicKey(walletMetadata.accountAddress),
});

const txid = await connection.sendRawTransaction(signedTx.serialize());
await connection.confirmTransaction(txid, 'confirmed');
console.log('Sponsored transaction confirmed:', txid);
```

## Related

* [`WalletMetadata`](/node/reference/types/wallet-metadata) - The metadata object passed to every operation
* [`signMessage()`](/node/reference/svm/sign-message) - Sign a message instead of a transaction
* [`sponsorTransaction()`](/node/reference/svm/sponsor-transaction) - Sponsor a transaction separately for manual control
* [`createWalletAccount()`](/node/reference/svm/create-wallet-account) - Create a new wallet account
* [Sign SVM Transactions guide](/node/svm/sign-transactions) - Full guide including VersionedTransaction and Checkout API patterns
