Node side modules (Recipes)

A recipe file is a json file describing the properties of an asset (also token), a (data) source or an engine implementation.

For example: when you query hybrixd for the balance of your waves address: /asset/waves/$ADDRESS this will be routed to the Node side module defined in recipes/asset.waves.json.
The logic there (written in qrtz) will reformat the request to https://nodes.wavesplatform.com/addresses/balance/details/$YOUR_ADDRESS
it will retrieve the result, extract the required information, reformat that and return the standardized end result.

Recipes are stored in the $HYBRIXD/node/recipes folder. View on gitlab

For a token only a basic recipe is required that will import an existing chain's properties.

Example for an asset foo with properties host and cache and quartz program for balance that does something and returns something:

asset.foo.json
{
  "symbol" :"foo",
  "host" : "http://foo.bar",
  "quartz" : {
    "balance" : ["dosomething", "returnsomething"]
  },
  "router" : {
    "balance" : "Does something and then returns something to the user."
  }
}

A recipe defines either an asset/token or a source. For assets (and tokens) a symbol is required, for sources an id.

To facilitate some common standards there are qrtz engines available for Insight and Electrum rpc's. Import these to use their functionality

Filename

For assets the filename is defined as /recipes/asset.$SYMBOL.json or /recipes/token.$SYMBOL.json

For sources the filename is defined as /recipes/source.$TYPE.$ID.json

For engines the filename is defined as /recipes/engine.$NAME.json

Properties

symbol (Only required for assets) Discription: A string containing the symbol. This is used as the main idenitfier. Format: "$BASE[.$TOKEN]" Examples: "BTC", "ETH.SHIFT"
source (Only required for sources) Discription: Examples: "abe.bitcoin", "insight.litecoin", "deterministic"
engine (Only required for engines) Discription: Examples: "storage"
name Discription: A string containing the display name (for pretty printing). Example: "Bitcoin"
mode Discription: A string containing the deterministic mode. Format: "$DETERMINISTIC_MODULE.$SUBMODE" Example: "bitjoinjslib.bitcoin"
contract (Only required for token assets) Description: The unique identifier for an asset token
originator (Only required for token assets) Description: The creator or origin address for an asset token
import Discription: A string or array of strings containing the id's / symbols of the recipes from which this recipe should inherit properties. Cf Import section below Example: "btc", ["btc","eth"] , "btc::host"
module Discription: The name of the server/node side code implementation
module-deterministic (Only required for assets) Discription: The name of the client side code implementation (TODO TO BE RENAMED!)
factor (Only required for assets) Discription: The number of decimal digits used for this asset.
fee (Only required for assets) Discription: A number representing the fee associated with transfering assets
fee-symbol (Optional for assets) Discription: the symbol in which the fee is calculated
host A string or array of strings containing the hosts
[cache]
The ammount of time in miliseconds that data should be cached (Defaults to 12000)
[throttle]
Defaults to 5
[retry]
Defaults to 3
[timeout]
Defaults to 15000
[interval]
Defaults to 2000
The following properties are used to initialize the connection: (cf https://www.npmjs.com/package/node-rest-client#options-parameters )
[user]
[pass]
[proxy]
[connection]
[mimetypes]
[requestConfig]
[responseConfig]
quartz

Defines the Qrtz code. A function is defined by an array of qrtz statements.

router Defines the routing definitions. Used to expose functions as API endpoints and to generate documentation.

Asset Endpoints

An asset should provide the following endpoints: TODO TODO mention default.qrtz
EndpointDescriptionExpected output
/balance/$ADDRESS
/transaction/$TRANSACTION_ID
/validate/$ADDRESS
/sample/$ADDRESS
/details/$ADDRESS
/fee
/factor
/unspent/$ADDRESS

qrtz

Browse to https://api.hybrix.io/help/qrtz for more help on qrtz.

$ Operator $PROPERTY

For qrtz commands the $ is used (inspired by posix) to retrieve variables:

Calling /asset/foo/balance/bar on

asset.foo.json
{
  "id" :"foo",
  "a" : 1,
  "b" : 2,
  "quartz" : {
  "balance" : ["dosomething with $a, $b, $0", "returns $1"]
}
}

Results in

asset.foo.json
{
  "id" :"foo",
  "a" : 1,
  "b" : 2,
  "quartz" : {
    "balance" : ["dosomething with 1, 2, balance", "returns bar"]
  }
}

Cross recipe variables $RECIPE::PROPERTY

The $foo::bar notation can be used to reference variables in other (non imported files)

Given

asset.foo.json
{
  "id" :"foo",
  "a" : 1,
}
 

then

asset.bar.json
{
  "id" :"bar",
  "a" : -1,
  "quartz" : {
    "balance" : ["dosomething with $a, $foo::a", "returnsomething"]
  }
}
 

Compiles to:

{
  "id" :"bar",
  "a" : -1,
  "quartz" : {
    "balance" : ["dosomething with -1, 1", "returnsomething"]
  }
}
 

Import

Inheritance using "import":

Given foo.json

asset.foo.json
{
  "id" :"foo",
  "a" : 1,
  "b" : 2,
}
  

bar.json can inherit foo.json by using

asset.bar.json
{
"id" :"bar",
"a" : -1,
"c" : 3,
"import" : "foo"
}
  

which compiles to

asset.bar.json
{
  "id" :"bar",
  "a" : -1,
  "b" : 2,
  "c" : 3,
  "import" : "foo"
}
  

Note that the value of a is retained, bu b is added.

Multi-inheritance

Multi-inheritance can be defined by using:

asset.bar.json
{
  "id" :"bar",
  "a" : -1,
  "c" : 3,
  "import" : ["foo1","foo2","foo3"]
}
  

They are imported from left to right (values in foo3 overwrite those of foo1 and foo2)

Token inheritance

A token asset, identified by a two part symbol "$BASE.$TOKEN", for example: "eth.shift" will automatically inherit the qrtz code from its base asset "eth".

Javascript modules

To run your javascript code directly you can use the qrtz func method.

To create a helloworld module create a folder in the modules folder with the following files:

  • modules/
    • helloworld/
      • engine.helloworld.json
      • module.js

With the following content:

modules/helloworld/engine.helloworld.json:
{
    "engine":"helloworld"
    "name":"Hello World",
    "module":"helloworld",
    "router":{
      "example" : "Returns the text 'example'",
      "hello" : "Returns the text 'hello world'"
    },
    "quartz": {
      "example" : [
       "done example"
     ],
      "hello" : [
        "func hello"
      ]
    }
}   

The router defines the api endpoints and their corresponding api endpoints. With this module you can now call /engine/helloworld/example and /engine/helloworld/hello and view the automatically generated help page on /help/api/engine/helloworld

The qrtz function example returns 'example' immediatly by using qrtz directly. The function hello will call the hello function in de module.js:

modules/helloworld/module.js:

function hello(proc, data){ // proc, the process handle and the data from the data stream are passed (data is unused in this example

  proc.done('hello world'); // pass 'hello world' as output

  // proc.fail('Oops! Someting gone wrong'); // return a failure
  // proc.peek('myVariable'); // retrieve the content of the variable named myVariable
  // proc.poke('myVariable',123); // set the content of the myVariable variable
}

exports.hello = hello; // export the function so it can be used by qrtz func

Check out the existing modules: View on gitlab