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

# Spark Wallet Integration Guide

> Step-by-step guide for integrating your Spark wallet with Dynamic

<Card title="Recommended: JavaScript SDK with React Hooks" icon="react" color="#4779FE">
  For new React apps, we recommend the JavaScript SDK with React Hooks (`@dynamic-labs-sdk/react-hooks`) instead of the legacy React SDK documented here. The JS SDK comes with many benefits such as a much smaller bundle size and other optimizations. Use the [React quickstart (JavaScript SDK)](/javascript/reference/react-quickstart) to get started.
</Card>

This guide walks you through integrating your Spark wallet with the Dynamic SDK. By implementing the `ISparkProvider` interface, your wallet will be compatible with Dynamic's Spark network support.

## Overview

To integrate your Spark wallet with Dynamic, you'll need to follow these steps:

For general information about custom wallet connectors, see our [Integrate your Wallet](/overview/wallets-and-chains/wallets#custom-wallet-connectors) guide.

<Steps>
  <Step title="Implement the ISparkProvider Interface">
    Your wallet must implement the `ISparkProvider` interface. This interface defines all the methods Dynamic expects from a Spark wallet.

    ### Required Methods

    * `connect()` - Establishes connection and returns the public key
    * `disconnect()` - Disconnects from the wallet
    * `getAddress()` - Retrieves the current wallet address
    * `signMessage()` - Signs messages for authentication
    * `signMessageWithTaproot()` - Signs messages using Taproot protocol
    * `transferBitcoin()` - Sends Bitcoin to other Spark addresses
    * `transferTokens()` - Transfers tokens between Spark addresses
    * `request()` - Handles generic RPC requests

    ### Example Implementation

    ```typescript title="Your Wallet Provider Implementation" theme={"system"}
    // This is what your wallet should implement
    class YourWalletProvider implements ISparkProvider {
      async connect(): Promise<string> {
        // Your wallet's connection logic
        const publicKey = await this.connectToWallet();
        this.isConnected = true;
        return publicKey;
      }

      async disconnect(): Promise<void> {
        await this.disconnectFromWallet();
        this.isConnected = false;
      }

      async getAddress(): Promise<string> {
        return await this.getWalletAddress();
      }

      async signMessage(message: string | SparkSignMessageRequest): Promise<SparkSignatureResult> {
        const messageText = typeof message === 'string' ? message : message.message;
        const isTaproot = typeof message === 'object' ? message.isTaproot : false;
        
        if (isTaproot) {
          const signature = await this.signMessageWithTaproot(messageText);
          return { signature };
        } else {
          const signature = await this.signMessageRegular(messageText);
          return { signature };
        }
      }

      async signMessageWithTaproot(message: string): Promise<SparkSignatureResult> {
        const signature = await this.signMessageWithTaproot(message);
        return { signature };
      }

      async transferBitcoin(params: {
        receiverSparkAddress: string;
        amountSats: bigint;
        isTaproot?: boolean;
      }): Promise<string> {
        return await this.sendBitcoin({
          to: params.receiverSparkAddress,
          amount: params.amountSats,
          useTaproot: params.isTaproot || false
        });
      }

      async transferTokens(params: {
        tokenPublicKey: string;
        receiverSparkAddress: string;
        tokenAmount: number;
        isTaproot?: boolean;
      }): Promise<string> {
        return await this.sendToken({
          tokenPublicKey: params.tokenPublicKey,
          to: params.receiverSparkAddress,
          amount: params.tokenAmount,
          useTaproot: params.isTaproot || false
        });
      }

      async request(method: string, params?: unknown): Promise<unknown> {
        return await this.handleRequest(method, params);
      }

      // Your wallet's internal methods
      private async connectToWallet(): Promise<string> { /* ... */ }
      private async disconnectFromWallet(): Promise<void> { /* ... */ }
      private async getWalletAddress(): Promise<string> { /* ... */ }
      private async signMessageRegular(message: string): Promise<string> { /* ... */ }
      private async sendBitcoin(params: any): Promise<string> { /* ... */ }
      private async sendToken(params: any): Promise<string> { /* ... */ }
      private async handleRequest(method: string, params?: unknown): Promise<unknown> { /* ... */ }
    }
    ```
  </Step>

  <Step title="Create a Custom Wallet Connector">
    Follow the process outlined in our [Custom Wallet Connectors](/overview/wallets-and-chains/wallets#custom-wallet-connectors) guide:

    1. Visit the [Dynamic Public Wallet Connectors repository](https://github.com/dynamic-labs/public-wallet-connectors)
    2. Follow the guidelines in the [CONTRIBUTING.md](https://github.com/dynamic-labs/public-wallet-connectors/blob/main/CONTRIBUTING.md) file
    3. Create your connector package following the established patterns

    ### Connector Structure

    Your connector should extend `SparkWalletConnector` and implement the required overrides:

    ```typescript title="YourSparkConnector Implementation" theme={"system"}
    import { SparkWalletConnector, type ISparkProvider } from '@dynamic-labs/spark';

    export class YourSparkConnector extends SparkWalletConnector {
      /**
       * The name of the wallet connector
       * @override Required override from the base connector class
       */
      override name = 'Your Wallet Name';

      /**
       * Unique identifier for your wallet
       * @override Required override from the base connector class
       */
      override overrideKey = 'yourwallet';

      /**
       * Whether the wallet can connect via custodial service
       * @override Optional override
       */
      override canConnectViaCustodialService = false;

      /**
       * The constructor for the connector, with the relevant metadata
       * @param props The options for the connector
       */
      constructor(props: any) {
        super({
          ...props,
          metadata: {
            id: 'yourwallet',
            name: 'Your Wallet Name',
            icon: 'https://your-wallet.com/icon.png',
          },
        });
      }

      /**
       * Returns the wallet provider instance
       * @override Required override from the base connector class
       */
      public override getProvider(): ISparkProvider | undefined {
        return window.yourWalletProvider;
      }
    }
    ```
  </Step>

  <Step title="Test Your Integration">
    Before submitting, thoroughly test your integration:

    1. **Connection Testing** - Verify wallet connects and disconnects properly
    2. **Address Retrieval** - Ensure addresses are returned correctly
    3. **Message Signing** - Test both regular and Taproot message signing
    4. **Transaction Testing** - Test Bitcoin and token transfers
    5. **Error Handling** - Verify proper error handling for all methods
  </Step>

  <Step title="Submit Your Connector">
    Once your implementation is complete and tested:

    1. Submit your connector following the [Custom Wallet Connectors](/overview/wallets-and-chains/wallets#custom-wallet-connectors) process
    2. Fill out the submission form to get allowlisted
    3. Our team will review and integrate your connector
  </Step>
</Steps>

## Supported Networks

| Network     | Chain ID | Description        | Block Explorer                         |
| ----------- | -------- | ------------------ | -------------------------------------- |
| **Mainnet** | 301      | Production network | [mempool.space](https://mempool.space) |

> **Note**: Currently only mainnet is supported. Testnet, signet, and regtest support may be added in future versions.

## Reference: ISparkProvider Interface

The complete `ISparkProvider` interface specification:

```typescript title="ISparkProvider Interface" theme={"system"}
interface ISparkProvider {
  /** Whether the wallet is currently connected */
  isConnected: boolean;

  /** The current network chain ID (e.g., '301' for mainnet) */
  chainId?: string;

  /** The current network name (e.g., 'mainnet', 'testnet') */
  network?: string;

  /**
   * Establishes a connection to the wallet
   * @returns Promise resolving to the public key (string)
   */
  connect(): Promise<string>;

  /**
   * Disconnects from the wallet
   * @returns Promise that resolves when disconnected
   */
  disconnect(): Promise<void>;

  /**
   * Retrieves the current wallet address
   * @returns Promise resolving to address information
   */
  getAddress(): Promise<SparkAddressResult>;

  /**
   * Signs a message for authentication
   * @param message - Message to sign or signing request object
   * @returns Promise resolving to signature result
   */
  signMessage(
    message: string | SparkSignMessageRequest,
  ): Promise<SparkSignatureResult>;

  /**
   * Signs a message using Taproot protocol
   * @param message - Message to sign
   * @returns Promise resolving to signature result
   */
  signMessageWithTaproot(message: string): Promise<SparkSignatureResult>;

  /**
   * Transfers Bitcoin to another Spark address
   * @param params - Transfer parameters
   * @param params.receiverSparkAddress - The recipient's Spark address
   * @param params.amountSats - Amount to transfer in satoshis
   * @param params.isTaproot - Whether to use Taproot (defaults to false)
   * @returns Promise resolving to transaction hash
   */
  transferBitcoin(params: {
    receiverSparkAddress: string;
    amountSats: bigint;
    isTaproot?: boolean;
  }): Promise<string>;

  /**
   * Transfers tokens to another Spark address
   * @param params - Transfer parameters
   * @param params.tokenPublicKey - The token's public key
   * @param params.receiverSparkAddress - The recipient's Spark address
   * @param params.tokenAmount - Amount of tokens to transfer
   * @param params.isTaproot - Whether to use Taproot (defaults to false)
   * @returns Promise resolving to transaction hash
   */
  transferTokens(params: {
    tokenPublicKey: string;
    receiverSparkAddress: string;
    tokenAmount: number;
    isTaproot?: boolean;
  }): Promise<string>;

  /**
   * Generic RPC method for custom requests
   * @param method - The RPC method name
   * @param params - Optional parameters for the method
   * @returns Promise resolving to the method result
   */
  request(method: string, params?: unknown): Promise<unknown>;

  // Allow any additional properties for flexibility
  /** Additional properties that providers may implement */
  [key: string]: unknown;
}
```

## Reference: Type Definitions

```typescript title="Spark Type Definitions" theme={"system"}
/**
 * Result from address retrieval, supporting different formats
 */
type SparkAddressResult = string;

/**
 * Message signing request, supporting both simple and advanced options
 */
type SparkSignMessageRequest =
  | {
      message: string;
      isTaproot?: boolean; // defaults to false
    }
  | string;

/**
 * Result from message signing, supporting different return formats
 */
type SparkSignatureResult =
  | {
      signature: string;
    }
  | string;
```
