Skip to content

Bitcoin CashTemplates

For Dapp and Wallet Development

LibCash

Note

DANGER

This is a preview release to get developer feedback and (hopefully) identify any gaps in the current specification. CashConnect is still under development and IS NOT yet safe for Production use.

Introduction

CashConnect is a lightweight templating system that aims to provide a versatile and secure interface for Dapp <-> Wallet communications on Bitcoin Cash.

These templates are serializable to JSON and use CashASM to give them advanced scripting capabilities. They have a structure as follows:

ts
{
  name: 'Example Template',
  description: 'This is an example template',
  actions: {
    // ... methods that can be invoked.
  },
  scripts: {
    // ... global scripts that are re-used by Actions.
    //     E.g. Lock/Unlock scripts.
  }
}
Details

At their bare-minimum, Actions have params (data-in), instructions (processes) and returns (data-out). In this sense, they operate like a function with instructions being a pipeline of operations that should be performed (usually, by the wallet). This pipeline-esque approach allows templates to generalize to many use-cases that might otherwise be difficult to formalize into a fixed schema.

A very simple send action may look like so:

ts
{
  //...
  actions: {
    // A very simple send action that pays a given sats amount to the provided address
    send: {
      params: {
        receivingAddress: Vars.address('Receiving Address'),
        sats: Vars.number('Sats to send'),
      },
      instructions: [
        Instructions.transaction({
          name: 'tx',
          // Use any available UTXOs from parent wallet.
          inputs: ['*'],
          outputs: [
            {
              lockingBytecode: expr`receivingAddress`,
              valueSatoshis: expr`sats`,
            },
            // Append change outputs to parent wallet.
            '*',
          ]
        })
      ],
      returns: {
        txHash: Vars.transactionHash('Resulting Tx Hash'),
      }
    }
  }
}

And then executed as follows:

ts
// ... Instantiate template instance.

// Execute the send action.
const sendResult = templateInstance.executeAction('send', {
  receivingAddress: Address.from('bitcoincash:...').toLockscriptBytes(),
  sats: Satoshis.fromBCH('0.01').toBigInt(),
});

// The returned data (e.g. for DB persistence) is available under:
// sendResult.data;

// Broadcast the resulting transaction(s).
await blockchain.broadcastTransactions(sendResult.transactions);

To ease development and testing of templates, Tooling is provided under a cashconnect-js/templates-dev package.

// Import TestEnv and Example Template from our Templates-Dev package.
import { TestEnv, TemplateDataStore } from '@cashconnect-js/templates-dev';

// Import some primitive tooling for convenience.
import { Bytes } from '@cashconnect-js/core/primitives';

// Instantiate a Test Environment.
const testEnv = await TestEnv.from(TemplateDataStore);

// Create a Test Wallet and Template Instance belonging to the Wallet.
const { wallet: testWallet, templateInstance: walletTemplateInstance } = await testEnv.createWalletP2PKH({
    // Load the Wallet with 1 BCH.
    satsBalance: 100_000_000n
});

// Execute the Store Action on our Wallet's Template Instance.
const storeResult = await walletTemplateInstance.executeAction('store', {
    data: Bytes.fromUtf8('Because we are storing data on an input, this can be up to nearly 10,000 bytes long!')
});

// Broadcast the transaction(s) using our Mock Blockchain.
await testEnv.blockchain.broadcastTransactions(storeResult.transactions);

// Get the new balance of the Wallet.
const balance = await testWallet.getBalanceSats();

// Print it to the console.
console.log('New Balance', balance);

INFO

The recommended approach ...

Once written, Templates can then be leveraged in Bitcoin Cash Dapps (using WalletConnect as a transport) like so:

// Import a console-based UI for CashConnect.
// NOTE: A Vanilla-JS implementation will also be provided in future for easy, (hopefully) no-fuss, integration into Dapps.
import { CashConnectDappConsole } from '@cashconnect-js/dapp';

// Import an example template and a Blockchain Adapter.
import { BlockchainElectrum, TemplateDataStore } from '@cashconnect-js/templates-dev';

// Import some convenience primitives.
import { Bytes } from '@cashconnect-js/core/primitives';

// Instantiate a Blockchain Connection using a Fulcrum Chipnet Server.
// NOTE: ONLY use Chipnet until V1.0 release.
const blockchain = await BlockchainElectrum.from({
    servers: ['chipnet.imaginary.cash'],
});

// Instantiate our CashConnect Dapp (using Chipnet).
const dapp = await CashConnectDappConsole.from(TemplateDataStore, 'bch:bchtest');

// Request a session with the wallet.
await dapp.newSession();

// Execute the store action on our template.
const storeResult = await dapp.executeAction('store', {
    // This data stores data in an input - so we are not bound by OP_RETURN-like limits (we have ~10,000 bytes to play with!)
    data: Bytes.generateRandom(800),
});

// NOTE: This interface is too clunky and will likely be amended to throw a specific error type on "CANCELLED" instead.
if(storeResult !== 'CANCELLED') {
    // Show data returned by the action.
    console.log('returned', storeResult.data);

    // Broadcast the transactions to the blockchain.
    await blockchain.broadcastTransactions(storeResult.transactions);

    // Log a link to a block explorer where user can view the data.
    console.log(`View data here: https://chipnet.chaingraph.cash/tx/${storeResult.data.dataTxHash}`);
}

INFO

While the initial release of CashConnect targets WalletConnect as a transport, the templates are designed to be transport agnostic. This means that, in future, they can:

  • Be used across HTTP transports (in a flow similar to BIP70/JPP).
  • Be used across P2P transports (e.g. LibP2P).
  • Be used in Backends.
  • Be used Intra-Wallet as Dapps (e.g. as Wallets or Integrated-Dapps).

See Roadmap for further information.