Step-by-step guide for integrating your Spark wallet with Dynamic
Recommended: JavaScript SDK with React Hooks
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) to get started.
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.
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 guide.
1
Implement the ISparkProvider Interface
Your wallet must implement the ISparkProvider interface. This interface defines all the methods Dynamic expects from a Spark wallet.
Your connector should extend SparkWalletConnector and implement the required overrides:
YourSparkConnector Implementation
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; }}
3
Test Your Integration
Before submitting, thoroughly test your integration:
Connection Testing - Verify wallet connects and disconnects properly
Address Retrieval - Ensure addresses are returned correctly
Message Signing - Test both regular and Taproot message signing
Transaction Testing - Test Bitcoin and token transfers
Error Handling - Verify proper error handling for all methods
The complete ISparkProvider interface specification:
ISparkProvider Interface
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;}