Skip to content

NickP005/ledger-mochimo

Repository files navigation

Ledger Mochimo

A TypeScript library for interfacing with Ledger hardware wallets to manage Mochimo cryptocurrency transactions. Supports both USB (WebHID) and Bluetooth (Web BLE) connections for web and mobile applications.

Features

  • 🔐 Secure Hardware Integration: Complete integration with Ledger hardware wallets
  • 🌐 Cross-Platform: Works on web browsers and mobile apps (via Capacitor)
  • 🔌 Multiple Connection Types: USB (WebHID) and Bluetooth (Web BLE) support
  • 📱 Mobile-Optimized: Advanced device discovery and selection for mobile workflows
  • WOTS+ Signatures: Full support for Mochimo's WOTS+ signature scheme
  • 🛡️ Input Validation: Robust validation of Mochimo reference formats and transaction limits
  • 📊 TypeScript: Full type safety and excellent developer experience
  • 🧪 Well Tested: Comprehensive test suite with 42+ test cases

Installation

npm install ledger-mochimo

Quick Reference Guide

Essential functions for Ledger Mochimo integration:

1. Connect to Device

const transport = new MochimoTransport();
await transport.connectAuto(); // Auto-detects USB/Bluetooth

2. Initialize App

const app = new MochimoApp(transport);

3. Generate Address

const address = await app.getAddress({ account: 0, addressIndex: 5 });

4. Prepare Transaction (Max 4 destinations)

const transaction = {
  bip32Path: { account: 0, addressIndex: 5 },
  destinations: [{ tag: addressHash, ref: 'PAYMENT', amount: 1000000000n }],
  sourceTotal: 1500000000n,
  feeTotal: 500000000n,
  nonce: 123456789n,
  blkToLive: 0n
};

5. Sign Transaction

const signature = await app.signTransactionComplete(transaction);

6. Discover Bluetooth Devices (Mobile)

const devices = await MochimoTransport.discoverDevices();
await transport.connectToDevice(devices[0]);

7. Handle Errors

try {
  await app.signTransactionComplete(transaction);
} catch (error) {
  if (error instanceof TransactionRejected) { /* User denied */ }
}

8. Validate References (Required format)

// ✅ Valid: 'ABC', '123', 'AB-12-CD'
// ❌ Invalid: 'abc', 'AB-CD', 'AB_12'

9. Check Platform Support

const hasUSB = MochimoTransport.isWebHIDSupported();
const hasBluetooth = MochimoTransport.isWebBLESupported();

10. Disconnect Safely

await transport.disconnect();

Quick Start

Basic Usage

import { MochimoApp, MochimoTransport } from 'ledger-mochimo';

// Create transport and app
const transport = new MochimoTransport();
const app = new MochimoApp(transport);

// Connect to device (auto-detects best transport)
await transport.connectAuto();

// Generate address
const address = await app.getAddress({
  account: 0,
  addressIndex: 5
});

console.log('Address:', address.addressHash);

Mobile Device Selection Workflow

import { MochimoApp, MochimoTransport } from 'ledger-mochimo';

// 1. Discover available devices
const devices = await MochimoTransport.discoverDevices();
console.log('Available devices:', devices);

// 2. Let user select device (implement your own UI)
const selectedDevice = devices[0]; // or show selection UI

// 3. Connect to selected device
const transport = new MochimoTransport();
await transport.connectToDevice(selectedDevice);

// 4. Create app instance
const app = new MochimoApp(transport);

Bluetooth Device Selection

// Show native browser device selection dialog
const device = await MochimoTransport.requestBluetoothDevice({
  allowAllDevices: false // Only show Ledger devices
});

if (device) {
  const transport = new MochimoTransport();
  await transport.connectToDevice(device);
}

Advanced Bluetooth Discovery

// Scan for devices with more control
const device = await MochimoTransport.discoverAndSelectBluetoothDevice({
  scanTime: 15000, // 15 seconds
  showUnknownDevices: false
});

Transaction Limits

The library enforces Mochimo's transaction limits:

  • Maximum 4 destinations per transaction (APDU limit)
  • Maximum 255 bytes per APDU command
  • Reference format validation (uppercase/digits/dashes only)
  • Sorted destinations required by protocol
// ✅ Valid transaction (up to 4 destinations)
const transaction = {
  bip32Path: { account: 0, addressIndex: 5 },
  destinations: [
    { tag: address1, ref: 'PAY-123', amount: 1000000000n },
    { tag: address2, ref: 'FEE-456', amount: 2000000000n },
    { tag: address3, ref: 'SEND-789', amount: 3000000000n },
    { tag: address4, ref: 'CHANGE-1', amount: 4000000000n }
  ],
  sourceTotal: 10200000000n,
  feeTotal: 200000000n,
  nonce: 123456789n,
  blkToLive: 0n
};

// ❌ Invalid - too many destinations
const invalidTransaction = {
  destinations: [dest1, dest2, dest3, dest4, dest5] // 5 destinations = error
};

Reference Format Validation

Mochimo references must follow specific rules:

// ✅ Valid references
'ABC'           // Uppercase letters only
'123'           // Digits only  
'AB-12-CD'      // Alternating groups
'XY-789-PQ'     // Mixed with proper alternation
''              // Empty reference

// ❌ Invalid references
'AB-CD'         // Consecutive letter groups
'12-34'         // Consecutive digit groups
'abc'           // Lowercase letters
'AB_12'         // Invalid characters
'-ABC'          // Starting with dash
'ABC-'          // Ending with dash

Mobile Integration Example

See examples/enhanced-mobile-integration.ts for a complete mobile implementation:

import { MochimoMobileIntegration, ReactNativeMochimoUI } from 'ledger-mochimo/examples';

const ui = new ReactNativeMochimoUI();
const mochimo = new MochimoMobileIntegration(ui);

// Complete setup workflow with device selection
const connected = await mochimo.setupLedgerConnection();
if (connected) {
  const address = await mochimo.generateAddress(0, 5);
  const signature = await mochimo.signTransaction(transaction);
}

API Reference

MochimoTransport

Connection management and device discovery.

// Static methods
MochimoTransport.discoverDevices(options?)
MochimoTransport.requestBluetoothDevice(options?)
MochimoTransport.discoverAndSelectBluetoothDevice(options?)
MochimoTransport.isWebHIDSupported()
MochimoTransport.isWebBLESupported()
MochimoTransport.getSupportedTransports()

// Instance methods
transport.connectAuto(options?)
transport.connectWebHID(options?)
transport.connectWebBLE(options?)
transport.connectToDevice(device, options?)
transport.disconnect()
transport.getStatus()

MochimoApp

Main application interface for Ledger operations.

// Address generation
app.getAddress(path: MochimoBIP32Path): Promise<MochimoAddress>

// Transaction signing (two-phase process)
app.signTransaction(transaction: MochimoTransaction): Promise<ApprovalResponse>
app.downloadSignature(totalChunks: number): Promise<SignatureResponse>

// Complete signing workflow
app.signTransactionComplete(transaction: MochimoTransaction): Promise<MochimoSignature>

// Static discovery methods
MochimoApp.discoverDevices(options?)
MochimoApp.requestBluetoothDevice(options?)

Types

Core Types

interface MochimoBIP32Path {
  account: number;        // Account number
  addressIndex: number;   // Address index
}

interface MochimoDestination {
  tag: Uint8Array;       // 20-byte address tag
  ref: string;           // Reference/memo (validated format)
  amount: bigint;        // Amount in nMCM
}

interface MochimoTransaction {
  bip32Path: MochimoBIP32Path;
  destinations: MochimoDestination[];  // Max 4 destinations
  sourceTotal: bigint;
  feeTotal: bigint;
  nonce: bigint;
  blkToLive: bigint;     // Must be 0
}

interface LedgerDeviceInfo {
  id: string;
  name: string;
  type: 'webhid' | 'webble';
  connected: boolean;
  bluetoothDevice?: any; // For Web BLE devices
}

Environment Support

Platform WebHID (USB) Web BLE (Bluetooth)
Chrome Desktop
Chrome Mobile
Safari Desktop
Safari Mobile
Capacitor iOS
Capacitor Android

Error Handling

The library provides specific error types:

import { 
  MochimoLedgerError, 
  AddressReuseWarning, 
  TransactionRejected 
} from 'ledger-mochimo';

try {
  await app.signTransaction(transaction);
} catch (error) {
  if (error instanceof TransactionRejected) {
    console.log('User rejected transaction');
  } else if (error instanceof AddressReuseWarning) {
    console.log('Address reuse warning - user must confirm');
  } else if (error instanceof MochimoLedgerError) {
    console.log('Ledger error:', error.message);
  }
}

Development

# Install dependencies
npm install

# Run tests  
npm test

# Build library
npm run build

# Lint code
npm run lint

Testing

The library includes comprehensive tests:

  • 42 test cases covering all functionality
  • Reference format validation tests
  • Transaction limit validation
  • Device discovery simulation
  • Error handling verification
npm test

Examples

  • examples/mobile-integration.ts - Basic mobile integration
  • examples/enhanced-mobile-integration.ts - Advanced mobile workflow with device selection
  • Mobile UI implementation examples for React Native

Protocol Details

BIP32 Path Format

m/44'/1027'/account'/0/address_index

  • Purpose: 44 (BIP44)
  • Coin Type: 1027 (Mochimo)
  • Account: User-defined account number
  • Change: Always 0 (external addresses)
  • Address Index: Address index within account

APDU Command Structure

Phase 1 - Address Generation (INS=0x05):
[CLA][INS][P1][P2][LC][BIP32_PATH]

Phase 2 - Transaction Signing (INS=0x06):  
[CLA][INS][P1][P2][LC][BIP32_PATH][TRANSACTION_DATA]

Phase 3 - Signature Download (INS=0x07):
[CLA][INS][P1][P2][LC][CHUNK_INDEX]

WOTS+ Signature Format

  • Signature length: 2144 bytes
  • Downloaded in chunks (max 255 bytes per APDU)
  • Requires 9+ chunks for complete signature

License

MIT License - see LICENSE file for details.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Security

This library handles cryptocurrency transactions and private key operations. Always:

  • Test thoroughly before production use
  • Validate all user inputs
  • Use hardware wallets for transaction signing
  • Keep the library updated

Support

  • GitHub Issues: Report bugs and feature requests
  • Documentation: Check examples and API reference
  • Mochimo Community: Join the Mochimo Discord/Telegram

API Reference

MochimoApp

Connection Management

// Connect with auto-detection
await app.connect();

// Connect with specific transport
await app.connect('webhid'); // USB
await app.connect('webble');  // Bluetooth

// Disconnect
await app.disconnect();

// Check connection status
const status = app.getConnectionStatus();

Address Generation

// Generate address silently
const address = await app.getAddress({
  account: 0,
  addressIndex: 5
}, false);

// Generate address with device verification
const verifiedAddress = await app.verifyAddress({
  account: 0,
  addressIndex: 5
});

// Get account tag (for wallet integration)
const accountTag = await app.getAccountTag(0);

Transaction Signing

// Complete transaction signing workflow
const signature = await app.signTransactionComplete({
  bip32Path: { account: 0, addressIndex: 5 },
  destinations: [{
    tag: destinationAddressHash,  // 20-byte Uint8Array
    ref: 'Payment memo',          // Max 15 characters
    amount: 1000000000n           // Amount in nMCM (bigint)
  }],
  sourceTotal: 2000000000n,       // Total available from UTXO
  feeTotal: 500000000n,           // Transaction fee
  nonce: 123456789n,              // Block number
  blkToLive: 0n                   // Must be 0 for Mochimo
});

console.log('Signature:', signature.signature); // 2144-byte WOTS+ signature

Advanced Transaction Signing

// Step-by-step signing for custom workflows
const approval = await app.signTransaction(transaction);
console.log('Transaction ID:', approval.transactionId);

const signatureData = await app.downloadSignature(
  approval.sessionInfo.totalChunks
);

Transport Management

import { MochimoTransport } from 'ledger-mochimo';

// Check supported transports
const supported = MochimoTransport.getSupportedTransports();
console.log('Supported:', supported); // ['webhid', 'webble']

// Manual transport management
const transport = new MochimoTransport();
await transport.connectWebHID(); // USB connection
await transport.connectWebBLE(); // Bluetooth connection

// Check device availability
const isAvailable = await MochimoTransport.isWebHIDDeviceAvailable();

Types

Core Types

interface MochimoBIP32Path {
  account: number;         // Account number (hardened)
  addressIndex: number;    // Address index within account
}

interface MochimoDestination {
  tag: Uint8Array;        // 20-byte address hash
  ref: string;            // Reference/memo (max 15 chars)
  amount: bigint;         // Amount in nMCM
}

interface MochimoTransaction {
  bip32Path: MochimoBIP32Path;
  destinations: MochimoDestination[];
  sourceTotal: bigint;    // Total UTXO amount
  feeTotal: bigint;       // Transaction fee
  nonce: bigint;          // Block number
  blkToLive: bigint;      // Must be 0
}

Response Types

interface MochimoAddress {
  addressHash: Uint8Array;  // 20-byte address hash
  addressIndex: number;     // Address index used
  pubSeed: Uint8Array;      // 32-byte WOTS+ public seed
  addrPartial: Uint8Array;  // 20-byte partial addr
}

interface MochimoSignature {
  signature: Uint8Array;    // 2144-byte WOTS+ signature
  transactionId: Uint8Array; // 32-byte transaction ID
  pubSeed: Uint8Array;      // 32-byte WOTS+ public seed
  addr: Uint8Array;         // 32-byte WOTS+ address
}

Protocol Details

BIP32 Path Structure

Mochimo uses the path structure: m/44'/1027'/account'/0/address_index

  • 44' - BIP44 purpose (hardened)
  • 1027' - Mochimo coin type (hardened)
  • account' - Account number (hardened)
  • 0 - Change index (always 0, non-hardened)
  • address_index - Address index (non-hardened)

Transaction Limits

  • Maximum destinations per APDU: 4 destinations
  • Maximum APDU size: 255 bytes
  • Signature size: 2144 bytes (WOTS+)
  • Chunk download: 9 chunks of max 240 bytes each

Address Types

  • Account Tag: Generated with address_index = 0, used for account identification
  • Address Hash: Generated with any address_index, used for transactions

Error Handling

import { 
  MochimoLedgerError,
  AddressReuseWarning,
  TransactionRejected 
} from 'ledger-mochimo';

try {
  const signature = await app.signTransactionComplete(transaction);
} catch (error) {
  if (error instanceof TransactionRejected) {
    console.log('User rejected the transaction');
  } else if (error instanceof AddressReuseWarning) {
    console.log('Address reuse warning - user must confirm');
  } else if (error instanceof MochimoLedgerError) {
    console.log('Ledger error:', error.message, 'Code:', error.code);
  }
}

Platform Support

Browser Support

  • Chrome/Chromium - Full WebHID and Web BLE support
  • Edge - Full WebHID and Web BLE support
  • ⚠️ Firefox - Limited Web BLE support
  • Safari - No WebHID/Web BLE support

Mobile Support (via Capacitor)

  • iOS - Bluetooth support via Web BLE
  • Android - Bluetooth support via Web BLE
  • USB connections - Not supported on mobile

Feature Detection

// Check what's supported in current environment
const capabilities = app.getCapabilities();
console.log('Supported transports:', capabilities.supportedTransports);

// Check specific features
const hasWebHID = MochimoTransport.isWebHIDSupported();
const hasWebBLE = MochimoTransport.isWebBLESupported();

Examples

Basic Wallet Integration

import { MochimoApp } from 'ledger-mochimo';

class MochimoWallet {
  private app: MochimoApp;

  constructor() {
    this.app = new MochimoApp();
  }

  async connect() {
    await this.app.connect();
  }

  async getAddresses(account: number, count: number) {
    const addresses = [];
    for (let i = 0; i < count; i++) {
      const addr = await this.app.getAddress({
        account,
        addressIndex: i
      });
      addresses.push(addr);
    }
    return addresses;
  }

  async sendTransaction(to: string, amount: bigint, fee: bigint) {
    // Implementation depends on your address format and UTXO management
    const transaction = {
      bip32Path: { account: 0, addressIndex: 0 },
      destinations: [{
        tag: hexToBytes(to), // Convert address to bytes
        ref: 'Payment',
        amount
      }],
      sourceTotal: amount + fee,
      feeTotal: fee,
      nonce: await this.getCurrentBlockNumber(),
      blkToLive: 0n
    };

    return await this.app.signTransactionComplete(transaction);
  }
}

Capacitor Mobile Integration

// capacitor.config.ts
import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  // Enable Bluetooth permissions
  plugins: {
    BluetoothLe: {
      displayStrings: {
        scanning: "Scanning for Ledger device...",
        cancel: "Cancel",
        connect: "Connect",
        connectedTo: "Connected to Ledger"
      }
    }
  }
};

// In your app
import { MochimoApp } from 'ledger-mochimo';

const app = new MochimoApp();

// Only Bluetooth is available on mobile
await app.connect('webble');

Development

# Install dependencies
npm install

# Build the library
npm run build

# Run tests
npm test

# Lint code
npm run lint

# Development mode (watch)
npm run dev

License

MIT

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support

Related Projects

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors