Extending FractaLedger

Extending FractaLedger

FractaLedger is designed to be highly extensible. This guide explains how to customize and extend the system to meet your specific requirements.

Overview

FractaLedger has been designed to be published as an npm package while allowing users to extend and customize it without modifying files in the node_modules directory. This is important because any changes to files in node_modules would be lost when updating the package.

The extension system follows these key principles:

  • Non-invasive: All customizations are made outside the node_modules directory
  • Template-based: CLI tools generate starter templates for your custom implementations
  • Configuration-driven: Your custom implementations are connected to the system through configuration
  • Modular: You can extend specific parts of the system without affecting others
Extension Architecture Diagram
┌─────────────────────────────────────────────────────────────┐
│                      Your Project                           │
│                                                             │
│  ┌───────────────┐    ┌───────────────┐    ┌──────────────┐ │
│  │ Custom        │    │ Custom API    │    │ Custom       │ │
│  │ Transceivers  │    │ Extensions    │    │ Chaincode    │ │
│  └───────────────┘    └───────────────┘    └──────────────┘ │
│                              │                              │
│                     ┌────────┴─────────┐                    │
│                     │  Configuration   │                    │
│                     └────────┬─────────┘                    │
│                              │                              │
└──────────────────────────────┼──────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                      node_modules                            │
│                                                             │
│  ┌───────────────┐    ┌───────────────┐    ┌──────────────┐ │
│  │ FractaLedger  │    │ Core          │    │ Extension    │ │
│  │ Core          │───▶│ Components    │───▶│ System       │ │
│  └───────────────┘    └───────────────┘    └──────────────┘ │
│                                                             │
└─────────────────────────────────────────────────────────────┘
      

Extension Process

Here's the step-by-step process to extend FractaLedger:

1

Install FractaLedger

npm install fractaledger
2

Initialize a New FractaLedger Project

npx fractaledger-init --dir my-fractaledger-project

This command creates a new project with the necessary directory structure and configuration files.

3

Navigate to Your Project Directory

cd my-fractaledger-project
4

Generate Custom Implementations

Use the provided CLI tools to generate templates for your custom implementations:

For Transceivers:
npx fractaledger-generate-transceiver --type bitcoin --output ./my-transceivers
For API Extensions:
npx fractaledger-generate-api-extension --type basic --output ./my-extensions --name my-custom-extension
For Configuration:
npx fractaledger-generate-config --output ./fractaledger.json
5

Customize the Generated Files

Edit the generated files to implement your specific business logic and requirements.

6

Update Your Configuration

Update your fractaledger.json file to point to your custom implementations:

{
  "bitcoin": [
    {
      "name": "btc_wallet_1",
      "network": "mainnet",
      "walletAddress": "bc1q...",
      "secretEnvVar": "BTC_WALLET_1_SECRET",
      "transceiver": {
        "method": "callback",
        "module": "./my-transceivers/bitcoin-transceiver.js",
        "config": {
          "apiUrl": "https://blockstream.info/api",
          "monitoringInterval": 60000
        }
      }
    }
  ],
  "api": {
    "port": 3000,
    "host": "localhost",
    "extensions": [
      {
        "module": "./my-extensions/my-custom-extension.js"
      }
    ]
  }
}

Extension Points

FractaLedger provides several extension points that allow you to customize the system to meet your specific requirements.

Transceivers

Transceivers handle blockchain interactions, including transaction broadcasting and wallet monitoring. They serve as the bridge between FractaLedger and the blockchain networks.

What You Can Customize

  • Transaction broadcasting logic
  • Wallet address monitoring
  • Balance retrieval
  • Transaction history retrieval
  • UTXO (Unspent Transaction Output) management
  • Blockchain API integration

How to Implement

Create a custom transceiver by implementing the UTXOTransceiver interface:

const { UTXOTransceiver } = require('fractaledger');

class MyCustomTransceiver extends UTXOTransceiver {
  constructor(config = {}) {
    super(config);
    
    // Initialize your transceiver
    this.apiUrl = config.apiUrl || 'https://your-blockchain-api.com';
    this.monitoringIntervals = {};
    this.processedTransactions = new Set();
  }
  
  async broadcastTransaction(txHex, metadata = {}) {
    // Implement transaction broadcasting logic
    // ...
    return { success: true, txid: '...' };
  }
  
  async startMonitoring(address, options = {}) {
    // Implement wallet monitoring logic
    // ...
    return { success: true };
  }
  
  async stopMonitoring(address) {
    // Implement logic to stop monitoring
    // ...
    return { success: true };
  }
  
  async getBalance(address) {
    // Implement balance retrieval logic
    // ...
    return 1.5; // Balance in BTC/LTC/etc.
  }
  
  async getTransactionHistory(address, options = {}) {
    // Implement transaction history retrieval
    // ...
    return []; // Array of transactions
  }
  
  async getUTXOs(address) {
    // Implement UTXO retrieval logic
    // ...
    return []; // Array of UTXOs
  }
}

module.exports = MyCustomTransceiver;

Configuration

In your fractaledger.json file, reference your custom transceiver:

"bitcoin": [
  {
    "name": "btc_wallet_1",
    "network": "mainnet",
    "walletAddress": "bc1q...",
    "secretEnvVar": "BTC_WALLET_1_SECRET",
    "transceiver": {
      "method": "callback",
      "module": "./my-transceivers/my-custom-transceiver.js",
      "config": {
        "apiUrl": "https://your-blockchain-api.com",
        "monitoringInterval": 60000
      }
    }
  }
]

API Extensions

API extensions allow you to add custom endpoints to the FractaLedger API server. This is useful for implementing domain-specific functionality or integrating with other systems.

What You Can Customize

  • Custom API endpoints
  • Domain-specific business logic
  • Integration with external systems
  • Custom authentication and authorization
  • Specialized data processing

How to Implement

Create a custom API extension:

/**
 * My Custom API Extension
 * 
 * This extension adds endpoints for a custom feature.
 */

/**
 * Register the custom extension with the API server
 * @param {Object} app The Express app instance
 * @param {Function} authenticateJWT The authentication middleware
 * @param {Object} dependencies Additional dependencies (walletManager, fabricClient, etc.)
 */
function registerMyExtension(app, authenticateJWT, dependencies) {
  const { walletManager, fabricClient } = dependencies;
  
  /**
   * Create a custom feature
   * POST /api/custom-feature
   */
  app.post('/api/custom-feature', authenticateJWT, async (req, res) => {
    try {
      const { name, config } = req.body;
      
      if (!name) {
        return res.status(400).json({ error: 'Missing required parameters' });
      }
      
      // Implement your custom logic here
      // ...
      
      res.json({ success: true, name, config });
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  });
  
  /**
   * Get custom features
   * GET /api/custom-features
   */
  app.get('/api/custom-features', authenticateJWT, async (req, res) => {
    try {
      // Implement your custom logic here
      // ...
      
      res.json([]);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  });
}

module.exports = registerMyExtension;

Configuration

In your fractaledger.json file, register your API extension:

"api": {
  "port": 3000,
  "host": "localhost",
  "extensions": [
    {
      "module": "./my-extensions/my-custom-extension.js"
    }
  ]
}

Chaincode (Smart Contracts)

Chaincode is the smart contract code that runs on the Hyperledger Fabric network. It defines the business logic for your FractaLedger application.

What You Can Customize

  • Fund distribution rules
  • Fee structures
  • Withdrawal logic
  • Transaction frequency controls
  • Custom business logic

How to Implement

Create a custom chaincode based on one of the provided templates:

  1. Create a directory for your custom chaincode:
    mkdir -p src/chaincode/custom/my-custom-chaincode
  2. Copy files from a template:
    cp -r src/chaincode/templates/merchant-fee/* src/chaincode/custom/my-custom-chaincode/
  3. Customize the chaincode files to implement your business logic.

Example of a custom chaincode implementation:

const { Contract } = require('fabric-contract-api');

class MyCustomContract extends Contract {
  async initLedger(ctx) {
    // Initialize the ledger
    // ...
  }
  
  async createInternalWallet(ctx, id, primaryWalletId, description, metadata) {
    // Create an internal wallet
    // ...
  }
  
  async internalTransfer(ctx, fromWalletId, toWalletId, amount, memo) {
    // Implement internal transfer logic
    // ...
  }
  
  async processCustomTransaction(ctx, fromWalletId, toWalletId, amount, customData) {
    // Implement your custom transaction logic
    // ...
  }
}

module.exports = MyCustomContract;

Configuration

In your fractaledger.json file, reference your custom chaincode:

"hyperledger": {
  "chaincodePath": "./src/chaincode/custom/my-custom-chaincode",
  "channelName": "fractaledger-channel",
  "chaincodeName": "fractaledger-chaincode"
}

Configuration

The configuration file (fractaledger.json) controls how FractaLedger connects to blockchains and manages wallets.

What You Can Customize

  • Blockchain connection details
  • Wallet configurations
  • Transceiver methods
  • Balance reconciliation settings
  • Base internal wallet settings
  • API server configuration

Example Configuration

Here's a comprehensive example of a fractaledger.json file:

{
  "bitcoin": [
    {
      "name": "btc_wallet_1",
      "network": "mainnet",
      "walletAddress": "bc1q...",
      "secretEnvVar": "BTC_WALLET_1_SECRET",
      "transceiver": {
        "method": "callback",
        "module": "./my-transceivers/bitcoin-transceiver.js",
        "config": {
          "apiUrl": "https://blockstream.info/api",
          "monitoringInterval": 60000,
          "autoMonitor": true
        }
      }
    }
  ],
  "api": {
    "port": 3000,
    "host": "localhost",
    "extensions": [
      {
        "module": "./my-extensions/my-custom-extension.js"
      }
    ]
  },
  "baseInternalWallet": {
    "namePrefix": "base_wallet_",
    "description": "Represents excess funds in the primary on-chain wallet",
    "createOnInitialization": true
  },
  "balanceReconciliation": {
    "strategy": "afterTransaction",
    "scheduledFrequency": 3600000,
    "warningThreshold": 0.00001,
    "strictMode": false
  }
}

Multiple Blockchain Support

FractaLedger is designed to support multiple UTXO-based blockchains simultaneously. You can create and configure transceivers for different blockchains like Bitcoin, Litecoin, and Dogecoin.

Setting Up Multiple Blockchain Transceivers

Generate transceiver implementations for each blockchain type:

# Generate Bitcoin transceiver
npx fractaledger-generate-transceiver --type bitcoin --output ./my-transceivers

# Generate Litecoin transceiver
npx fractaledger-generate-transceiver --type litecoin --output ./my-transceivers

# Generate Dogecoin transceiver
npx fractaledger-generate-transceiver --type dogecoin --output ./my-transceivers

This will create three separate transceiver files:

  • ./my-transceivers/bitcoin-transceiver.js
  • ./my-transceivers/litecoin-transceiver.js
  • ./my-transceivers/dogecoin-transceiver.js

Customizing Each Transceiver

Each generated file will be pre-configured with blockchain-specific settings:

  • Bitcoin transceiver will use https://blockstream.info/api as the default API URL
  • Litecoin transceiver will use https://ltc.bitaps.com/api/v1/blockchain
  • Dogecoin transceiver will use https://dogechain.info/api/v1

You'll need to customize each transceiver file to implement the specific logic needed for that blockchain, addressing differences in:

  • API endpoints and formats
  • Transaction structure and serialization
  • Address formats and validation
  • Fee calculation
  • Network-specific features

Configuration for Multiple Blockchains

In your fractaledger.json configuration file, reference each transceiver in the appropriate blockchain section:

{
  "bitcoin": [
    {
      "name": "btc_wallet_1",
      "network": "mainnet",
      "walletAddress": "bc1q...",
      "secretEnvVar": "BTC_WALLET_1_SECRET",
      "transceiver": {
        "method": "callback",
        "module": "./my-transceivers/bitcoin-transceiver.js",
        "config": {
          "apiUrl": "https://blockstream.info/api",
          "monitoringInterval": 60000,
          "autoMonitor": true
        }
      }
    }
  ],
  "litecoin": [
    {
      "name": "ltc_wallet_1",
      "network": "mainnet",
      "walletAddress": "ltc1q...",
      "secretEnvVar": "LTC_WALLET_1_SECRET",
      "transceiver": {
        "method": "callback",
        "module": "./my-transceivers/litecoin-transceiver.js",
        "config": {
          "apiUrl": "https://ltc.bitaps.com/api/v1/blockchain",
          "monitoringInterval": 60000,
          "autoMonitor": true
        }
      }
    }
  ],
  "dogecoin": [
    {
      "name": "doge_wallet_1",
      "network": "mainnet",
      "walletAddress": "D...",
      "secretEnvVar": "DOGE_WALLET_1_SECRET",
      "transceiver": {
        "method": "callback",
        "module": "./my-transceivers/dogecoin-transceiver.js",
        "config": {
          "apiUrl": "https://dogechain.info/api/v1",
          "monitoringInterval": 60000,
          "autoMonitor": true
        }
      }
    }
  ]
}

How It Works Internally

When FractaLedger starts up, it:

  1. Reads the configuration file
  2. For each blockchain section (bitcoin, litecoin, dogecoin), it loads the specified wallets
  3. For each wallet, it initializes the appropriate transceiver based on the configuration
  4. The transceiver manager maintains separate instances for each blockchain and wallet

This architecture allows FractaLedger to interact with multiple blockchains simultaneously, each with its own set of wallets and transceivers.

Wallet-Specific Business Logic

FractaLedger uses a specific architecture to handle wallet-specific business logic. Understanding this architecture is important for implementing custom business rules for different wallets.

Chaincode and Wallet Relationship

FractaLedger uses a single Hyperledger Fabric network with one deployed chaincode that handles all the business logic for the entire system. This chaincode is not directly linked to specific wallets on a one-to-one basis. Instead:

  • The chaincode contains the logic for all operations (transfers, fee calculations, etc.)
  • When operations are performed, the specific wallets involved are passed as parameters to the chaincode functions

This means you don't need to deploy separate chaincodes for each wallet. Rather, you customize a single chaincode that handles all your business logic, and that chaincode processes transactions for all wallets in the system.

API Extensions for Wallet-Specific Logic

To implement wallet-specific business logic, FractaLedger uses API Extensions. These extensions:

  • Add custom API endpoints to the system
  • Implement business logic that can be specific to certain wallets or wallet types
  • Call the appropriate chaincode functions with the right parameters

For example, in the merchant-fee-extension.js, you can see endpoints like:

  • /api/fee-config - For setting up fee configurations
  • /api/internal-wallets/:id/fund - For funding specific internal wallets
  • /api/transactions/merchant - For processing merchant transactions with specific wallets

Implementing Wallet-Specific Logic

To implement wallet-specific logic, you have two main options:

Option 1: Single Chaincode with Comprehensive Logic

Create a custom chaincode that includes logic for different wallet types, with functions that determine which logic to apply based on wallet metadata or transaction parameters.

// Example of a comprehensive chaincode function
async function processTransaction(ctx, fromWalletId, toWalletId, amount, transactionType) {
  if (transactionType === 'merchant') {
    // Apply merchant fee logic
    // ...
  } else if (transactionType === 'payroll') {
    // Apply payroll logic
    // ...
  }
  // ...
}

Option 2: Multiple Instances

Run separate FractaLedger instances, each with its own configuration, Hyperledger Fabric network, and deployed chaincode. This approach provides complete separation between different business domains but is more complex to manage.

Recommendation

For most use cases, Option 1 (single instance with comprehensive chaincode) is recommended because:

  • It's simpler to manage
  • It allows internal transfers between all wallets
  • It provides a unified view of all transactions
  • It's more resource-efficient

Only use Option 2 if you have strict separation requirements or vastly different business domains that cannot coexist in the same chaincode.

Best Practices

Follow these best practices when extending FractaLedger:

Keep Custom Files Outside node_modules

All customizations should be in your project directory, not in the node_modules directory. This ensures your customizations won't be lost when updating the package.

Use Relative Paths in Configuration

Your configuration file should point to your custom files using relative paths. This makes your project more portable and easier to deploy.

Follow the Provided Templates

Use the generated templates as a starting point for your customizations. They provide the correct structure and interface implementations.

Test Thoroughly

Make sure your custom implementations work correctly before deploying to production. FractaLedger provides testing utilities to help you test your customizations.

Implement Error Handling

Add proper error handling to your custom implementations. This helps with debugging and ensures your application can recover from failures.

Use Environment Variables for Secrets

Never hardcode sensitive information like API keys or private keys in your code. Use environment variables and reference them in your configuration.

Document Your Extensions

Add comments and documentation to your custom implementations. This helps other developers understand your code and makes maintenance easier.

Use Automatic Monitoring

When implementing custom transceivers, use the autoMonitor configuration option to automatically start monitoring wallet addresses when the system starts up.

Implement Reconnection Logic

When using real-time connections to blockchain nodes or services, implement robust reconnection logic to handle network interruptions.

Use Balance Reconciliation

Enable the balance reconciliation feature to ensure that your internal wallet balances stay in sync with the actual on-chain balances.