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

#  Sample Bitcoin Wallet Setup

> Create a sample Bitcoin wallet for testing and development purposes

This guide provides a complete implementation of a Bitcoin wallet for testing and development purposes.

## What You'll Accomplish

By the end of this step, you'll have:

* ✅ A complete Bitcoin wallet implementation for testing
* ✅ Support for P2TR (Taproot) address generation
* ✅ BIP322 message signing capabilities
* ✅ Mnemonic seed phrase management
* ✅ Integration with the Odin authentication flow

## Why Use a Sample Wallet?

For development and testing purposes, having a programmatic Bitcoin wallet allows you to:

* **Test Authentication Flows**: Quickly test your Odin integration without manual wallet interactions
* **Automated Testing**: Create automated test suites for your authentication logic
* **Development Environment**: Work in environments where external wallets may not be available
* **Educational Purposes**: Understand how Bitcoin wallets work under the hood

<Warning>
  This sample wallet is designed for **development and testing only**. Never use this code in production environments DYOR
</Warning>

## Install Required Dependencies

First, install the additional dependencies needed for the Bitcoin wallet implementation:

```bash theme={null}
npm install bip39 varuint-bitcoin @noble/secp256k1 @scure/bip32 @scure/bip39 @scure/btc-signer bip322-js
```

Add these to your package.json dependencies:

```js package.json theme={null}
"dependencies": {
    "@dfinity/agent": "^2.4.1",
    "@dfinity/candid": "^2.4.1",
    "@dfinity/identity": "^2.4.1",
    "@dfinity/principal": "^2.4.1",
    "axios": "^1.6.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.3.0",
    "bip322-js": "^3.0.0",
    "bip39": "^3.1.0",
    "varuint-bitcoin": "^1.1.2",
    "@noble/secp256k1": "^1.7.1",
    "@scure/bip32": "^1.7.0",
    "@scure/bip39": "^1.6.0",
    "@scure/btc-signer": "^1.8.0"
  }
```

## Sample Wallet Implementation

Here's a complete Bitcoin wallet implementation that supports P2TR (Taproot) addresses and BIP322 message signing:

```typescript sample-wallet.ts theme={null}
import * as bip32 from '@scure/bip32';
import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39';
import { wordlist } from '@scure/bip39/wordlists/english';
import * as btc from '@scure/btc-signer';
import { hex } from '@scure/base';
import * as sha2 from '@noble/hashes/sha2';
import { encode } from 'varuint-bitcoin';

const NETWORK = btc.NETWORK;
const DEFAULT_DERIVATION_PATH = "m/86'/0'/0'/0/0";

export type SampleWallet = {
  address: string;
  publicKey: string;
  privateKey: string;
  mnemonic: string;
  derivationPath: string;
  signMessage: (message: string) => Promise<string>;
};

/**
 * BIP0322 message hashing
 */
function bip0322Hash(message: string) {
  const tag = 'BIP0322-signed-message';
  const tagHash = sha2.sha256(Buffer.from(tag));
  const result = sha2.sha256(Buffer.concat([tagHash, tagHash, Buffer.from(message)]));
  return hex.encode(result);
}

/**
 * Encode variable-length string for BIP322
 */
function encodeVarString(b: Uint8Array) {
  return Buffer.concat([encode(b.byteLength), b]);
}

/**
 * Sign a message using BIP322 format (adapted from odin/utils/bip322.ts)
 */
async function signBip322MessageWithKey({
  message,
  privateKeyHex,
}: {
  message: string;
  privateKeyHex: string;
}): Promise<string> {
  const secp256k1 = await import('@noble/secp256k1');

  const privateKeyBytes = hex.decode(privateKeyHex);
  const publicKeyBytes = secp256k1.schnorr.getPublicKey(privateKeyBytes);

  const txScript = btc.p2tr(publicKeyBytes, undefined, NETWORK);

  const inputHash = hex.decode('0000000000000000000000000000000000000000000000000000000000000000');
  const txVersion = 0;
  const inputIndex = 4294967295;
  const sequence = 0;
  const scriptSig = btc.Script.encode(['OP_0', hex.decode(bip0322Hash(message))]);

  const txToSpend = new btc.Transaction({
    allowUnknownOutputs: true,
    version: txVersion,
  });
  txToSpend.addOutput({
    amount: BigInt(0),
    script: txScript.script,
  });
  txToSpend.addInput({
    txid: inputHash,
    index: inputIndex,
    sequence,
    finalScriptSig: scriptSig,
  });

  const txToSign = new btc.Transaction({
    allowUnknownOutputs: true,
    version: txVersion,
  });
  txToSign.addInput({
    txid: txToSpend.id,
    index: 0,
    sequence,
    tapInternalKey: publicKeyBytes,
    witnessUtxo: {
      script: txScript.script,
      amount: BigInt(0),
    },
    redeemScript: Buffer.alloc(0),
  });
  txToSign.addOutput({
    script: btc.Script.encode(['RETURN']),
    amount: BigInt(0),
  });

  txToSign.sign(privateKeyBytes);
  txToSign.finalize();

  const firstInput = txToSign.getInput(0);
  if (firstInput.finalScriptWitness?.length) {
    const len = encode(firstInput.finalScriptWitness?.length);
    const result = Buffer.concat([
      len,
      ...firstInput.finalScriptWitness.map(w => encodeVarString(w)),
    ]);
    return result.toString('base64');
  }
  return '';
}

/**
 * Generates P2TR (Taproot) address and keypair from a derived HDKey node
 */
async function getP2TRFromNode(node: bip32.HDKey) {
  const secp256k1 = await import('@noble/secp256k1');

  if (!node.privateKey) {
    throw new Error('HDKey node does not contain a private key.');
  }

  const privateKeyHex = hex.encode(node.privateKey);
  const publicKey = secp256k1.schnorr.getPublicKey(privateKeyHex);

  const p2tr = btc.p2tr(publicKey, undefined, NETWORK);

  return {
    p2tr,
    keyPair: {
      publicKey: hex.encode(publicKey),
      privateKey: privateKeyHex,
    },
  };
}

/**
 * Creates a master HDKey and derives a child HDKey using the provided derivation path
 */
function createHDNodeFromMnemonic(mnemonic: string, derivationPath: string) {
  if (!validateMnemonic(mnemonic, wordlist)) {
    throw new Error('Invalid mnemonic');
  }

  const seed = mnemonicToSeedSync(mnemonic);
  const masterNode = bip32.HDKey.fromMasterSeed(seed);
  const derivedNode = masterNode.derive(derivationPath);

  return { derivedNode, seedHex: Buffer.from(seed).toString('hex') };
}

/**
 * Creates a sample wallet for testing and examples
 * If mnemonic is not provided, a new one is generated
 */
export async function createSampleWallet(
  mnemonic?: string,
  derivationPath?: string
): Promise<SampleWallet> {
  const phrase = mnemonic || generateMnemonic(wordlist);
  const path = derivationPath || DEFAULT_DERIVATION_PATH;

  const { derivedNode } = createHDNodeFromMnemonic(phrase, path);
  const { p2tr, keyPair } = await getP2TRFromNode(derivedNode);

  const wallet: SampleWallet = {
    address: p2tr.address!,
    publicKey: keyPair.publicKey,
    privateKey: keyPair.privateKey,
    mnemonic: phrase,
    derivationPath: path,
    signMessage: async (message: string) => {
      return signBip322MessageWithKey({
        message,
        privateKeyHex: keyPair.privateKey,
      });
    },
  };

  return wallet;
}

/**
 * Create a sample wallet from an existing mnemonic
 */
export async function createSampleWalletFromMnemonic(
  mnemonic: string,
  derivationPath?: string
): Promise<SampleWallet> {
  return createSampleWallet(mnemonic, derivationPath);
}

/**
 * Generate a new mnemonic phrase
 */
export function generateSampleMnemonic(): string {
  return generateMnemonic(wordlist);
}

/**
 * Validate a mnemonic phrase
 */
export function validateSampleMnemonic(mnemonic: string): boolean {
  return validateMnemonic(mnemonic, wordlist);
}

```

## Understanding the Wallet Implementation

The sample wallet implementation includes several key components:

<AccordionGroup>
  <Accordion title="BIP322 Message Signing">
    Implements the BIP322 standard for Bitcoin message signing, which is required for Taproot (P2TR) addresses. This is more secure than legacy ECDSA signing.
  </Accordion>

  <Accordion title="HD Wallet Support">
    Uses BIP32 hierarchical deterministic (HD) wallet functionality to derive keys from a mnemonic seed phrase, following standard Bitcoin wallet patterns.
  </Accordion>

  <Accordion title="P2TR Address Generation">
    Creates Pay-to-Taproot (P2TR) addresses, which are the latest Bitcoin address format and provide enhanced privacy and functionality.
  </Accordion>

  <Accordion title="Mnemonic Management">
    Supports generating, validating, and importing mnemonic seed phrases using the BIP39 standard.
  </Accordion>
</AccordionGroup>

## Using the Sample Wallet

Here are some examples of how to use the sample wallet:

<Tabs>
  <Tab title="Generate New Wallet">
    ```typescript theme={null}
    import { createSampleWallet } from './sample-wallet';

    // Generate a new wallet with random mnemonic
    const wallet = await createSampleWallet();

    console.log({
      address: wallet.address,
      publicKey: wallet.publicKey,
      mnemonic: wallet.mnemonic
    });
    ```
  </Tab>

  <Tab title="Import from Mnemonic">
    ```typescript theme={null}
    import { createSampleWalletFromMnemonic } from './sample-wallet';

    // Import wallet from existing mnemonic
    const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
    const wallet = await createSampleWalletFromMnemonic(mnemonic);

    console.log('Imported wallet address:', wallet.address);
    ```
  </Tab>

  <Tab title="Sign Messages">
    ```typescript theme={null}
    import { createSampleWallet } from './sample-wallet';

    const wallet = await createSampleWallet();
    const message = "Hello, Odin!";
    const signature = await wallet.signMessage(message);

    console.log('Message signature:', signature);
    ```
  </Tab>
</Tabs>

## Security Best Practices

<Warning>
  **Development vs Production**

  * **Never use this sample wallet in production**: The private keys are generated programmatically and may not have sufficient entropy
  * **Secure mnemonic storage**: In production, use hardware wallets or secure key management systems
  * **Key rotation**: Regularly rotate keys and addresses in production environments
  * **Loss funds**: Do not send real funds to the generated address, you might lose them.
</Warning>

## Wallet Integration Summary

You now have a complete Bitcoin wallet implementation that:

* ✅ Generates secure P2TR (Taproot) addresses
* ✅ Supports BIP322 message signing
* ✅ Uses industry-standard HD wallet derivation
* ✅ Integrates seamlessly with Odin authentication
* ✅ Provides comprehensive testing capabilities

<Card title="Back to Welcome" icon="home" href="/welcome">
  Return to the main documentation to explore advanced features and API references
</Card>
