CasinocoinAPI Beginners Guide

This tutorial guides you through the basics of building an CSC Ledger-connected application using Node.js and CasinocoinAPI, a JavaScript API for accessing the CSC Ledger.

The scripts and configuration files used in this guide are available in the CasinoCoin Dev Portal GitHub Repository.

Environment Setup

The first step to using CasinocoinAPI is setting up your development environment.

Install Node.js and npm

CasinocoinAPI is built as an application for the Node.js runtime environment, so the first step is getting Node.js installed. CasinocoinAPI requires Node.js version 0.12, version 4.x, or higher.

This step depends on your operating system. We recommend the official instructions for installing Node.js using a package manager for your operating system. If the packages for Node.js and npm (Node Package Manager) are separate, install both. (This applies to Arch Linux, CentOS, Fedora, and RHEL.)

After you have installed Node.js, you can check the version of the node binary from a command line:

node --version

On some platforms, the binary is named nodejs instead:

nodejs --version

Use NPM to install CasinocoinAPI and dependencies

CasinocoinAPI uses the newest version of JavaScript, ECMAScript 6 (also known as ES2015). To use the new features of ECMAScript 6, CasinocoinAPI depends on Babel-Node and its ES2015 presets. You can use npm to install CasinocoinAPI and these dependencies together.

1. Create a new directory for your project

Create a folder called (for example) my_casinocoin_experiment:

mkdir my_casinocoin_experiment && cd my_casinocoin_experiment

Optionally, start a Git repository in that directory so you can track changes to your code.

git init

Alternatively, you can create a repo on GitHub to version and share your work. After setting it up, clone the repo to your local machine and cd into that directory.

2. Create a new package.json file for your project.

Use the following template, which includes:

  • CasinocoinAPI itself (casinocoin-libjs)
  • Babel (babel-cli)
  • The ECMAScript 6 presets for Babel (babel-preset-es2015)
  • (Optional) ESLint (eslint) for checking code quality.
{
  "name": "my_casinocoin_experiment",
  "version": "0.0.1",
  "license": "MIT",
  "private": true,
  "//": "Change the license to something appropriate. You may want to use 'UNLICENSED' if you are just starting out.",
  "dependencies": {
    "casinocoin-libjs": "*",
    "babel-cli": "^6.0.0",
    "babel-preset-es2015": "*"
  },
  "babel": {
    "presets": ["es2015"]
  },
  "devDependencies": {
    "eslint": "*"
  }
}

3. Use NPM to install the dependencies.

npm install

This automatically installs all the dependencies defined in the package.json into the local folder node_modules/. (We recommend not using npm -g to install the dependencies globally.)

The install process may take a while and end with a few warnings. You may safely ignore the following warnings:

npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents@1.0.6
npm WARN ajv@1.4.10 requires a peer of ajv-i18n@0.1.x but none was installed.

First CasinocoinAPI Script

This script, get-account-info.js, fetches information about a hard-coded account. Use it to test that CasinocoinAPI works:

'use strict';
const CasinocoinAPI = require('casinocoin-libjs').CasinocoinAPI;

const api = new CasinocoinAPI({
  server: 'wss://ws01.casinocoin.org', // Public rippled server
  port: 4443
});
api.connect().then(() => {
  /* begin custom code ------------------------------------ */
  const myAddress = 'caddErVDoBGw1oWMxMHyGhSs9gfTn5pWet';

  console.log('getting account info for', myAddress);
  return api.getAccountInfo(myAddress);

}).then(info => {
  console.log(info);
  console.log('getAccountInfo done');

  /* end custom code -------------------------------------- */
}).then(() => {
  return api.disconnect();
}).then(() => {
  console.log('done and disconnected.');
}).catch(console.error);

Running the script

CasinocoinAPI and the script both use the ECMAScript 6 version of JavaScript. That's why we installed Babel earlier. The easiest way to run ECMAScript 6 is to use the babel-node binary, which NPM installs in the node_modules/.bin/ directory of your project. Thus, running the script looks like this:

./node_modules/.bin/babel-node get-account-info.js

Output:

getting account info for cDarPNJEpCnpBZSfmcquydockkePkjPGA2
{ sequence: 359,
  cscBalance: '75.181663',
  ownerCount: 4,
  previousInitiatedTransactionID: 'E5C6DD25B2DCF534056D98A2EFE3B7CFAE4EBC624854DE3FA436F733A56D8BD9',
  previousAffectingTransactionID: 'E5C6DD25B2DCF534056D98A2EFE3B7CFAE4EBC624854DE3FA436F733A56D8BD9',
  previousAffectingTransactionLedgerVersion: 18489336 }
getAccountInfo done
done and disconnected.

Understanding the script

In addition to CasinocoinAPI-specific code, this script uses syntax and conventions that are recent developments in JavaScript. Let's divide the sample code into smaller chunks to explain each one.

Script opening

'use strict';
const CasinocoinAPI = require('casinocoin-libjs').CasinocoinAPI;

The opening line enables strict mode. This is purely optional, but it helps you avoid some common pitfalls of JavaScript. See also: Restrictions on Code in Strict Mode.

The second line imports CasinocoinAPI into the current scope using Node.js's require function. CasinocoinAPI is one of the modules casinocoin-libjs exports.

Instantiating the API

const api = new CasinocoinAPI({
  server: 'wss://ws01.casinocoin.org', // Public casinocoind server
  port: 4443
});

This section creates a new instance of the CasinocoinAPI class, assigning it to the variable api. (The const keyword means you can't reassign the value api to some other value. The internal state of the object can still change, though.)

The one argument to the constructor is an options object, which has a variety of options. The server parameter tells it where it should connect to a casinocoind server.

  • The example server setting uses a secure WebSocket connection to connect to one of the public servers that CasinoCoin (the company) operates.
  • If you don't include the server option, CasinocoinAPI runs in offline mode instead, which only provides methods that don't need network connectivity.
  • You can specify a CasinoCoin Test Net server instead to connect to the parallel-world Test Network instead of the production CSC Ledger.
  • If you run your own casinocoind, you can instruct it to connect to your local server. For example, you might say server: 'ws://localhost:5005' instead.

Connecting and Promises

api.connect().then(() => {

The connect() method is one of many CasinocoinAPI methods that returns a Promise, which is a special kind of JavaScript object. A Promise is designed to do an asynchronous operation that returns a value later, such as querying the CSC Ledger.

When you get a Promise back from some expression (like api.connect()), you call the Promise's then method and pass in a callback function. Passing a function as an argument is conventional in JavaScript, taking advantage of how JavaScript functions are first-class objects.

When a Promise finishes with its asynchronous operations, the Promise runs the callback function you passed it. The return value from the then method is another Promise object, so you can "chain" that into another then method, or the Promise's catch method, which also takes a callback. The callback you pass to catch gets called if something goes wrong.

Finally, we have more new ECMAScript 6 syntax - an arrow function. Arrow functions are a shorter way of defining anonymous functions. This is convenient for defining lots of one-off functions as callbacks. The syntax ()=> {...} is mostly equivalent to function() {...}. If you want an anonymous function with one parameter, you can use a syntax like info => {...} instead, which is almost the same as function(info) {...} syntax.

Custom code

  /* begin custom code ------------------------------------ */
  const myAddress = 'cDarPNJEpCnpBZSfmcquydockkePkjPGA2';

  console.log('getting account info for', myAddress);
  return api.getAccountInfo(myAddress);

}).then(info => {
  console.log(info);
  console.log('getAccountInfo done');

  /* end custom code -------------------------------------- */

This is the part that you change to do whatever you want the script to do.

The example code looks up an CSC Ledger account by its address. Try running the code with different addresses to see different results.

The console.log() function is built into both Node.js and web browsers, and writes out to the console. This example includes lots of console output to make it easier to understand what the code is doing.

Keep in mind that the example code starts in the middle of a callback function (called when CasinocoinAPI finishes connecting). That function calls CasinocoinAPI's getAccountInfo method, and returns the results.

The getAccountInfo API method returns another Promise, so the line }).then( info => { defines another anonymous callback function to run when this Promise's asynchronous work is done. Unlike the previous case, this callback function takes one argument, called info, which holds the asynchronous return value from the getAccountInfo API method. The rest of this callback function outputs that return value to the console.

Cleanup

}).then(() => {
  return api.disconnect();
}).then(() => {
  console.log('done and disconnected.');
}).catch(console.error);

The rest of the sample code is mostly more boilerplate code. The first line ends the previous callback function, then chains to another callback to run when it ends. That method disconnects cleanly from the CSC Ledger, and has yet another callback which writes to the console when it finishes. If your script waits on CasinocoinAPI events, do not disconnect until you are done waiting for events.

The catch method ends this Promise chain. The callback provided here runs if any of the Promises or their callback functions encounters an error. In this case, we pass the standard console.error function, which writes to the console, instead of defining a custom callback. You could define a smarter callback function here to intelligently catch certain error types.

Waiting for Validation

One of the biggest challenges in using the CSC Ledger (or any decentralized system) is knowing the final, immutable transaction results. Even if you follow the best practices you still have to wait for the consensus process to finally accept or reject your transaction. The following example code demonstrates how to wait for the final outcome of a transaction:

'use strict';
/* import CasinocoinAPI and support libraries */
const CasinocoinAPI = require('casinocoin-libjs').CasinocoinAPI;
const assert = require('assert');

/* Credentials of the account placing the order */
const myAddr = 'caddErVDoBGw1oWMxMHyGhSs9gfTn5pWet';
const mySecret = 's████████████████████████████';

/* Define the order to place here */
const myOrder = {
  'direction': 'buy',
  'quantity': {
    'currency': 'FOO',
    'counterparty': 'cUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v',
    'value': '100'
  },
  'totalPrice': {
    'currency': 'CSC',
    'value': '1000'
  }
};

/* Milliseconds to wait between checks for a new ledger. */
const INTERVAL = 1000;
/* Instantiate CasinocoinAPI. Uses s2 (full history server) */
const api = new CasinocoinAPI({server: 'wss://ws01.casinocoin.org', port: 4443});
/* Number of ledgers to check for valid transaction before failing */
const ledgerOffset = 5;
const myInstructions = {maxLedgerVersionOffset: ledgerOffset};


/* Verify a transaction is in a validated CSC Ledger version */
function verifyTransaction(hash, options) {
  console.log('Verifing Transaction');
  return api.getTransaction(hash, options).then(data => {
    console.log('Final Result: ', data.outcome.result);
    console.log('Validated in Ledger: ', data.outcome.ledgerVersion);
    console.log('Sequence: ', data.sequence);
    return data.outcome.result === 'tesSUCCESS';
  }).catch(error => {
    /* If transaction not in latest validated ledger,
       try again until max ledger hit */
    if (error instanceof api.errors.PendingLedgerVersionError) {
      return new Promise((resolve, reject) => {
        setTimeout(() => verifyTransaction(hash, options)
        .then(resolve, reject), INTERVAL);
      });
    }
    return error;
  });
}


/* Function to prepare, sign, and submit a transaction to the CSC Ledger. */
function submitTransaction(lastClosedLedgerVersion, prepared, secret) {
  const signedData = api.sign(prepared.txJSON, secret);
  return api.submit(signedData.signedTransaction).then(data => {
    console.log('Tentative Result: ', data.resultCode);
    console.log('Tentative Message: ', data.resultMessage);
    /* If transaction was not successfully submitted throw error */
    assert.strictEqual(data.resultCode, 'tesSUCCESS');
    /* 'tesSUCCESS' means the transaction is being considered for the next ledger, and requires validation. */

    /* If successfully submitted, begin validation workflow */
    const options = {
      minLedgerVersion: lastClosedLedgerVersion,
      maxLedgerVersion: prepared.instructions.maxLedgerVersion
    };
    return new Promise((resolve, reject) => {
      setTimeout(() => verifyTransaction(signedData.id, options)
    .then(resolve, reject), INTERVAL);
    });
  });
}


api.connect().then(() => {
  console.log('Connected');
  return api.prepareOrder(myAddr, myOrder, myInstructions);
}).then(prepared => {
  console.log('Order Prepared');
  return api.getLedger().then(ledger => {
    console.log('Current Ledger', ledger.ledgerVersion);
    return submitTransaction(ledger.ledgerVersion, prepared, mySecret);
  });
}).then(() => {
  api.disconnect().then(() => {
    console.log('api disconnected');
    process.exit();
  });
}).catch(console.error);

This code creates and submits an order transaction, although the same principles apply to other types of transactions as well. After submitting the transaction, the code uses a new Promise, which queries the ledger again after using setTimeout to wait a fixed amount of time, to see if the transaction has been verified. If it hasn't been verified, the process repeats until either the transaction is found in a validated ledger or the returned ledger is higher than the LastLedgerSequence parameter.

In rare cases (particularly with a large delay or a loss of power), the casinocoind server may be missing a ledger version between when you submitted the transaction and when you determined that the network has passed the maxLedgerVersion. In this case, you cannot be definitively sure whether the transaction has failed, or has been included in one of the missing ledger versions. CasinocoinAPI returns MissingLedgerHistoryError in this case.

If you are the administrator of the casinocoind server, you can manually request the missing ledger(s). Otherwise, you can try checking the ledger history using a different server. (CasinoCoin runs a public full-history server at ws01.casinocoin.org for this purpose.)

See Reliable Transaction Submission for a more thorough explanation.

CasinocoinAPI in Web Browsers

CasinocoinAPI can also be used in a web browser if you compile a browser-compatible version and include lodash as a dependency before the CasinocoinAPI script.

Build Instructions

To use CasinocoinAPI in a browser, you need to build a browser-compatible version. The following process compiles CasinocoinAPI into a single JavaScript file you can include in a webpage.

1. Download a copy of the CasinocoinAPI git repository.

If you have Git installed, you can clone the repository and check out the master branch, which always has the latest official release:

git clone https://github.com/casinocoin/casinocoin-libjs.git
cd casinocoin-libjs
git checkout master

Alternatively, you can download an archive (.zip or .tar.gz) of a specific release from the CasinocoinAPI releases page and extract it.

2. Install dependencies using NPM

You need to have NPM (Node.js Package Manager) installed first.

Then, from within the casinocoin-libjs directory, you can use NPM to install all the necessary dependencies:

npm install

(We recommend not using npm -g to install dependencies globally.)

This can take a while, and may include some warnings. The following warnings are benign and do not indicate a problem:

npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents@1.0.6

3. Use Gulp to build a single JavaScript output

CasinocoinAPI comes with code to use the gulp package to compile all its source code into browser-compatible JavaScript files. Gulp is automatically installed as one of the dependencies, so all you have to do is run it. CasinocoinAPI's configuration makes this easy:

npm run build

Output:

> casinocoin-libjs@0.16.5 build /home/username/casinocoin-libjs
> gulp

[15:22:30] Using gulpfile /home/username/casinocoin-libjs/Gulpfile.js
[15:22:30] Starting 'build'...
[15:22:30] Starting 'build-debug'...
[15:22:42] Finished 'build' after 12 s
[15:22:42] Starting 'build-min'...
[15:22:42] Finished 'build-debug' after 12 s
[15:22:51] Finished 'build-min' after 9.83 s
[15:22:51] Starting 'default'...
[15:22:51] Finished 'default' after 4.58 μs

This may take a while. At the end, the build process creates a new build/ folder, which contains the files you want.

The file build/casinocoin-<VERSION NUMBER>.js is a straight export of CasinocoinAPI (whatever version you built) ready to be used in browsers. The file ending in -min.js is the same thing, but with the content minified for faster loading.

Example Browser Usage

The following HTML file demonstrates basic usage of the browser version of CasinocoinAPI to connect to a public casinocoind server and report information about that server. Instead of using Node.js's "require" syntax, the browser version creates a global variable named casinocoin, which contains the CasinocoinAPI class.

To use this example, you must first build CasinocoinAPI and then copy one of the resulting output files to the same folder as this HTML file. (You can use either the minified or full-size version.) Change the first <script> tag in this example to use the correct file name for the version of CasinocoinAPI you built.

browser-demo.html:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>
  <script src="casinocoin-0.17.7-min.js"></script>
  <script>
    console.log(ripple);
    var api = new ripple.RippleAPI({server:'wss://ws01.casinocoin.org/', port: 4443});
    api.connect().then(function() {
        return api.getServerInfo();
    }).then(function(server_info) {
    document.body.innerHTML += "<p>Connected to rippled server!</p>" +
"      <table>" +
"        <tr><th>Version</th>" +
"          <td>" + server_info.buildVersion + "</td></tr>" +
"        <tr><th>Ledgers available</th>" +
"          <td>" + server_info.completeLedgers + "</td></tr>" +
"        <tr><th>hostID</th>" +
"          <td>" + server_info.hostID + "</td></tr>" +
"        <tr><th>Most Recent Validated Ledger Seq.</th>" +
"          <td>" + server_info.validatedLedger.ledgerVersion + "</td></tr>" +
"        <tr><th>Most Recent Validated Ledger Hash</th>" +
"          <td>" + server_info.validatedLedger.hash + "</td></tr>" +
"        <tr><th>Seconds since last ledger validated</th>" +
"          <td>" + server_info.validatedLedger.age + "</td></tr>" +
"      </table>";
    });
  </script>
  <style type="text/css">
    td, th { border: 1px solid black; padding: 5px; }
    table { border-collapse: collapse; }
  </style>
</head>
<body></body>
</html>