0.3.0 • Published 6 months ago

@ordchan/sdk v0.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

OrdChan SDK

npm version License: MIT

A TypeScript SDK for interacting with the OrdChan protocol - a decentralized messaging platform built on Bitcoin Ordinals.

Features

  • 🔍 Search & Discover - Find boards, threads, and replies
  • 📝 Content Creation - Create boards, threads, and replies
  • 🔔 Real-time Updates - Subscribe to new content via WebSockets
  • 👛 Wallet Integration - Built-in adapters for popular Bitcoin wallets (UniSat, OKX, Xverse)
  • 🔑 Direct Key Access - Use private keys or seed phrases without a browser extension
  • 🌍 Network Support - Works on both mainnet and testnet
  • 🏷️ Username Market - Buy, sell, and make offers on usernames
  • 📊 Voting System - Upvote/downvote content with satoshis
  • 🧰 Ordinals Processing - Extract and parse ordinals inscriptions from blocks and transactions
  • 🧩 Extensible Architecture - Easily add custom wallet adapters
  • 🔄 Transaction Access - Get raw transaction data from Bitcoin nodes or public APIs
  • 💱 NFT Marketplace - Buy and sell NFTs with our marketplace utilities (new in v0.3.0)
  • 🌐 Cross-Platform - Compatible with both browser and Node.js environments (new in v0.3.0)

Installation

npm install @ordchan/sdk

Or using Yarn:

yarn add @ordchan/sdk

Quick Start

import { OrdChanSDK, UniSatWalletAdapter, PrivateKeyWalletAdapter } from '@ordchan/sdk';

// Initialize the SDK
const sdk = new OrdChanSDK({
  apiUrl: 'https://api.ordchan.com'
});

// Connect wallet (choose one method)
const connectBrowserWallet = async () => {
  const wallet = new UniSatWalletAdapter();
  await wallet.connect();
  sdk.setWalletAdapter(wallet);
  console.log('Connected to browser wallet');
};

const connectWithSeedPhrase = async () => {
  const wallet = new PrivateKeyWalletAdapter({
    seedPhrase: 'your twelve or twenty four word mnemonic seed phrase',
    network: 'mainnet'
  });
  await wallet.connect();
  sdk.setWalletAdapter(wallet);
  console.log('Connected with seed phrase');
};

// Get all boards
const getBoards = async () => {
  const boards = await sdk.boards.getAll();
  console.log('Boards:', boards);
};

// Create a new thread
const createThread = async () => {
  const thread = await sdk.threads.create({
    board: 'bitcoin',
    title: 'Hello OrdChan',
    content: 'This is my first thread'
  });
  console.log('Created thread:', thread);
};

// Subscribe to new replies in a thread
const subscribeToReplies = (threadId) => {
  const unsubscribe = sdk.replies.subscribe(
    { threadId },
    (reply) => {
      console.log('New reply:', reply);
    }
  );
  
  // To stop listening later:
  // unsubscribe();
};

NFT Marketplace (New in v0.3.0)

The SDK includes a complete marketplace implementation for buying and selling NFTs on Bitcoin:

import { marketplace } from '@ordchan/sdk';
import { UniSatWalletAdapter, PrivateKeyWalletAdapter } from '@ordchan/sdk';

// Example 1: Sell an NFT by creating a listing
const sellNft = async () => {
  // Connect a wallet (browser extension or private key)
  const wallet = new PrivateKeyWalletAdapter({ 
    seedPhrase: 'your seed phrase here',
    network: 'bitcoin'
  });
  await wallet.connect();
  
  // Get seller's address
  const sellerAddress = await wallet.getAddress();
  
  // Find the UTXO containing the inscription
  const inscriptionId = '1d33f2a46047fbb366652d003d8049bbadc6e38062ce1b9b57408a2a5d4373a7i0';
  const inscriptionUtxo = await marketplace.utxo.findInscriptionUtxo(
    inscriptionId,
    sellerAddress,
    'bitcoin' // or 'fractal' for Fractal network
  );
  
  if (!inscriptionUtxo) {
    console.error('Inscription not found in this wallet');
    return;
  }
  
  // Create a listing PSBT
  const price = 10000; // 10,000 satoshis
  const listingPsbt = marketplace.psbt.createNftListingPsbt({
    inscriptionUtxo,
    sellerAddress,
    recipientAddress: sellerAddress, // Where to receive payment
    price,
    platformFeeAddress: 'bc1q...' // Optional: platform fee recipient
  });
  
  // Sign the listing PSBT with the wallet
  const privateKey = await wallet.getPrivateKey(); // Implementation depends on wallet
  const signedPsbt = marketplace.psbt.signNftSellerPsbt(listingPsbt, privateKey);
  
  console.log('Listing PSBT created and signed:');
  console.log(signedPsbt);
  
  // This PSBT can now be shared with potential buyers
  return signedPsbt;
};

// Example 2: Buy an NFT from a listing
const buyNft = async (listingPsbtHex) => {
  // Connect a wallet
  const wallet = new UniSatWalletAdapter();
  await wallet.connect();
  
  // Get buyer's address
  const buyerAddress = await wallet.getAddress();
  
  // Find payment UTXOs
  const utxos = await marketplace.utxo.findAllUtxos(buyerAddress, 'bitcoin');
  
  // Create buyer's PSBT
  const buyerPsbt = marketplace.psbt.createNftBuyerPsbt({
    sellerSignedPsbtHex: listingPsbtHex,
    buyerAddress,
    changeAddress: buyerAddress,
    paymentUtxos: utxos,
    feeRate: 5 // sats/byte
  });
  
  // Sign the buyer's PSBT
  const signedBuyerPsbt = await wallet.signPsbt(buyerPsbt);
  
  // Combine PSBTs
  const completePsbt = marketplace.psbt.combineNftPsbts(
    listingPsbtHex,
    signedBuyerPsbt
  );
  
  // Extract and broadcast the final transaction
  const txHex = marketplace.transaction.extractTransaction(completePsbt);
  if (txHex) {
    const result = await marketplace.transaction.broadcastTransaction(
      txHex,
      'bitcoin' // or 'fractal'
    );
    
    console.log('NFT purchase successful!');
    console.log('Transaction ID:', result.txid);
    console.log('Explorer URL:', marketplace.transaction.getExplorerUrl(result.txid, 'bitcoin'));
  }
};

Cross-Platform Compatibility (New in v0.3.0)

The SDK now works seamlessly in both browser and Node.js environments:

import { marketplace, wallet } from '@ordchan/sdk';

// Browser environment: Use a browser wallet
const useBrowserWallet = async () => {
  // This will only attempt to connect if running in a browser
  try {
    const walletAdapter = new wallet.UniSatWalletAdapter();
    await walletAdapter.connect();
    console.log('Connected to UniSat wallet');
    return walletAdapter;
  } catch (error) {
    console.error('Browser wallet not available:', error);
    return null;
  }
};

// Node.js environment: Use a private key or seed phrase
const usePrivateKeyWallet = async () => {
  const walletAdapter = new wallet.PrivateKeyWalletAdapter({
    seedPhrase: 'your seed phrase here',
    // or privateKey: 'your WIF private key',
    network: 'bitcoin'
  });
  await walletAdapter.connect();
  console.log('Connected with private key wallet');
  return walletAdapter;
};

// Works in both environments
const getWalletAdapter = async () => {
  // Try browser wallet first
  const browserWallet = await useBrowserWallet().catch(() => null);
  if (browserWallet) return browserWallet;
  
  // Fall back to private key wallet
  return await usePrivateKeyWallet();
};

UTXO Management (New in v0.3.0)

The SDK provides comprehensive UTXO utilities:

import { marketplace } from '@ordchan/sdk';

// Find UTXOs containing a specific inscription
const findInscription = async () => {
  const inscriptionId = '1d33f2a46047fbb366652d003d8049bbadc6e38062ce1b9b57408a2a5d4373a7i0';
  const address = 'bc1q...';
  const network = 'bitcoin'; // or 'fractal'
  
  const utxo = await marketplace.utxo.findInscriptionUtxo(
    inscriptionId,
    address,
    network
  );
  
  if (utxo) {
    console.log(`Inscription found in UTXO: ${utxo.txid}:${utxo.vout}`);
    console.log(`Value: ${utxo.value} sats`);
  } else {
    console.log('Inscription not found in this address');
  }
};

// Find all UTXOs for an address
const findAllUtxos = async () => {
  const address = 'bc1q...';
  const utxos = await marketplace.utxo.findAllUtxos(address, 'bitcoin');
  console.log(`Found ${utxos.length} UTXOs with total value: ${
    utxos.reduce((sum, u) => sum + u.value, 0)
  } sats`);
};

// Select UTXOs for a transaction
const selectUtxos = () => {
  const availableUtxos = [/* array of UTXOs */];
  const amountNeeded = 50000; // 50,000 sats
  const minUtxosNeeded = 2; // Need at least 2 UTXOs for placeholder inputs
  
  const selectedUtxos = marketplace.utxo.selectUtxosForPayment(
    availableUtxos,
    amountNeeded,
    minUtxosNeeded
  );
  
  console.log(`Selected ${selectedUtxos.length} UTXOs with value: ${
    selectedUtxos.reduce((sum, u) => sum + u.value, 0)
  } sats`);
};

// Create placeholder UTXOs for complex transactions
const createPlaceholderUtxos = async () => {
  const wallet = new wallet.PrivateKeyWalletAdapter({
    seedPhrase: 'your seed phrase here'
  });
  await wallet.connect();
  
  const address = await wallet.getAddress();
  const utxos = await marketplace.utxo.findAllUtxos(address);
  
  // Create multiple small UTXOs from a larger one
  const txid = await marketplace.transaction.createPlaceholderUtxos(
    utxos,
    address,
    wallet.getPrivateKey(),
    5, // number of UTXOs to create
    5000, // value of each UTXO (5,000 sats)
    5, // fee rate (sats/byte)
    'bitcoin' // network
  );
  
  console.log(`Created placeholder UTXOs in transaction: ${txid}`);
};

Transaction Handling (New in v0.3.0)

The SDK provides comprehensive transaction utilities:

import { marketplace } from '@ordchan/sdk';

// Broadcast a transaction
const broadcastTx = async () => {
  const txHex = '020000000001...'; // Transaction hex
  const network = 'bitcoin'; // or 'fractal'
  
  try {
    const result = await marketplace.transaction.broadcastTransaction(txHex, network);
    console.log('Transaction broadcast successful!');
    console.log('Transaction ID:', result.txid);
    
    // Get explorer URL
    const url = marketplace.transaction.getExplorerUrl(result.txid, network);
    console.log('View transaction:', url);
  } catch (error) {
    console.error('Broadcast failed:', error);
  }
};

// Sign a PSBT with a private key
const signPsbt = () => {
  const psbtHex = '70736274ff...'; // PSBT hex
  const privateKey = Buffer.from('...'); // Private key buffer
  
  // Optionally specify sighash types for each input
  const sighashTypes = [
    0x01, // SIGHASH_ALL for input 0
    0x81  // SIGHASH_SINGLE|ANYONECANPAY for input 1
  ];
  
  const signedPsbtHex = marketplace.transaction.signPsbt(
    psbtHex,
    privateKey,
    sighashTypes // optional
  );
  
  console.log('Signed PSBT:', signedPsbtHex);
};

// Extract a transaction from a PSBT
const extractTx = () => {
  const psbtHex = '70736274ff...'; // PSBT hex
  
  // Try to extract a complete transaction
  const txHex = marketplace.transaction.extractTransaction(psbtHex);
  
  if (txHex) {
    console.log('Extracted transaction:', txHex);
  } else {
    // Try with allowIncomplete=true for partially signed PSBTs
    const incompleteTxHex = marketplace.transaction.extractTransaction(psbtHex, true);
    console.log('Extracted incomplete transaction:', incompleteTxHex);
  }
};

// Calculate transaction fee
const calculateFee = () => {
  const txHex = '020000000001...'; // Transaction hex
  const feeRate = 5; // sats/byte
  
  const estimatedFee = marketplace.transaction.estimateTransactionFee(txHex, feeRate);
  console.log(`Estimated fee: ${estimatedFee} sats`);
};

Ordinals Processing

The SDK includes powerful utilities for processing Bitcoin blocks and transactions to extract ordinals inscriptions:

// Initialize the SDK
const sdk = new OrdChanSDK({
  apiUrl: 'https://api.ordchan.com'
});

// Process a Bitcoin block to extract all ordinals inscriptions
const processBlock = async () => {
  const blockHash = '000000000000000000076c036ff5119e5c5a633a9e8e5ba71b7ad89e52a0dcec'; // Block 800000
  const messages = await sdk.ordinals.processBlock(blockHash);
  console.log(`Found ${messages.length} ordinals in block`);
  
  // Filter to only OrdChan protocol messages
  const ordchanMessages = sdk.ordinals.filterByProtocol(messages, ['ordchan']);
  console.log(`Found ${ordchanMessages.length} OrdChan messages`);
};

// Process a single transaction to extract ordinals
const processTransaction = async () => {
  const txid = 'f34c43b1158de337e8e4f74d09256a574e865d8ab280926a0cd40d4e7aabf9a2';
  const messages = await sdk.ordinals.processTransaction(txid);
  console.log(`Found ${messages.length} inscriptions in transaction`);
};

// Process a transaction directly from its raw hex
const processTransactionHex = async () => {
  // Get transaction hex from anywhere (from wallet, API, or manual construction)
  const txHex = '020000000001018c57c91a45a44ba....'; // Transaction hex data
  
  // Process directly without needing to broadcast or have txid
  const { txid, ordinals } = await sdk.ordinals.processTransactionFromHex(txHex);
  console.log(`Transaction ID: ${txid}`);
  console.log(`Found ${ordinals.length} inscriptions in transaction hex`);
  
  // You can also provide optional block information if available
  const result = await sdk.ordinals.processTransactionFromHex(txHex, {
    blockInfo: {
      blockHeight: 800000,
      blockHash: '000000000000000000076c036ff5119e5c5a633a9e8e5ba71b7ad89e52a0dcec',
      timestamp: 1685341196
    }
  });
  console.log(`Transaction ${result.txid} has ${result.ordinals.length} inscriptions`);
};

// Extract a message from an inscription ID
const extractMessage = async () => {
  const inscriptionId = 'f34c43b1158de337e8e4f74d09256a574e865d8ab280926a0cd40d4e7aabf9a2i0';
  const content = await sdk.ordinals.extractMessage(inscriptionId);
  console.log('Inscription content:', content);
};

See ORDINALS_PROCESSING.md for more details.

Transaction Data Access

The SDK provides methods to retrieve raw Bitcoin transaction data from various sources:

// Initialize the SDK with Bitcoin RPC configuration (optional)
const sdk = new OrdChanSDK({
  apiUrl: 'https://api.ordchan.com',
  // Optionally configure Bitcoin RPC access
  bitcoinRpc: {
    host: 'localhost',
    port: 8332,
    user: 'username',
    password: 'password'
    // Alternatively, use a cookie file
    // cookieFile: '~/.bitcoin/.cookie'
  },
  // Optionally configure fallbacks and preferred data sources
  dataSourceConfig: {
    preferBlockstream: false, // Prefer blockstream.info API over RPC
    preferMempool: true,      // Prefer mempool.space API over RPC
    fallbackToPublicApis: true // Use public APIs if RPC fails
  }
});

// Get raw transaction hex
const getRawTx = async (txid) => {
  try {
    const txHex = await sdk.transactions.getRawTransactionHex(txid);
    console.log(`Transaction hex (${txHex.length / 2} bytes):`);
    console.log(txHex.substring(0, 100) + '...');
    
    // Parse the transaction
    const tx = bitcoin.Transaction.fromHex(txHex);
    console.log(`Transaction has ${tx.ins.length} inputs and ${tx.outs.length} outputs`);
    
    return txHex;
  } catch (error) {
    console.error('Failed to get transaction hex:', error);
  }
};

The SDK will automatically try multiple sources to get transaction data: 1. Local Bitcoin node (via RPC) if configured 2. mempool.space API 3. blockstream.info API 4. blockchain.info API 5. OrdChan API as a last resort

Documentation

For full API documentation, see the SDK Docs.

Examples

The repository includes several examples demonstrating how to use the SDK:

Version History

v0.3.0

  • Added comprehensive NFT marketplace functionality
  • Made wallet adapters compatible with both browser and Node.js
  • Added UTXO management utilities
  • Added transaction handling utilities
  • Fixed TypeScript compilation issues
  • Improved error handling and type safety

v0.2.3

  • Added ordinals processing utilities
  • Added transaction data access
  • Added username market functionality
  • Improved wallet adapters

v0.2.0

  • Initial public release
  • Basic board and thread functionality
  • Wallet integration

License

MIT

0.3.0

6 months ago

0.2.3

7 months ago

0.2.2

7 months ago

0.2.1

7 months ago

0.2.0

7 months ago

0.1.0

7 months ago