> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spark.money/llms.txt
> Use this file to discover all available pages before exploring further.

# Spark Signer Interface

export const Method = ({children, className = ""}) => {
  return <code className={`spark-method not-prose inline-block px-2 py-1 mt-12 text-sm font-mono font-semibold rounded-md border ${className}`}>
      {children}
    </code>;
};

The Spark SDK provides the `SparkSigner` interface to enable flexible implementation of signing operations. This abstraction allows you to customize how cryptographic operations are performed, enabling support for secure enclaves, hardware wallets, remote signing services, and other specialized key management systems.

<Info>
  The SDK includes `DefaultSparkSigner` which handles standard single-signature operations and stores nonces internally for security. For server-side enclave integrations, `UnsafeStatelessSparkSigner` is available.
</Info>

***

## Core Concepts

### Key Types

Spark wallets derive 5 key types from a master seed using BIP32:

| Path               | Key Type              | Purpose                                      |
| ------------------ | --------------------- | -------------------------------------------- |
| `m/8797555'/n'/0'` | Identity Key          | Primary wallet identifier and authentication |
| `m/8797555'/n'/1'` | Signing HD Key        | Base key for leaf key derivation             |
| `m/8797555'/n'/2'` | Deposit Key           | Receiving L1 Bitcoin deposits                |
| `m/8797555'/n'/3'` | Static Deposit HD Key | Reusable deposit addresses                   |
| `m/8797555'/n'/4'` | HTLC Preimage HD Key  | Lightning HTLC operations                    |

### The KeyDerivation System

The signer uses a discriminated union type to specify how to derive or retrieve a private key for signing operations:

```typescript theme={null}
enum KeyDerivationType {
  LEAF = "leaf",           // Derive from signing HD key using sha256(path)
  DEPOSIT = "deposit",     // Use the deposit key directly
  STATIC_DEPOSIT = "static_deposit",  // Use static deposit key at index
  ECIES = "ecies",         // Decrypt private key from ciphertext
  RANDOM = "random",       // Generate a random key (for adaptor signatures)
}

type KeyDerivation =
  | { type: KeyDerivationType.LEAF; path: string }
  | { type: KeyDerivationType.DEPOSIT }
  | { type: KeyDerivationType.RANDOM }
  | { type: KeyDerivationType.STATIC_DEPOSIT; path: number }
  | { type: KeyDerivationType.ECIES; path: Uint8Array };
```

This abstraction is used throughout the signer interface, particularly in `signFrost()` and `getPublicKeyFromDerivation()`.

### Security Model

* All private keys are derived from a master seed using BIP32 hierarchical deterministic key derivation
* Private keys never leave the signer. Only signatures and public keys are returned.
* `DefaultSparkSigner` stores nonces internally to prevent reuse attacks
* For enclave integrations, `UnsafeStatelessSparkSigner` exposes nonces externally

***

## Implementations

### DefaultSparkSigner

The recommended implementation for client-side applications. It stores signing nonces internally to prevent reuse attacks.

```typescript theme={null}
import { DefaultSparkSigner } from "@buildonspark/spark-sdk";

const signer = new DefaultSparkSigner();
const mnemonic = await signer.generateMnemonic();
const seed = await signer.mnemonicToSeed(mnemonic);
await signer.createSparkWalletFromSeed(seed, 0);
```

### UnsafeStatelessSparkSigner

For server-side enclave integrations where nonces need to be managed externally. This signer returns nonces in `getRandomSigningCommitment()` instead of storing them internally.

```typescript theme={null}
import { UnsafeStatelessSparkSigner } from "@buildonspark/spark-sdk";

// Only use in secure server environments
const signer = new UnsafeStatelessSparkSigner();
```

<Warning>
  `UnsafeStatelessSparkSigner` exposes nonces externally. Only use this in secure server environments where you can properly protect nonce data.
</Warning>

### Custom Signer Implementation

You can extend `DefaultSparkSigner` to implement custom signing logic, such as forwarding requests to a secure enclave:

```typescript theme={null}
import { DefaultSparkSigner, SignFrostParams } from "@buildonspark/spark-sdk";

class EnclaveSigner extends DefaultSparkSigner {
  private enclave: EnclaveClient;

  constructor(enclave: EnclaveClient) {
    super();
    this.enclave = enclave;
  }

  async signFrost(params: SignFrostParams): Promise<Uint8Array> {
    // Forward signing request to secure enclave
    return this.enclave.signFrost(params);
  }

  async createSparkWalletFromSeed(
    seed: Uint8Array | string,
    accountNumber?: number
  ): Promise<string> {
    // Initialize keys in enclave
    return this.enclave.initializeWallet(seed, accountNumber);
  }
}

// Use with SparkWallet
const { wallet } = await SparkWallet.initialize({
  signer: new EnclaveSigner(myEnclave),
  options: { network: "MAINNET" }
});
```

### Custom Key Derivation Paths

If you need a non-standard derivation scheme, you can pass a custom `sparkKeysGenerator` to `DefaultSparkSigner`.

This example shows a simple generator that replaces `?` with the `accountNumber` and then derives the five Spark key roots under that account:

```typescript theme={null}
import { DefaultSparkSigner, SparkValidationError } from "@buildonspark/spark-sdk";
import { HDKey } from "@scure/bip32";

class DerivationPathKeysGenerator {
  constructor(private readonly basePathTemplate: string) {}

  async deriveKeysFromSeed(seed: Uint8Array, accountNumber: number) {
    const hdkey = HDKey.fromMasterSeed(seed);

    const basePath = this.basePathTemplate.replace("?", String(accountNumber));
    const identityKey = hdkey.derive(`${basePath}/0'`);
    const signingKey = hdkey.derive(`${basePath}/1'`);
    const depositKey = hdkey.derive(`${basePath}/2'`);
    const staticDepositKey = hdkey.derive(`${basePath}/3'`);
    const htlcPreimageKey = hdkey.derive(`${basePath}/4'`);

    if (
      !identityKey.privateKey ||
      !identityKey.publicKey ||
      !signingKey.privateKey ||
      !signingKey.publicKey ||
      !depositKey.privateKey ||
      !depositKey.publicKey ||
      !staticDepositKey.privateKey ||
      !staticDepositKey.publicKey ||
      !htlcPreimageKey.privateKey ||
      !htlcPreimageKey.publicKey
    ) {
      throw new SparkValidationError("Failed to derive all required keys from seed");
    }

    return {
      identityKey: {
        privateKey: identityKey.privateKey,
        publicKey: identityKey.publicKey,
      },
      signingHDKey: {
        hdKey: signingKey,
        privateKey: signingKey.privateKey,
        publicKey: signingKey.publicKey,
      },
      depositKey: {
        privateKey: depositKey.privateKey,
        publicKey: depositKey.publicKey,
      },
      staticDepositHDKey: {
        hdKey: staticDepositKey,
        privateKey: staticDepositKey.privateKey,
        publicKey: staticDepositKey.publicKey,
      },
      HTLCPreimageHDKey: {
        hdKey: htlcPreimageKey,
        privateKey: htlcPreimageKey.privateKey,
        publicKey: htlcPreimageKey.publicKey,
      },
    };
  }
}

// Use ? as placeholder for account number
const customGenerator = new DerivationPathKeysGenerator("m/44'/0'/?'");

const signer = new DefaultSparkSigner({
  sparkKeysGenerator: customGenerator
});
```

***

## Wallet Initialization

### Generate Mnemonic

<Method>generateMnemonic()</Method>

Generates a new BIP39 mnemonic phrase for wallet creation.

```typescript theme={null}
const mnemonic = await signer.generateMnemonic();
console.log(mnemonic); // "abandon ability able about above absent..."
```

<Expandable title="Returns">
  <ResponseField name="mnemonic" type="Promise<string>" required>
    A 12-word BIP39 mnemonic phrase
  </ResponseField>
</Expandable>

### Convert Mnemonic to Seed

<Method>mnemonicToSeed(mnemonic)</Method>

Converts a BIP39 mnemonic phrase to a cryptographic seed.

```typescript theme={null}
const seed = await signer.mnemonicToSeed(mnemonic);
console.log("Seed length:", seed.length); // 64 bytes
```

<Expandable title="Parameters">
  <ResponseField name="mnemonic" type="string" required>
    Valid BIP39 mnemonic phrase
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="seed" type="Promise<Uint8Array>" required>
    64-byte seed derived from the mnemonic
  </ResponseField>
</Expandable>

### Initialize from Seed

<Method>createSparkWalletFromSeed(seed, accountNumber?)</Method>

Initializes the signer with a master seed and derives all necessary keys.

```typescript theme={null}
const seed = await signer.mnemonicToSeed(mnemonic);
const identityPubKey = await signer.createSparkWalletFromSeed(seed, 0);
console.log("Identity public key:", identityPubKey);
```

<Expandable title="Parameters">
  <ResponseField name="seed" type="Uint8Array | string" required>
    Master seed as bytes or hex string
  </ResponseField>

  <ResponseField name="accountNumber" type="number" required={false} default="0">
    Account index for key derivation. Defaults to 0 on REGTEST, 1 on MAINNET for backwards compatibility.
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="identityPubKey" type="Promise<string>" required>
    Hex-encoded identity public key
  </ResponseField>
</Expandable>

***

## Key Management

### Get Identity Public Key

<Method>getIdentityPublicKey()</Method>

Retrieves the wallet's identity public key.

```typescript theme={null}
const identityKey = await signer.getIdentityPublicKey();
console.log("Identity key:", identityKey);
```

<Expandable title="Returns">
  <ResponseField name="identityKey" type="Promise<Uint8Array>" required>
    The identity public key (33 bytes, compressed)
  </ResponseField>
</Expandable>

### Get Deposit Signing Key

<Method>getDepositSigningKey()</Method>

Retrieves the deposit signing public key used for L1 Bitcoin deposits.

```typescript theme={null}
const depositKey = await signer.getDepositSigningKey();
console.log("Deposit signing key:", depositKey);
```

<Expandable title="Returns">
  <ResponseField name="depositKey" type="Promise<Uint8Array>" required>
    The deposit signing public key
  </ResponseField>
</Expandable>

### Get Static Deposit Signing Key

<Method>getStaticDepositSigningKey(idx)</Method>

Retrieves a static deposit signing public key by index.

```typescript theme={null}
const signingKey = await signer.getStaticDepositSigningKey(0);
console.log("Static deposit signing key:", signingKey);
```

<Expandable title="Parameters">
  <ResponseField name="idx" type="number" required>
    Index for the static deposit key
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="signingKey" type="Promise<Uint8Array>" required>
    The static deposit signing public key
  </ResponseField>
</Expandable>

### Get Static Deposit Secret Key

<Method>getStaticDepositSecretKey(idx)</Method>

Retrieves a static deposit private key by index. Used when the private key needs to be shared with the SSP for static deposit flows.

```typescript theme={null}
const secretKey = await signer.getStaticDepositSecretKey(0);
```

<Expandable title="Parameters">
  <ResponseField name="idx" type="number" required>
    Index for the static deposit key
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="secretKey" type="Promise<Uint8Array>" required>
    The static deposit private key
  </ResponseField>
</Expandable>

### Get Public Key from Derivation

<Method>getPublicKeyFromDerivation(keyDerivation)</Method>

Derives a public key based on a `KeyDerivation` specification.

```typescript theme={null}
import { KeyDerivationType } from "@buildonspark/spark-sdk";

// Get public key for a leaf
const leafPubKey = await signer.getPublicKeyFromDerivation({
  type: KeyDerivationType.LEAF,
  path: "leaf-123"
});

// Get deposit public key
const depositPubKey = await signer.getPublicKeyFromDerivation({
  type: KeyDerivationType.DEPOSIT
});
```

<Expandable title="Parameters">
  <ResponseField name="keyDerivation" type="KeyDerivation" required>
    Specifies how to derive the key (LEAF, DEPOSIT, STATIC\_DEPOSIT, ECIES, or RANDOM)
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="publicKey" type="Promise<Uint8Array>" required>
    The derived public key
  </ResponseField>
</Expandable>

***

## Digital Signatures

### Sign with Identity Key

<Method>signMessageWithIdentityKey(message, compact?)</Method>

Signs a message using the wallet's identity key with ECDSA.

```typescript theme={null}
const message = new TextEncoder().encode("Hello, Spark!");
const signature = await signer.signMessageWithIdentityKey(message);
console.log("Signature:", signature);

// With compact format
const compactSignature = await signer.signMessageWithIdentityKey(message, true);
```

<Expandable title="Parameters">
  <ResponseField name="message" type="Uint8Array" required>
    Message to sign
  </ResponseField>

  <ResponseField name="compact" type="boolean" required={false} default="false">
    Use compact signature format instead of DER
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="signature" type="Promise<Uint8Array>" required>
    ECDSA signature (DER or compact format)
  </ResponseField>
</Expandable>

### Validate Signature

<Method>validateMessageWithIdentityKey(message, signature)</Method>

Validates an ECDSA signature against the identity key.

```typescript theme={null}
const message = new TextEncoder().encode("Hello, Spark!");
const signature = await signer.signMessageWithIdentityKey(message);
const isValid = await signer.validateMessageWithIdentityKey(message, signature);
console.log("Signature valid:", isValid);
```

<Expandable title="Parameters">
  <ResponseField name="message" type="Uint8Array" required>
    Original message
  </ResponseField>

  <ResponseField name="signature" type="Uint8Array" required>
    Signature to validate
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="isValid" type="Promise<boolean>" required>
    True if signature is valid
  </ResponseField>
</Expandable>

### Sign with Schnorr (Identity Key)

<Method>signSchnorrWithIdentityKey(message)</Method>

Creates a Schnorr signature using the identity key.

```typescript theme={null}
const message = new TextEncoder().encode("Hello, Spark!");
const schnorrSignature = await signer.signSchnorrWithIdentityKey(message);
console.log("Schnorr signature:", schnorrSignature);
```

<Expandable title="Parameters">
  <ResponseField name="message" type="Uint8Array" required>
    Message to sign
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="schnorrSignature" type="Promise<Uint8Array>" required>
    Schnorr signature (64 bytes)
  </ResponseField>
</Expandable>

### Sign Transaction Index

<Method>signTransactionIndex(tx, index, publicKey)</Method>

Signs a specific input of a Bitcoin transaction. The method looks up the private key based on the provided public key (must be either identity or deposit key).

```typescript theme={null}
import { Transaction } from "@scure/btc-signer";

const tx = new Transaction();
// ... build transaction ...

const identityKey = await signer.getIdentityPublicKey();
signer.signTransactionIndex(tx, 0, identityKey);
```

<Expandable title="Parameters">
  <ResponseField name="tx" type="Transaction" required>
    The Bitcoin transaction to sign (from @scure/btc-signer)
  </ResponseField>

  <ResponseField name="index" type="number" required>
    Input index to sign
  </ResponseField>

  <ResponseField name="publicKey" type="Uint8Array" required>
    Public key identifying which private key to use
  </ResponseField>
</Expandable>

***

## FROST Protocol (Threshold Signatures)

Spark uses FROST (Flexible Round-Optimized Schnorr Threshold) signatures for collaborative signing between users and Signing Operators.

### Get Random Signing Commitment

<Method>getRandomSigningCommitment()</Method>

Generates a random signing commitment for FROST protocol. In `DefaultSparkSigner`, the nonce is stored internally. In `UnsafeStatelessSparkSigner`, the nonce is returned in the response.

```typescript theme={null}
const commitment = await signer.getRandomSigningCommitment();
console.log("Commitment:", commitment.commitment);
// commitment.nonce is only present in UnsafeStatelessSparkSigner
```

<Expandable title="Returns">
  <ResponseField name="commitment" type="Promise<SigningCommitmentWithOptionalNonce>" required>
    Object containing the signing commitment, and optionally the nonce (for stateless signers)
  </ResponseField>
</Expandable>

### Get Nonce for Commitment

<Method>getNonceForSelfCommitment(selfCommitment)</Method>

Retrieves the nonce associated with a previously generated commitment. In `DefaultSparkSigner`, this looks up the internally stored nonce. In `UnsafeStatelessSparkSigner`, this returns the nonce from the commitment object.

```typescript theme={null}
const commitment = await signer.getRandomSigningCommitment();
const nonce = signer.getNonceForSelfCommitment(commitment);
```

<Expandable title="Parameters">
  <ResponseField name="selfCommitment" type="SigningCommitmentWithOptionalNonce" required>
    The commitment returned from getRandomSigningCommitment()
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="nonce" type="SigningNonce | undefined">
    The signing nonce, or undefined if not found
  </ResponseField>
</Expandable>

### FROST Signing

<Method>signFrost(params)</Method>

Performs FROST signing operation. This produces the user's signature share that will be combined with Signing Operator shares.

```typescript theme={null}
import { KeyDerivationType } from "@buildonspark/spark-sdk";

const commitment = await signer.getRandomSigningCommitment();

const params = {
  message: sighash,  // Transaction sighash to sign
  keyDerivation: { type: KeyDerivationType.LEAF, path: leafId },
  publicKey: leafPublicKey,
  verifyingKey: leaf.verifyingPublicKey,
  selfCommitment: commitment,
  statechainCommitments: soCommitments,  // From Signing Operators
  adaptorPubKey: undefined  // Optional adaptor for atomic swaps
};

const signatureShare = await signer.signFrost(params);
```

<Expandable title="Parameters">
  <ResponseField name="params" type="SignFrostParams" required>
    FROST signing parameters:

    * `message`: The message (sighash) to sign
    * `keyDerivation`: How to derive the signing key
    * `publicKey`: The user's public key for this leaf
    * `verifyingKey`: The aggregated public key (user + SOs)
    * `selfCommitment`: User's signing commitment
    * `statechainCommitments`: Signing Operators' commitments
    * `adaptorPubKey`: Optional adaptor public key
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="signatureShare" type="Promise<Uint8Array>" required>
    FROST signature share
  </ResponseField>
</Expandable>

### Aggregate FROST Signatures

<Method>aggregateFrost(params)</Method>

Aggregates FROST signature shares (user's + Signing Operators') into a final Schnorr signature.

```typescript theme={null}
const params = {
  message: sighash,
  publicKey: leafPublicKey,
  verifyingKey: leaf.verifyingPublicKey,
  selfCommitment: commitment,
  selfSignature: userSignatureShare,
  statechainCommitments: soCommitments,
  statechainSignatures: soSignatures,
  statechainPublicKeys: soPublicKeys
};

const finalSignature = await signer.aggregateFrost(params);
```

<Expandable title="Parameters">
  <ResponseField name="params" type="AggregateFrostParams" required>
    FROST aggregation parameters including all signature shares and public keys
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="finalSignature" type="Promise<Uint8Array>" required>
    Final aggregated Schnorr signature (64 bytes)
  </ResponseField>
</Expandable>

***

## Secret Sharing

These methods implement Shamir's Secret Sharing with verifiable proofs, used internally for key splitting operations.

### Split Secret with Proofs

<Method>splitSecretWithProofs(params)</Method>

Splits a secret into shares using Shamir's Secret Sharing with verifiable proofs.

```typescript theme={null}
const params = {
  secret: privateKey,
  curveOrder: secp256k1.CURVE.n,
  threshold: 3,
  numShares: 5
};

const shares = await signer.splitSecretWithProofs(params);
```

<Expandable title="Parameters">
  <ResponseField name="params" type="SplitSecretWithProofsParams" required>
    * `secret`: The secret to split (as Uint8Array)
    * `curveOrder`: The curve order (bigint)
    * `threshold`: Minimum shares needed to reconstruct
    * `numShares`: Total number of shares to generate
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="shares" type="Promise<VerifiableSecretShare[]>" required>
    Array of verifiable secret shares
  </ResponseField>
</Expandable>

### Subtract and Split with Proofs

<Method>subtractAndSplitSecretWithProofsGivenDerivations(params)</Method>

Subtracts two derived private keys and splits the result into verifiable shares. Used in transfer flows.

```typescript theme={null}
import { KeyDerivationType } from "@buildonspark/spark-sdk";

const shares = await signer.subtractAndSplitSecretWithProofsGivenDerivations({
  first: { type: KeyDerivationType.LEAF, path: "old-leaf" },
  second: { type: KeyDerivationType.LEAF, path: "new-leaf" },
  curveOrder: secp256k1.CURVE.n,
  threshold: 3,
  numShares: 5
});
```

### Subtract, Split, and Encrypt

<Method>subtractSplitAndEncrypt(params)</Method>

Subtracts keys, splits into shares, and encrypts the second key for the receiver. Used in transfer operations.

```typescript theme={null}
const result = await signer.subtractSplitAndEncrypt({
  first: { type: KeyDerivationType.LEAF, path: oldLeafId },
  second: { type: KeyDerivationType.LEAF, path: newLeafId },
  curveOrder: secp256k1.CURVE.n,
  threshold: 3,
  numShares: 5,
  receiverPublicKey: receiverIdentityKey
});

console.log(result.shares);       // Verifiable secret shares
console.log(result.secretCipher); // Encrypted key for receiver
```

***

## Encryption

### Decrypt ECIES

<Method>decryptEcies(ciphertext)</Method>

Decrypts ECIES-encrypted data using the identity key. Returns the public key corresponding to the decrypted private key.

```typescript theme={null}
const ciphertext = encryptedKeyFromSender;
const publicKey = await signer.decryptEcies(ciphertext);
```

<Expandable title="Parameters">
  <ResponseField name="ciphertext" type="Uint8Array" required>
    ECIES-encrypted private key
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="publicKey" type="Promise<Uint8Array>" required>
    Public key corresponding to the decrypted private key
  </ResponseField>
</Expandable>

***

## HTLC Operations

### Generate HTLC HMAC

<Method>htlcHMAC(transferID)</Method>

Generates an HMAC for HTLC (Hash Time-Locked Contract) operations using the HTLC preimage key.

```typescript theme={null}
const hmac = await signer.htlcHMAC(transferId);
```

<Expandable title="Parameters">
  <ResponseField name="transferID" type="string" required>
    The transfer ID to generate HMAC for
  </ResponseField>
</Expandable>

<Expandable title="Returns">
  <ResponseField name="hmac" type="Promise<Uint8Array>" required>
    HMAC output (32 bytes)
  </ResponseField>
</Expandable>

***

## Complete Example

```typescript theme={null}
import { 
  SparkWallet, 
  DefaultSparkSigner,
  KeyDerivationType 
} from "@buildonspark/spark-sdk";

async function demonstrateSparkSigner() {
  // 1. Create and initialize signer
  const signer = new DefaultSparkSigner();
  
  const mnemonic = await signer.generateMnemonic();
  console.log("Generated mnemonic:", mnemonic);

  const seed = await signer.mnemonicToSeed(mnemonic);
  const identityKeyHex = await signer.createSparkWalletFromSeed(seed, 0);
  console.log("Identity key:", identityKeyHex);

  // 2. Get keys
  const identityKey = await signer.getIdentityPublicKey();
  const depositKey = await signer.getDepositSigningKey();
  const staticDepositKey = await signer.getStaticDepositSigningKey(0);

  console.log("Keys initialized");

  // 3. Sign and validate a message
  const message = new TextEncoder().encode("Hello, Spark!");
  
  const signature = await signer.signMessageWithIdentityKey(message);
  const isValid = await signer.validateMessageWithIdentityKey(message, signature);
  console.log("Signature valid:", isValid);

  // 4. Schnorr signature
  const schnorrSig = await signer.signSchnorrWithIdentityKey(message);
  console.log("Schnorr signature length:", schnorrSig.length);

  // 5. Get public key from derivation
  const leafPubKey = await signer.getPublicKeyFromDerivation({
    type: KeyDerivationType.LEAF,
    path: "my-leaf-id"
  });
  console.log("Leaf public key:", leafPubKey);

  // 6. Use with SparkWallet
  const { wallet } = await SparkWallet.initialize({
    mnemonicOrSeed: mnemonic,
    accountNumber: 0,
    options: { network: "REGTEST" }
  });

  const address = await wallet.getSparkAddress();
  console.log("Spark address:", address);
}
```

***

## Integration Patterns

### Remote Signer (Enclave Pattern)

For wallet providers that need to keep keys in a secure enclave:

```typescript theme={null}
class RemoteSigner extends DefaultSparkSigner {
  private apiClient: EnclaveAPIClient;
  private userId: string;

  constructor(apiClient: EnclaveAPIClient, userId: string) {
    super();
    this.apiClient = apiClient;
    this.userId = userId;
  }

  async signFrost(params: SignFrostParams): Promise<Uint8Array> {
    // Forward to enclave
    return this.apiClient.signFrost(this.userId, params);
  }

  async aggregateFrost(params: AggregateFrostParams): Promise<Uint8Array> {
    return this.apiClient.aggregateFrost(this.userId, params);
  }

  async createSparkWalletFromSeed(
    seed: Uint8Array | string, 
    accountNumber?: number
  ): Promise<string> {
    // Keys are managed in the enclave
    return this.apiClient.initializeWallet(this.userId, seed, accountNumber);
  }
}
```

### Multi-User Wallet Pattern

For services managing wallets for multiple users:

```typescript theme={null}
class MultiUserSigner extends UnsafeStatelessSparkSigner {
  private keyStore: KeyStore;

  async signFrost(params: SignFrostParams): Promise<Uint8Array> {
    // Look up user's key material from secure storage
    const userKeys = await this.keyStore.getKeys(params.publicKey);
    
    // Perform signing with user's keys
    return super.signFrost({
      ...params,
      // Additional context if needed
    });
  }
}
```

<Note>
  For multi-user wallets, consider the trust model carefully. See the [Alby architecture blog post](https://getalby.com/blog/a-trust-minimized-multi-user-nwc-wallet-with-ark-spark) for a trust-minimized approach using NWC.
</Note>
