Source: blockchains/fennel/transactions.js

'use strict';
/**
 * @module lib/blockchains/fennel/transactions
 * @summary Whiteflag API Fennel transaction module
 * @description Module to process Fennel transactions for Whiteflag
 */
module.exports = {
    init: initTransactions,
    get: getTransaction,
    sendSignal,
    sendTokens,
    extractMessage
};

/* Common internal functions and classes */
const log = require('../../_common/logger');
const { ProcessingError } = require('../../_common/errors');
const { withHexPrefix, 
        noHexPrefix } = require('../../_common/format');

/* Fennel sub-modules */
const fnlRpc = require('./rpc');
const fnlAccounts = require('./accounts');

/* Module constants */
const MODULELOG = 'fennel';
const WFINDENTIFIER = '5746';

/* Module variables */
let _fnlChain;
let _traceRaw = false;

/**
 * Initialises Fennel Transactions processing
 * @function initTransactions
 * @alias module:lib/blockchains/fennel/transactions.init
 * @param {Object} fnlConfig the Fennel blockchain configuration
 * @returns {Promise} resolve if succesfully initialised
 */
function initTransactions(fnlConfig) {
    log.trace(MODULELOG, 'Initialising Fennel transaction processing');
    _fnlChain = fnlConfig.name;

    // Trace all transactions if configured
    if (fnlConfig.traceRawTransaction) _traceRaw = fnlConfig.traceRawTransaction;

    // Succesfully completed initialisation
    return Promise.resolve();
}

/**
 * Sends a signal transaction on the Fennel blockchain
 * @function sendSignal
 * @alias module:lib/blockchains/fennel/transactions.sendSignal
 * @param {wfAccount} account the account used to send the transaction
 * @param {string} toAddress the address to send the transaction to
 * @param {string} data the data to be sent
 * @returns {Promise} resolve to transaction hash and block number
 */
function sendSignal(account, data) {
    log.debug(MODULELOG, `Sending signal from account ${account.address}: ${data}`);
    return fnlAccounts.getKeyring(account.address)
    .then(originator => {
        const signal = withHexPrefix(data);
        return fnlRpc.sendSignal(originator, signal);
    })
    .then(result => {
        log.debug(MODULELOG, `Transaction result: ${JSON.stringify(result)}`)
        return Promise.resolve(noHexPrefix(result.toHex()));
    })
    .catch(err => {
        return Promise.reject(err);
    });
}

/**
 * Sends a token transaction on the Fennel blockchain
 * @function sendTokens
 * @alias module:lib/blockchains/fennel/transactions.sendTokens
 * @param {wfAccount} account the account used to send the transaction
 * @param {string} toAddress the address to transfer the tokens to
 * @param {number} amount the amount of tokens to transfer
 * @returns {Promise} resolve to transaction hash and block number
 */
function sendTokens(account, toAddress, amount) {
    log.debug(MODULELOG, `Sending tokens from account ${account.address} to ${toAddress}: ${amount}`);
    return fnlAccounts.getKeyring(account.address)
    .then(originator => {
        return fnlRpc.sendTokens(originator, toAddress, amount);
    })
    .then(result => {
        log.debug(MODULELOG, `Transaction result: ${JSON.stringify(result)}`)
        return Promise.resolve(result.toHex());
    })
    .catch(err => {
        return Promise.reject(err);
    });
}

/**
 * Gets a transaction by transaction hash and checks for Whiteflag message
 * @private
 * @param {string} transactionHash
 * @returns {Promise} resolves to a blockchain transaction
 */
function getTransaction(transactionHash) {
    log.trace(MODULELOG, `Retrieving transaction: ${transactionHash}`);
    return fnlRpc.getRawTransaction(transactionHash)
    .then(transaction => {
        if (!transaction) {
            return Promise.reject(new ProcessingError(`No transaction returned by ${_fnlChain} node for hash: ${transactionHash}`, null, 'WF_API_NO_DATA'));
        }
        return Promise.resolve(transaction);
    })
    .catch(err => {
        return Promise.reject(err);
    });
}

/**
 * Extracts Whiteflag message from Fennel transaction data
 * @function extractMessage
 * @alias module:lib/blockchains/fennel/transactions.extractMessage
 * @param {Object} transaction the Fennel transaction
 * @returns {Promise} resolves to a Whiteflag message
 */
 function extractMessage(transaction) {
    if (_traceRaw) log.trace(MODULELOG, `Extracting Whiteflag message from extrinsic ${transaction.block}/${transaction.index}: ${JSON.stringify(transaction)}`);
    return fnlAccounts.getPublicKey(transaction.originator)
    .then(fnlPubkey => {
        if (transaction.signal.startsWith(WFINDENTIFIER)) {
            let wfMessage = {
                MetaHeader: {
                    blockchain: _fnlChain,
                    blockNumber: transaction.block,
                    transactionIndex: transaction.index,
                    transactionHash: transaction.hash,
                    transactionTime: transaction.timestamp,
                    originatorAddress: transaction.originator,
                    originatorPubKey: fnlPubkey,
                    encodedMessage: transaction.signal
                }
            };
            return Promise.resolve(wfMessage);
        }
        return Promise.reject(new ProcessingError(`No Whiteflag message found in extrinsic ${transaction.block}/${transaction.index}`, null, 'WF_API_NO_DATA'));
    })
    .catch(err => {
        return Promise.reject(err);
    });
}