Include a Coin Manager on your Server

From CloudCoin Wiki
Jump to: navigation, search

Coin Manager is a program that can be installed to allow your application server to accept, manage and dispense CloudCoin via a command lines or a REST API.

The Coin Manager allows any other program written in any other language to easily integrate CloudCoins into server software. Coin Manager is an open source program and can be modified. It is written in the Go Language. Your software can order Coin Manager to:

  • Create folders/wallets/accounts for users to store their CloudCoins in (Create Wallet).
  • Show the user's balance (Show Balance)
  • Deposit coins into wallets. (Import)
  • Withdraw coins (Withdraw)
  • Move coins from user to user (Transfer)
  • Move coins from the user's account to the server's account and tell the server (Payment)
  • Move coins from the server's account to the user's account (Payouts)
  • Track and show all transactions of each account (Show Transactions)
  • Provide receipts to the user for Deposits and payments
  • Utilities like echoing the RAIDA.
  • Keep coins in good health (Health Check).
  • Backup accounts.
  • Display the serial numbers in an account.
  • Log actions

Also, the coin manager can be used to manage CloudCoin powered NFTs.

  • Create NFTs
  • Register NFTs with DNS and Web servers.
  • View NFT Thumbnails
  • View NFT details
  • Destroy NFTs and turn them back to CloudCoin
  • Import, export and transfer NFTs.

NOTE: The CloudCoin Consortium has created web programs in PHP and a Discord bot that you can add to your server that makes it even easier for you to enable these functions.

Choosing the right Version of Coin Manager

Coin Manager versioning uses a YY.MM.DD format. Version number 22.9.7 means the CoinManager was built on Septermer 7, 2022

It most cases it is advisable to use the latest version of the program

Downloading the Coin Manager

The latest CoinManager can be downloaded from the GitLab repository


https://gitlab.shurafom.eu/worthingtonse/super-client/-/blob/master/cloudcoin_manager


The repository is private and you may need to request credentials to access it

This is always an up to date binary. It is a x86_64 binary that can be run on any compatible Linux machine

Placing the Coin Manager

The cloudcoin_manager binary must be uploaded onto the server and put in any binary folder

  • /usr/bin
  • /usr/local/bin
  • /home/user/bin
  • /usr/local/sbin

The best choice would be /usr/local/bin

(!) Don't put the binary directly in your home folder.

The program will create its root folder 'cloudcoin_manager' in the user's home

If you run it as 'root' (not recommended) then the folder will be

/root/cloudcoin_manager

You may need to install a webkit library if you don't have one

$ sudo apt install libwebkit2gtk-4.0-37-gtk2

Testing the Coin Manager

The CoinManager on the server must be always run with -cli command line argument. This key prevents the program from launching the UI screen.

Run the program

$ /usr/local/bin/cloudcoin_manager -cli

There will be a long output from the command. It will contact the RAIDA servers and wait for the response.

The final line of the output is 'HTTP Router Configured'. That means the CoinManager is ready for use.


Check that the root folder is created. Navigate to your home folder and check the 'coin_manager' folder

$ ls -l /home/user/cloudcoin_manager/
total 236
drwx------ 2 ppp ppp   4096 Sep 14 08:12 NFTs
drwx------ 2 ppp ppp   4096 Sep 14 08:12 SkyWallets
drwx------ 2 ppp ppp   4096 Sep 14 08:12 Templates
drwx------ 3 ppp ppp   4096 Sep 14 08:12 Wallets
-rw-rw-r-- 1 ppp ppp    964 Sep 14 08:12 config.toml
-rw-r--r-- 1 ppp ppp    448 Sep 14 08:12 encryption.cc
-rw-rw-r-- 1 ppp ppp 213325 Sep 14 08:12 main.log

Also, you can check that port 8888 is listening

$ ss -nlpt |grep 8888
LISTEN   0         4096                      *:8888                   *:*        users:(("cloudcoin_manag",pid=5541,fd=32))

That means the CoinManager is up and running. You can execute a simple version API command

$ curl 'http://localhost:8888/api/v1/info'
{"payload":{"version":"22.9.10"},"status":"success"}


Using the Coin Manager

The CoinManager provides REST API via an http port. Any HTTP-client can connect to it and execute an API call


The input and output formats are JSON. The HTTP header Content-Type is always application/json


This is an example of queriyng the contents of the 'Default' wallet


$ curl 'http://localhost:8888/api/v1/wallets/Default' 2>/dev/null | jq

{
  "payload": {
    "name": "Default",
    "email": "",
    "password_hash": "",
    "balance": 2,
    "denominations": {
      "1": 2,
      "100": 0,
      "25": 0,
      "250": 0,
      "5": 0
    },
    "contents": [
      4301971,
      4301970
    ],
    "transactions": null,
    "fracked_count": 0,
    "limbo_count": 0,
    "collection_map": null
  },
  "status": "success"
}


The full list of API method is documented in OpenAPI 3.0 standard in the api.json file


https://gitlab.shurafom.eu/worthingtonse/super-client/-/blob/master/api.json


The file can be inported in any OpenAPI 3.0 compatible browser (e.g. Swagger. https://editor.swagger.io)


Response Types

There are two types of the CloudCoin Manager API command:

  • Synchronous
  • Asynchronous

Synchronous commands return the final response right after the request is processed. The example of the synchronous command is the request above. Usually they are short-running and quick commands that don't need much time to process.


Asynchronous commands create an internal task in the CoinManager and return the Task ID to the caller. Later the client can use the Task ID to query the task status and progress. Most of the Coin Manager calls that need to contact the RAIDA are asynchronous

An example of the asynchronous call is 'Echo'

$ curl 'http://localhost:8888/api/v1/echo' | jq
{
  "payload": {
    "id": "aa265b90-c2d6-490e-8d55-59691d555f7e",
    "status": "running",
    "progress": 0,
    "started": 1663134181,
    "finished": 0,
    "message": "",
    "data": null
  },
  "status": "success"
}

Here we received a Task ID aa265b90-c2d6-490e-8d55-59691d555f7e and we can periodically call this task to see if it is completed

curl 'http://localhost:8888/api/v1/tasks/aa265b90-c2d6-490e-8d55-59691d555f7e' 
{"payload":{"id":"aa265b90-c2d6-490e-8d55-59691d555f7e","status":"completed","progress":100,"started":1663134181,"finished":1663134181,"message":"Command Completed","data":{"online":25,"pownstring":"ppppppppppppppppppppppppp","pownarray":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"latencies":[229,368,325,209,204,146,185,214,186,199,336,125,264,144,125,189,355,184,152,155,128,231,327,215,194]}},"status":"success"}


Response format

Asynchronous calls return ErrorResponse object on failure and TaskResponse object on success. The contents of the TaskResponse depends on the initial call and all possible values can be seen in the API documentation. The program must check the "status" field that is always present in any response. "status":"success" means that the task was created successfully, but it does not mean that the task itself it successful. The program must wait when the task completes and check its status too.

Synchronous calls also return ErrorResponse on failure but they return the exact response object type that depends on the initial call. E.g. if the initial call is 'wallets' the response object is GetWalletsResponse


Configuring the Coin Manager

In most cases you don't need to configure the Coin Manager. All default values are fine in most situations.

However you can modify some variables and try to improve performance

The configuration file is config.toml and it is follows the TOML standard.

It is located in the Coin Manager root folder

/home/user/cloudcoin_manager/config.toml

The example of the file contents:

title = "CloudCoin Manager"
help = "support@cloudcoin.global"

[main]
  http_timeout = 3
  max_notes_to_send = 400
  export_background = "#02203D"
  brand_color = "#7FA8FF"
  guardians = ["raida-guardian-tx.us", "g2.cloudcoin.asia", "guardian.ladyjade.cc", "watchdog.guardwatch.cc", "g5.raida-guardian.us", "goodguardian.xyz", "g7.ccraida.com", "raidaguardian.nz", "g9.guardian9.net", "g10.guardian25.com", "g11.raidacash.com", "g12.aeroflightcb300.com", "g13.stomarket.co", "guardian14.gsxcover.com", "guardian.keilagd.cc", "g16.guardianstl.us", "raida-guardian.net", "g18.raidaguardian.al", "g19.paolobui.com", "g20.cloudcoins.asia", "guardian21.guardian.al", "rg.encrypting.us", "g23.cuvar.net", "guardian24.rsxcover.com", "g25.mattyd.click", "g26.cloudcoinconsortium.art"]
  default_timeout_mult = 100
  echo_timeout_mult = 100
  encryption_disabled = false


  • http_timeout sets the HTTP timeout when communication with remote HTTP servers (not RAIDA servers) e.g. DNS servers
  • max_notes_to_send tells the program how many coins to use at one go. If you send 1,000 coins to detect and this parameter is 400 there will be three calls with 400, 400 and 200 coins
  • brand_color is used on creating an exported png file
  • guardians arrays sets the initial array of the Guardians servers. Can be used for testing purposes
  • default_timeout_mult and echo_timeout_mult is a percentage value of the default and echo timeout mutlipliers
  • encryption_disabled can disable the AES ecryption that is used to encrypt traffic between the client and the RAIDA servers

Debugging the Coin Manager

The Coin Manager writes its debug information to the main.log file. This file is located in the CoinManager root folder

/home/user/cloudcoin_manager/main.log

The file contains information about every request and can be filtered by Request-ID that comrises a command name and a uniq ID (echo-9dc9994dfcad) The main.log also has records about RAIDA connections

Whenever the main.log exceeds 100Mb it is rotated


Calling CoinManager API

This is a code example that calls two functions: echo and wallets written in PHP.

The examples below show how to call local functions on the RAIDA.

<?php

ob_implicit_flush(1);
ini_set('display_errors', 1);

if (!extension_loaded('curl'))
  die("CURL is required");

/* 
 *
 * Calling ECHO (Async Method)
 * 
 */
$response = callAsyncMethod("echo", 'GET');
if (!$response)
  die("Failed to get echo response");

echo "Online RAIDA servers: " . $response->online . "<br>";
echo "Status string: " . $response->pownstring . "<br>";



/*
 *
 * GET Wallet balance (Sync Method)
 *
 */
$response = callMethod("wallets/Default", 'GET');
if (!$response)
  die("Failed to get wallet balance");

echo "The balance of the default wallet is " . $response->balance . "<br>";


/*
 *
 * Core functions
 *
 */
function callMethod($path, $method = 'POST', $data = null) {
  $curl = curl_init();

  $url = "http://localhost:8888/api/v1/$path";
  if ($method == 'POST') {
    curl_setopt($curl, CURLOPT_POST, 1);
    if ($data) {
      $data = json_encode($data);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
  } else if ($method == 'PUT') {
    curl_setopt($curl, CURLOPT_PUT, 1);
    if ($data) {
      $data = json_encode($data);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
  } else {
    if ($data) 
      $url .= "?" . http_build_query($data);
  }

  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

  $result = curl_exec($curl);
  if (!$result)
    return null;

  curl_close($curl);

  $data = json_decode($result);
  if (!$data)
    return null;

  if (isset($data->status) && $data->status !== "success")
    return null;

  return $data->payload;
}

function callAsyncMethod($path, $method = 'POST', $data = null) {
  $response = callMethod($path, $method, $data);
  if (!$response)
    die("Request failed");

  $taskID = $response->id;
  if (!$taskID)
    die("Failed to get taskID");

  while (true) {
    $taskResponse = callMethod("tasks/" . $taskID, 'GET');
    if (!$taskResponse)
      die("Failed to get task response");

    if ($taskResponse->status == "completed") {
      echo "Task completed<br>";
      return $taskResponse->data;
    }

    if ($taskResponse->status == "error") {
      echo "Error<br>";
      return;
    }

    echo "Running... Progress " . $taskResponse->progress . "%  Status: " . $taskResponse->message . "<br>";
    flush();
    ob_flush();
    sleep(1);
  }

}


The examples below show how to call skyvault functions on the RAIDA.

<?php

ob_implicit_flush(1);
ini_set('display_errors', 1);

if (!extension_loaded('curl'))
  die("CURL is required");


/*
 *
 * Show Payment.
 * This function downloads a specific Payment from the RAIDA along with its details
 * It accepts 'guid' query parameter.
 * 'guid' is a 32-hex char ID of the payment. 
 *
 *  Response parameters:
 *  guid: the ID of the payment
 *  type: type of the payment. Can be either 'transfer' or 'deposit'. For between-skyvaults operations this parameter is always 'transfer'
 *  amount: amount of coins in the payment
 *  balance: the balance of the skyvault after receiving this payment
 *  time: date and time of the payment
 *  memo: information the buyer put in the payment
 *  owner: the serial number of the owner's skyvault. 
 *
 */
$response = callMethod("payment", 'GET', ["guid" => "b09ec4caeed8678f34243e3a5155acea"]);
if (!$response) 
  die("Failed to download payment");

echo "Memo: " . $response->memo . ", amount " . $response->amount . "<br>";


/*
 * 
 * Verify Sky Vault.
 * This function ensures the skyvault exists and resolves into a valid CloudCoin
 *
 * It accepts 'name' POST parameter. That is the name of the validated skyvault.
 *
 * Response parameters:
 * status: If status is 'success' the validation succeeded. If failed otherwise.
 *
 */
$response = callMethod("skyverify", 'POST', ["name" => "nmiroch101.skyvault.cc"]);
if (!$response) 
  die("Failed to verify skyvault");

echo "Skyvault verified<br>";



/*
 *
 * Statements.
 * This function downloads information about a skyvault from the RAIDA. This information includes statements.
 * You must be the owner of the skyvault to access this method. The ID coin of the skyvault must be present in the ID folder.
 *
 * The function accepts only one paramenter that is the name of the skyvault. It is passed in the URL
 *
 * Response parameters:
 * name: the name of the skyvault
 * balance: the number of coins in the skyvault
 * png: a graphic image of the skyvault
 * statements: an array of the statements present in the skyvault
 *  - guid: the unique 32-hexchar ID of the statement
 *  - type: type of the statement. Can be 'deposit' or 'transfer'
 *  - balance: running balance
 *  - amount: amount of coins in the statement
 *  - time: time of creation
 * idcoin: a structure with ID coin info:
 *  - sn: the serial number of the ID coin
 *  - ans: authenticity numbers
 */
$response = callAsyncMethod("skywallets/nmiroch101.skyvault.cc", 'GET');
if (!$response) 
  die("Failed to download statements");

var_dump($response->statements);




/*
 *
 * Sky Transfer
 *
 * This function transfers coins from a skyvault to another skyvault
 * You must be the onwer of the source skyvault. The ID coin must be present in the ID folder
 *
 * Parameters:
 *
 * srcname - the name of the sender's sky vault
 * dstname - the name of the recipient's skyvault
 * amount - amount to send
 * tag - optional tag of the operation
 * 
 * Response:
 *
 * The function return
 * status - can be 'success' or 'error'
 *
 */
$response = callAsyncMethod("skytransfer", 'POST', ['srcname'=>'me.skyvault.cc', 'dstname'=>'you.skyvault.cc', 'amount'=>'10']);
if (!$response) 
  die("Failed to transfer coins");

echo "Transferred successfully";











/*
 *
 * Core functions
 *
 */
function callMethod($path, $method = 'POST', $data = null) {
  $curl = curl_init();

  $url = "http://localhost:8888/api/v1/$path";
  if ($method == 'POST') {
    curl_setopt($curl, CURLOPT_POST, 1);
    if ($data) {
      $data = json_encode($data);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
  } else if ($method == 'PUT') {
    curl_setopt($curl, CURLOPT_PUT, 1);
    if ($data) {
      $data = json_encode($data);
      curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
  } else {
    if ($data) 
      $url .= "?" . http_build_query($data);
  }

  curl_setopt($curl, CURLOPT_URL, $url);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

  $result = curl_exec($curl);
  if (!$result)
    return null;

  curl_close($curl);

  $data = json_decode($result);
  if (!$data)
    return null;

  if (isset($data->status) && $data->status !== "success")
    return null;

  return $data->payload;
}

function callAsyncMethod($path, $method = 'POST', $data = null) {
  $response = callMethod($path, $method, $data);
  if (!$response)
    die("Request failed");

  $taskID = $response->id;
  if (!$taskID)
    die("Failed to get taskID");

  while (true) {
    $taskResponse = callMethod("tasks/" . $taskID, 'GET');
    if (!$taskResponse)
      die("Failed to get task response");

    if ($taskResponse->status == "completed") {
      echo "Task completed<br>";
      return $taskResponse->data;
    }

    if ($taskResponse->status == "error") {
      echo "Error<br>";
      return;
    }

    echo "Running... Progress " . $taskResponse->progress . "%  Status: " . $taskResponse->message . "<br>";
    flush();
    ob_flush();
    sleep(1);
  }

}