function createPaymentTransaction(remote, paymentData, orderRequestId, srcIssuer, amount){
    var transaction = remote.createTransaction('Payment', paymentData);
    transaction.lastLedger(remote.getLedgerSequence() + 10); // Wait at most 10 ledger sequences

    // Save order info on the blockchain
    if (orderRequestId) {
        transaction.tx_json.Memos = [
            {
                Memo: {
                    MemoType: RippleUtils.stringToHex('OrderRequestId'),
                    MemoData: RippleUtils.stringToHex(orderRequestId)
                }
            }
        ];
    }

    // Append it if you got it
    if (srcIssuer) {
        var maxValue = amount.toString(); // Send all; original code from ripple-rest is:
        // new BigNumber(payment.source_amount.value).plus(payment.source_slippage || 0).toString();
        transaction.sendMax({
            value: maxValue,
            currency: 'EUR',      // EUR foreveeer
            issuer: srcIssuer    // Gotcha!
        });
    }


    transaction.on('resubmit', function () {
        debug('resubmitting ', transaction);
    });

    return transaction;
}
    }, function( err, res ) {

      if ( err ) {
        winston.error( "Error getting ledger from rippled:", err );
        callback( err );
        return;
      }

      // add/edit fields that aren't in rippled's json format
      var ledger = res.ledger;
      ledger.close_time_rpepoch = ledger.close_time;
      ledger.close_time_timestamp = ripple.utils.toTimestamp( ledger.close_time );
      ledger.close_time_human = moment( ripple.utils.toTimestamp( ledger.close_time ) ).utc( ).format( "YYYY-MM-DD HH:mm:ss Z" );
      ledger.from_rippled_api = true;

      // remove fields that do not appear in format defined above in parseLedger
      delete ledger.close_time;
      delete ledger.hash;
      delete ledger.accepted;
      delete ledger.totalCoins;
      delete ledger.closed;
      delete ledger.seqNum;

      // parse ints from strings
      ledger.ledger_index = parseInt(ledger.ledger_index, 10);
      ledger.total_coins = parseInt(ledger.total_coins, 10);

      // add exchange rate field to metadata entries
      ledger.transactions.forEach( function( transaction ) {
        transaction.metaData.AffectedNodes.forEach( function( affNode ) {
          var node = affNode.CreatedNode || affNode.ModifiedNode || affNode.DeletedNode;

          if ( node.LedgerEntryType === "Offer" ) {

            var fields = node.FinalFields || node.NewFields;

            if ( typeof fields.BookDirectory === "string" ) {
              node.exchange_rate = ripple.Amount.from_quality( fields.BookDirectory ).to_json( ).value;
            }
          }
        } );
      } );

      // check the transaction hash of the ledger we got from the api call
      var ledgerJsonTxHash = Ledger.from_json( ledger ).calc_tx_hash( ).to_hex( );
      if ( ledgerJsonTxHash === ledger.transaction_hash ) {

        callback( null, ledger );

      } else {

        callback( new Error( "Error with ledger from rippled api call, transactions do not hash to expected value" +
          "\n  Actual:   " + ledgerJsonTxHash +
          "\n  Expected: " + ledger.transaction_hash +
          "\n\n  Ledger: " + JSON.stringify( ledger ) + "\n\n" ) );

      }
    } );
// parseRawLedgerHeader renames ledger header field names
function parseRawLedgerHeader( rawHeader ) {

  return {
    account_hash: rawHeader.AccountSetHash,
    close_time_rpepoch: rawHeader.ClosingTime,
    close_time_timestamp: ripple.utils.toTimestamp( rawHeader.ClosingTime ),
    close_time_human: moment( ripple.utils.toTimestamp( rawHeader.ClosingTime ) ).utc( ).format( "YYYY-MM-DD HH:mm:ss Z" ),
    close_time_resolution: rawHeader.CloseTimeRes,
    ledger_hash: rawHeader.LedgerHash,
    ledger_index: rawHeader.LedgerSeq,
    parent_hash: rawHeader.PrevHash,
    total_coins: rawHeader.TotalCoins,
    transaction_hash: rawHeader.TransSetHash
  };

}
var formatRemoteLedger = function(ledger) {

  ledger.close_time_rpepoch   = ledger.close_time;
  ledger.close_time_timestamp = ripple.utils.toTimestamp(ledger.close_time);
  ledger.close_time_human     = moment(ripple.utils.toTimestamp(ledger.close_time))
    .utc().format('YYYY-MM-DD HH:mm:ss Z');
  ledger.from_rippled_api = true;

  delete ledger.close_time;
  delete ledger.hash;
  delete ledger.accepted;
  delete ledger.totalCoins;
  delete ledger.closed;
  delete ledger.seqNum;

  // parse ints from strings
  ledger.ledger_index = parseInt(ledger.ledger_index, 10);
  ledger.total_coins = parseInt(ledger.total_coins, 10);

  // add exchange rate field to metadata entries
  ledger.transactions.forEach(function(transaction) {
    if(!transaction.metaData || !transaction.metaData.AffectedNodes) {
      log.error('transaction in ledger: ' + ledger.ledger_index + ' does not have metaData');
      return;
    }

    transaction.metaData.AffectedNodes.forEach(function(affNode) {

      var node = affNode.CreatedNode || affNode.ModifiedNode || affNode.DeletedNode;

      if (node.LedgerEntryType !== 'Offer') {
        return;
      }

      var fields = node.FinalFields || node.NewFields;

      if (typeof fields.BookDirectory === 'string') {
        node.exchange_rate = ripple.Amount.from_quality(fields.BookDirectory).to_json().value;
      }

    });
  });

  ledger._id = Client.addLeadingZeros(ledger.ledger_index);
  return ledger;
}
Beispiel #5
0
 engine.processor.getLedger(ledger_index, function (err, e) {
   if (err) winston.error("Error loading ledger: " + err.message);
   else {
     var ledger_time = new Date(utils.toTimestamp(e.ledger.close_time));
     engine.aggregator.process(ledger_time, null, function (err) {
       if (err) winston.error("Error processing aggregate: " + err.message);
       engine.shutdown();
     });
   }
 });
Beispiel #6
0
    remote.requestLedger(transaction.ledger_index, function(err, res) {
      if (err) {
        return res.json(404, { success: false, message: 'Transaction ledger not found' });
      }

      if (typeof res.ledger.close_time === 'number') {
        transaction.date = ripple.utils.toTimestamp(res.ledger.close_time);
      }

      callback(null, transaction);
    });
Beispiel #7
0
function outgoingTransactionEntryToTransaction(db_entry) {
  var values = db_entry.values || db_entry;

  // Convert to format similar to getTx call
  var transaction = JSON.parse(values.tx_json);
  transaction.meta = transaction.meta || {};
  transaction.meta.TransactionResult = values.rippled_result;
  transaction.ledger_index = values.ledger;
  transaction.hash = values.hash;
  transaction.finalized = values.finalized;
  transaction.date = ripple.utils.fromTimestamp(new Date(values.updated_at || db_entry.updated_at));
  transaction.client_resource_id = values.client_resource_id;

  // Note that this value is used by notifications.js
  transaction.from_local_db = true;

  return transaction;
};
function txToNotification(opts){
  var address = opts.address, 
    tx, 
    meta, 
    prev_tx_hash;

  if (opts.tx_entry || opts.tx) {
    tx = (opts.tx_entry ? opts.tx_entry.tx : opts.tx_entry) || opts.tx;
    meta = (opts.tx_entry ? opts.tx_entry.meta : tx.meta);
  } else {
    prev_tx_hash = opts.prev_tx_hash;
  }

  var notification = {
    address: address || '',
    type: (tx && tx.TransactionType ? tx.TransactionType.toLowerCase() : ''),
    tx_direction: '',
    tx_state: '',
    tx_result: (meta ? meta.TransactionResult : ''),
    tx_ledger: (tx && tx.ledger_index ? tx.ledger_index : ''),
    tx_hash: (tx && tx.hash ? tx.hash : ''),
    tx_timestamp: (tx && tx.date ? ripple.utils.toTimestamp(tx.date) : ''),
    tx_url: '',
    next_notification_url: '',
    confirmation_token: ''
  };

  if (tx) {

    // Determine direction
    if (tx.Account) {
      if (address === tx.Account) {
        notification.tx_direction = 'outgoing';
      } else if (tx.TransactionType === 'Payment' && tx.Destination !== address) {
        notification.tx_direction = 'passthrough';
      } else {
        notification.tx_direction = 'incoming';
      }
    }

    // State
    if (meta) {
      if (meta.TransactionResult === 'tesSUCCESS') {
        notification.tx_state = 'confirmed';
      } else {
        notification.tx_state = 'failed';
      }
    }

    // Add URLs
    if (notification.tx_hash) {

      // Add next_notification URL
      notification.next_notification_url = '/addresses/' + notification.address + '/next_notification/' + (notification.tx_hash ? notification.tx_hash : '');

      if (notification.type) {
        // Add resource URL
        if (notification.type === 'payment') {
          notification.tx_url = '/addresses/' + notification.address + '/payments/' + notification.tx_hash;
        } else {
          notification.tx_url = '/addresses/' + notification.address + '/txs/' + notification.tx_hash;      
        }
      }
    }
  } else {
    notification.type = 'none';
    notification.tx_state = 'empty';

    // Add next_notification URL
    notification.next_notification_url = '/addresses/' + notification.address + '/next_notification/' + (prev_tx_hash ? prev_tx_hash : '');
  }

  return notification;
}
function parsePaymentFromTx(tx, opts, callback) {

  if (typeof opts === 'function') {
    callback = opts;
    opts = {};
  }

  if (!opts.account) {
    callback(new Error('Internal Error. must supply opts.account'));
    return;
  }

  if (tx.TransactionType !== 'Payment') {
    callback(new Error('Not a payment. The transaction corresponding to the given identifier is not a payment.'));
    return;
  }

  var payment = {

    // User supplied
    source_account: tx.Account,
    source_tag: (tx.SourceTag ? '' + tx.SourceTag : ''),
    source_amount: (tx.SendMax ?
      (typeof tx.SendMax === 'object' ?
        tx.SendMax :
        {
          value: utils.dropsToXrp(tx.SendMax),
          currency: 'XRP',
          issuer: ''
        }) :
      (typeof tx.Amount === 'string' ? 
        {
          value: utils.dropsToXrp(tx.Amount),
          currency: 'XRP',
          issuer: ''
        } :
        tx.Amount)),
    source_slippage: '0',

    destination_account: tx.Destination,
    destination_tag: (tx.DestinationTag ? '' + tx.DestinationTag : ''),
    destination_amount: (typeof tx.Amount === 'object' ? 
      tx.Amount : 
      {
        value: utils.dropsToXrp(tx.Amount),
        currency: 'XRP',
        issuer: ''
      }),

    // Advanced options
    invoice_id: tx.InvoiceID || '',
    paths: JSON.stringify(tx.Paths || []),
    no_direct_ripple: (tx.Flags & 0x00010000 ? true : false),
    partial_payment: (tx.Flags & 0x00020000 ? true : false),

    // Generated after validation
    direction: (opts.account ? 
      (opts.account === tx.Account ? 
        'outgoing' : 
        (opts.account === tx.Destination ? 
          'incoming' : 
          'passthrough')) :
      ''),
    state: tx.state || (tx.meta.TransactionResult === 'tesSUCCESS' ? 'validated' : 'failed'),
    result: tx.meta.TransactionResult || '',
    ledger: '' + (tx.inLedger || tx.ledger_index),
    hash: tx.hash || '',
    timestamp: (tx.date ? new Date(ripple.utils.toTimestamp(tx.date)).toISOString() : ''),
    fee: utils.dropsToXrp(tx.Fee) || '',
    source_balance_changes: [],
    destination_balance_changes: []

  };

  // Add source_balance_changes
  utils.parseBalanceChanges(tx, tx.Account).forEach(function(amount){
    if (amount.value < 0) {
      payment.source_balance_changes.push(amount);
    }
  });

  // Add destination_balance_changes
  utils.parseBalanceChanges(tx, tx.Destination).forEach(function(amount){
    if (amount.value > 0) {
      payment.destination_balance_changes.push(amount);
    }
  });

  callback(null, payment);
}
Beispiel #10
0
function parsePaymentFromTx(tx, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  if (!options.account) {
    if (callback !== void(0)) {
      callback(new Error('Internal Error. must supply options.account'));
    }
    return;
  }
  if (tx.TransactionType !== 'Payment') {
    if (callback !== void(0)) {
      callback(new Error('Not a payment. The transaction corresponding to the given identifier is not a payment.'));
    }
    return;
  }
  if (tx.meta !== void(0) && tx.meta.TransactionResult !== void(0)) {
    if (tx.meta.TransactionResult === 'tejSecretInvalid') {
      if (callback !== void(0)) {
        callback(new Error('Invalid secret provided.'));
      }
      return;
    }
  }

  var Amount;
  var isPartialPayment = tx.Flags & 0x00020000 ? true : false;

  // if there is a DeliveredAmount we should use it over Amount
  // there should always be a DeliveredAmount if the partial payment flag is set
  // also there shouldn't be a DeliveredAmount if there's no partial payment flag
  if(isPartialPayment && tx.meta && tx.meta.DeliveredAmount) {
    Amount = tx.meta.DeliveredAmount;
  } else {
    Amount = tx.Amount;
  }

  var payment = {
    // User supplied
    source_account: tx.Account,
    source_tag: (tx.SourceTag ? '' + tx.SourceTag : ''),
    source_amount: (tx.SendMax ?
      (typeof tx.SendMax === 'object' ?
        tx.SendMax :
        {
          value: utils.dropsToXrp(tx.SendMax),
          currency: 'XRP',
          issuer: ''
        }) :
      (typeof Amount === 'string' ?
        {
          value: utils.dropsToXrp(tx.Amount),
          currency: 'XRP',
          issuer: ''
        } :
        Amount)),
    source_slippage: '0',
    destination_account: tx.Destination,
    destination_tag: (tx.DestinationTag ? '' + tx.DestinationTag : ''),
    destination_amount: (typeof Amount === 'object' ?
      Amount :
      {
        value: utils.dropsToXrp(Amount),
        currency: 'XRP',
        issuer: ''
      }),
    // Advanced options
    invoice_id: tx.InvoiceID || '',
    paths: JSON.stringify(tx.Paths || []),
    no_direct_ripple: (tx.Flags & 0x00010000 ? true : false),
    partial_payment: isPartialPayment,
    // Generated after validation
    direction: (options.account ?
      (options.account === tx.Account ?
        'outgoing' :
        (options.account === tx.Destination ?
          'incoming' :
          'passthrough')) :
      ''),
    state: tx.state || tx.meta ? (tx.meta.TransactionResult === 'tesSUCCESS' ? 'validated' : 'failed') : '',
    result: tx.meta ? tx.meta.TransactionResult : '',
    ledger: '' + (tx.inLedger || tx.ledger_index),
    hash: tx.hash || '',
    timestamp: (tx.date ? new Date(ripple.utils.toTimestamp(tx.date)).toISOString() : ''),
    fee: utils.dropsToXrp(tx.Fee) || '',
    source_balance_changes: [],
    destination_balance_changes: []
  };
  // Add source_balance_changes
  utils.parseBalanceChanges(tx, tx.Account).forEach(function(amount){
    if (amount.value < 0) {
      payment.source_balance_changes.push(amount);
    }
  });
  // Add destination_balance_changes
  utils.parseBalanceChanges(tx, tx.Destination).forEach(function(amount){
    if (amount.value > 0) {
      payment.destination_balance_changes.push(amount);
    }
  });
  if (Array.isArray(tx.Memos) && tx.Memos.length > 0) {
    payment.memos = [];
    for(var m=0; m<tx.Memos.length; m++) {
      payment.memos.push(tx.Memos[m].Memo);
    }
  }
  if (isPartialPayment && tx.meta && tx.meta.DeliveredAmount) {
    payment.destination_amount_submitted = (typeof tx.Amount === 'object' ?
      tx.Amount :
    {
      value: utils.dropsToXrp(tx.Amount),
      currency: 'XRP',
      issuer: ''
    });
    payment.source_amount_submitted = (tx.SendMax ?
      (typeof tx.SendMax === 'object' ?
        tx.SendMax :
      {
        value: utils.dropsToXrp(tx.SendMax),
        currency: 'XRP',
        issuer: ''
      }) :
      (typeof tx.Amount === 'string' ?
      {
        value: utils.dropsToXrp(tx.Amount),
        currency: 'XRP',
        issuer: ''
      } :
        tx.Amount));
  }
  return payment;
};