Client side modules

Introduction

A deterministic module is a client side module for hybrixd. It is used to handle client seeds, keys addresses and signing. As we do not want a client to share their keys all these actions should be performed client side. The node should never touch this data. To facilitate this the node supplies a 'client code blob' : compressed javascript code that can be executed on the client side.

Types

Most client side modules will be asset modules. For example the client module bitcoinjslib to handle bitcoin key and address generation and transaction signing. Other custom client side modules can also be provided. For example to provide connectivity to (decentralized) exchanges.

Source Files

The source files for deterministic modules with name $MY_ASSET_NAME are grouped in the module folder:

$HYBRIXD/deterministic/modules/$MY_ASSET_NAME/

You will need to create the following file(s):

deterministic.js
The entry file see below for the deterministic.js template
[Optional]: precompile.sh
A script to standardize and automate changes to third party libraries.
[Optional]:compile.sh
a script to compile the above into a single LZMA file

The artifact (compilation result) is build in the $HYBRIXD/deterministic/dist/$MY_ASSET_NAME/ folder. It will consist of a LZMA compressed code blob file named deterministic.js.lzma

For examples see the existing modules: gitlab.

Grocery List

To implement a deterministic module you will need the following

Node Side Module
A qrtz module added to the $HYBRIXD/node/recipes folder. This should provide a connection to the asset API's (for example: the block explorers) Handling queries for balance, unspents and pushing transactions.
A javascript library for the asset.
A library provided by the developers of the crypto currency. This can be a npm module or a (minified) web js library. Search online for "$MY_ASSET_NAME javascript library" this will very likely guide you to a github/gitlab repository or npm module which you can download.

Library Dependencies

To install npm modules: please use supplied npm to ensure version compatibility:

cd $HYBRIXD/deterministic/modules/$YOUR_ASSET
npm i $MY_ASSETS_NPM_MODULE

Each asset module will have its own package.json and node_modules folder. Only dev dependencies(webpack, eslint) are stored in $HYBRIXD/deterministic/node_modules

To use them include the npm module in your deterministic.js:

const myAssetLib = require("$MY_ASSETS_NPM_MODULE")

To include a js library file place the file in the module folder:

$HYBRIXD/deterministic/modules/$MY_ASSET_NAME/$MY_ASSET_LIBRARY/$SOME_FILE.js

To then include the js library in your deterministic.js:

const myAssetLib = require("$MY_ASSET_LIBRARY/$SOME_FILE")

deterministic.js Template

deterministic.js must provide the functions: keys, importKeys, address and transaction.

const wrapperlib = require("$MY_ASSET_LIBRARY/$SOME_FILE")

const wrapper = {
  keys : function(data) {
    return wrapperLib.someFunctionToCreateKeysFromSeed(data.seed);
  },

   // generate a unique wallet address from a given public key
  address : function(data) {
    return wrapperLib.someFunctionToGenerateAddressFromKeys(data.keys);
  },

  // create and sign a transaction for the given keys, amount, addresses and fees
  transaction : function(data,callback) {
    // contruct a transaction object
    var tx = {
      amount: data.amount
      fee:data.fee
      targetaddress: data.target
      sourceaddress: data.source
      fee: data.fee
    };
    return wrapperLib.someFunctionToSignTransaction(tx,data.keys);
    // If the function is asynchronious then use
    // wrapperLib.someAsyncFunctionToSignTransaction(tx,data.keys,callback);
  }
}

// export the wrapper
window.deterministic = wrapper;

The keys function expects a data parameter containing the seed property and returns an keys object with a key.

keys : function({seed: ..}){
  return  {privateKey:...}; // or {privateKey: ..., publicKey: ...} or { WIF: wif }
}

The address function expects a data parameter containing the seed, the keys, and the mode. (The mode is used to distinguish between assets using the same deterministic module. For example bitcoinjslib.bitcoin and bitcoinjslib.omni) It returns a string containing the address

address : function({seed: .. , keys: ..., mode: ...}){
 return "ABC123";
}

The transaction function expects a data parameter of the following format:

{
  keys:
  symbol:,
  source: ,
  target: ,
  account:,
  fee:,
  factor:,
  contract:,
  unspent:,
  target:,
  amount:,
  message: [optional]
}

and an optional callback parameter in case the transaction generation is asynchronious. The function will return the stringified signed transaction.

Result

A possible module folder could look like this:

node_modules/
deterministic.js
package.json
package-lock.json
precompile.sh

Compilation

All deterministic modules (which source files are modified more recent than the corresponding LZMA) are compiled by executing:

$HYBRIXD/deterministic/npm run build

Pipeline

The following steps are performed to create the client code blob:

[Optional] Precompile
automatic modification are made to third party libraries.
Compile
The compile script is run
Degloballify
All global/undeclared variables 'x' are declared as 'window.x'
Webpack
create a package that can be used by browsers
Compress
compress the result using lmza

Precompile

The precompile step is only executed if there's a precompile.sh present in the module folder. This can and should be used to make modification to third party libraries (which is sometimes required). We do not want to make these modification in the libraries statically because then our changes will be lost if we update the libraries. By adding the code in precompile.sh the changes will be reapplied after code updates.

Compile override

To override the compile script place a compile.sh script of your own making in the module folder.

Testing

Use $HYBRIXD/hybrix-lib/test/test --symbol $YOUR_ASSET_NAME to test your implementation for nodejs or browse to:

file://$HYBRIXD/hybrix-lib/test/test.html?symbol=$YOUR_ASSET_NAME

to test your implementation for web.

If you encounter issues you can do a partial testing (without webpack) by running:

$HYBRIXD/deterministic/test/test --symbol $YOUR_ASSET_NAME