mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 19:55:51 +00:00
Convert getAccountTransactions
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
[ignore]
|
||||
.*/src/.*
|
||||
.*/src/api/.*
|
||||
.*/src/core/.*
|
||||
.*/dist/.*
|
||||
.*/test/fixtures/.*
|
||||
|
||||
[include]
|
||||
./node_modules/
|
||||
|
||||
[libs]
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ RippleAPI.prototype = {
|
||||
getOrderBook: orders.getOrderBook,
|
||||
getSettings: settings.getSettings,
|
||||
getTransaction: transactions.getTransaction,
|
||||
getAccountTransactions: transactions.getAccountTransactions,
|
||||
getNotification: notifications.getNotification,
|
||||
getNotifications: notifications.getNotifications,
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
|
||||
function parseAmount(amount) {
|
||||
/*:: type Amount = string | {currency: string, issuer: string, value: string} */
|
||||
/*:: type XRPAmount = {currency: string, value: string} */
|
||||
/*:: type IOUAmount = {currency: string, value: string, counterparty: string} */
|
||||
/*:: type Output = XRPAmount | IOUAmount */
|
||||
function parseAmount(amount: Amount): Output {
|
||||
if (typeof amount === 'string') {
|
||||
return {
|
||||
currency: 'XRP',
|
||||
@@ -11,7 +16,7 @@ function parseAmount(amount) {
|
||||
return {
|
||||
currency: amount.currency,
|
||||
value: amount.value,
|
||||
counterparty: amount.issuer || amount.counterparty
|
||||
counterparty: amount.issuer
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
|
||||
function parseOrderCancellation(tx) {
|
||||
function parseOrderCancellation(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'OfferCancel');
|
||||
return {
|
||||
orderSequence: tx.OfferSequence
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const AccountFields = require('./utils').constants.AccountFields;
|
||||
|
||||
@@ -8,7 +9,7 @@ function parseField(info, value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseFields(data) {
|
||||
function parseFields(data: Object): Object {
|
||||
const settings = {};
|
||||
for (const fieldName in AccountFields) {
|
||||
const fieldValue = data[fieldName];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* @flow */
|
||||
/* eslint-disable valid-jsdoc */
|
||||
'use strict';
|
||||
const ripple = require('../utils').common.core;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parseAmount = require('./amount');
|
||||
const flags = utils.core.Transaction.flags.OfferCreate;
|
||||
|
||||
function parseOrder(tx) {
|
||||
function parseOrder(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'OfferCreate');
|
||||
|
||||
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell';
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const parseAmount = require('./amount');
|
||||
|
||||
function parsePathfind(sourceAddress, destinationAmount, pathfindResult) {
|
||||
function parsePathfind(sourceAddress: string,
|
||||
destinationAmount: Object, pathfindResult: Object): Object {
|
||||
return pathfindResult.alternatives.map(function(alternative) {
|
||||
return {
|
||||
source: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
@@ -19,7 +20,7 @@ function parsePaymentMemos(tx) {
|
||||
return tx.Memos.map((m) => m.Memo);
|
||||
}
|
||||
|
||||
function parsePayment(tx) {
|
||||
function parsePayment(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'Payment');
|
||||
|
||||
const source = {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
@@ -8,7 +9,7 @@ function getName(flagNumber) {
|
||||
return _.findKey(AccountSetFlags, (v) => v === flagNumber);
|
||||
}
|
||||
|
||||
function parseSettings(tx) {
|
||||
function parseSettings(tx: Object) {
|
||||
const txType = tx.TransactionType;
|
||||
assert(txType === 'AccountSet' || txType === 'SetRegularKey');
|
||||
const settings = {};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
@@ -19,7 +20,7 @@ function parseTransactionType(type) {
|
||||
return mapping[type] || null;
|
||||
}
|
||||
|
||||
function parseTransaction(tx) {
|
||||
function parseTransaction(tx: Object): ?Object {
|
||||
const type = parseTransactionType(tx.TransactionType);
|
||||
const mapping = {
|
||||
'payment': parsePayment,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const flags = utils.core.Transaction.flags.TrustSet;
|
||||
|
||||
function parseTrustline(tx) {
|
||||
function parseTrustline(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'TrustSet');
|
||||
|
||||
return {
|
||||
@@ -12,9 +13,9 @@ function parseTrustline(tx) {
|
||||
counterparty: tx.LimitAmount.issuer,
|
||||
qualityIn: tx.QualityIn,
|
||||
qualityOut: tx.QualityOut,
|
||||
allowRippling: tx.Flags & flags.NoRipple === 0,
|
||||
frozen: tx.Flags & flags.SetFreeze !== 0,
|
||||
authorized: tx.Flags & flags.SetAuth !== 0
|
||||
allowRippling: (tx.Flags & flags.NoRipple) === 0,
|
||||
frozen: (tx.Flags & flags.SetFreeze) !== 0,
|
||||
authorized: (tx.Flags & flags.SetAuth) !== 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const transactionParser = require('ripple-lib-transactionparser');
|
||||
const toTimestamp = require('../../../core/utils').toTimestamp;
|
||||
const utils = require('../utils');
|
||||
|
||||
function parseTimestamp(tx) {
|
||||
function parseTimestamp(tx: {date: string}): string | void {
|
||||
return tx.date ? (new Date(toTimestamp(tx.date))).toISOString() : undefined;
|
||||
}
|
||||
|
||||
function removeUndefined(obj) {
|
||||
function removeUndefined(obj: ?Object): ?Object {
|
||||
return obj ? _.omit(obj, _.isUndefined) : obj;
|
||||
}
|
||||
|
||||
function parseOutcome(tx) {
|
||||
function parseOutcome(tx: Object): ?Object {
|
||||
if (!tx.validated) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -27,6 +28,7 @@ function parseOutcome(tx) {
|
||||
balanceChanges: balanceChanges,
|
||||
orderbookChanges: orderbookChanges,
|
||||
ledgerVersion: tx.ledger_index,
|
||||
indexInLedger: tx.meta.TransactionIndex,
|
||||
sequence: tx.Sequence
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const parseTransaction = require('./parse/transaction');
|
||||
const validate = utils.common.validate;
|
||||
const errors = utils.common.errors;
|
||||
|
||||
const DEFAULT_RESULTS_PER_PAGE = 10;
|
||||
const DEFAULT_LIMIT = 100;
|
||||
const MIN_LEDGER_VERSION = 32570; // earlier versions have been completely lost
|
||||
|
||||
function hasCompleteLedgerRange(remote, options) {
|
||||
@@ -74,228 +74,86 @@ function getTransaction(identifier, options, callback) {
|
||||
], callbackWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around the standard ripple-lib requestAccountTx function
|
||||
*
|
||||
* @param {Remote} remote
|
||||
* @param {RippleAddress} options.account
|
||||
* @param {Number} [-1] options.ledger_index_min
|
||||
* @param {Number} [-1] options.ledger_index_max
|
||||
* @param {Boolean} [false] options.earliestFirst
|
||||
* @param {Boolean} [false] options.binary
|
||||
* @param {opaque value} options.marker
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @callback
|
||||
* @param {Error} error
|
||||
* @param {Array of transactions in JSON format} response.transactions
|
||||
* @param {opaque value} response.marker
|
||||
*/
|
||||
function getAccountTx(api, options, callback) {
|
||||
function parseAccountTxTransaction(tx) {
|
||||
// rippled uses a different response format for 'account_tx' than 'tx'
|
||||
tx.tx.meta = tx.meta;
|
||||
tx.tx.validated = tx.validated;
|
||||
return parseTransaction(tx.tx);
|
||||
}
|
||||
|
||||
function getAccountTx(remote, address, limit, marker, options, callback) {
|
||||
const params = {
|
||||
account: options.account,
|
||||
ledger_index_min: options.ledger_index_min || options.ledger_index || -1,
|
||||
ledger_index_max: options.ledger_index_max || options.ledger_index || -1,
|
||||
limit: options.limit || DEFAULT_RESULTS_PER_PAGE,
|
||||
account: address,
|
||||
ledger_index_min: options.ledgerVersion || options.minLedgerVersion || -1,
|
||||
ledger_index_max: options.ledgerVersion || options.maxLedgerVersion || -1,
|
||||
forward: options.earliestFirst,
|
||||
marker: options.marker
|
||||
binary: options.binary,
|
||||
limit: Math.min(limit || DEFAULT_LIMIT, 10),
|
||||
marker: marker
|
||||
};
|
||||
if (options.binary) {
|
||||
params.binary = true;
|
||||
|
||||
remote.requestAccountTx(params, (error, data) => {
|
||||
return error ? callback(error) : callback(null, {
|
||||
transactions: data.transactions.filter((tx) => tx.validated)
|
||||
.map(parseAccountTxTransaction),
|
||||
marker: data.marker
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function transactionFilter(address, filters, tx) {
|
||||
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
||||
return false;
|
||||
}
|
||||
api.remote.requestAccountTx(params, function(error, account_tx_results) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
const transactions = [];
|
||||
account_tx_results.transactions.forEach(function(tx_entry) {
|
||||
if (!tx_entry.validated) {
|
||||
return;
|
||||
}
|
||||
const tx = tx_entry.tx;
|
||||
tx.meta = tx_entry.meta;
|
||||
tx.validated = tx_entry.validated;
|
||||
transactions.push(tx);
|
||||
});
|
||||
callback(null, {
|
||||
transactions: transactions,
|
||||
marker: account_tx_results.marker
|
||||
});
|
||||
});
|
||||
if (filters.types && !_.includes(filters.types, tx.type)) {
|
||||
return false;
|
||||
}
|
||||
if (filters.outgoing && tx.address !== address) {
|
||||
return false;
|
||||
}
|
||||
if (filters.incoming && tx.address === address) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter transactions based on the given set of options.
|
||||
*
|
||||
* @param {Array of transactions in JSON format} transactions
|
||||
* @param {Boolean} [false] options.exclude_failed
|
||||
* @param {Array of Strings} options.types Possible values are "payment",
|
||||
* "offercreate", "offercancel", "trustset", "accountset"
|
||||
* @param {RippleAddress} options.source_account
|
||||
* @param {RippleAddress} options.destination_account
|
||||
* @param {String} options.direction Possible values are "incoming", "outgoing"
|
||||
*
|
||||
* @returns {Array of transactions in JSON format} filtered_transactions
|
||||
*/
|
||||
function transactionFilter(transactions, options) {
|
||||
const filtered_transactions = transactions.filter(function(transaction) {
|
||||
if (options.exclude_failed) {
|
||||
if (transaction.state === 'failed' || (transaction.meta
|
||||
&& transaction.meta.TransactionResult !== 'tesSUCCESS')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (options.types && options.types.length > 0) {
|
||||
if (options.types.indexOf(
|
||||
transaction.TransactionType.toLowerCase()) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (options.source_account) {
|
||||
if (transaction.Account !== options.source_account) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (options.destination_account) {
|
||||
if (transaction.Destination !== options.destination_account) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (options.direction) {
|
||||
if (options.direction === 'outgoing'
|
||||
&& transaction.Account !== options.account) {
|
||||
return false;
|
||||
}
|
||||
if (options.direction === 'incoming' && transaction.Destination
|
||||
&& transaction.Destination !== options.account) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return filtered_transactions;
|
||||
}
|
||||
|
||||
function getTransactionsHelper(api, options, callback) {
|
||||
getAccountTx(api, options, function(error, results) {
|
||||
function getAccountTransactionsRecursive(
|
||||
remote, address, limit, marker, options, callback) {
|
||||
getAccountTx(remote, address, limit, marker, options, (error, data) => {
|
||||
if (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
const filter = _.partial(transactionFilter, address, options);
|
||||
const unfilteredTransactions = data.transactions;
|
||||
const filteredTransactions = unfilteredTransactions.filter(filter);
|
||||
const isExhausted = unfilteredTransactions.length === 0;
|
||||
if (!isExhausted && filteredTransactions.length < limit) {
|
||||
const remaining = limit - filteredTransactions.length;
|
||||
getAccountTransactionsRecursive(
|
||||
remote, address, remaining, data.marker, options, (_err, txs) => {
|
||||
return error ? callback(_err) :
|
||||
callback(null, filteredTransactions.concat(txs));
|
||||
});
|
||||
} else {
|
||||
// Set marker so that when this function is called again
|
||||
// recursively it starts from the last place it left off
|
||||
options.marker = results.marker;
|
||||
callback(null, results.transactions);
|
||||
callback(null, filteredTransactions.slice(0, limit));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively get transactions for the specified account from
|
||||
* the Remote. If options.min is set, this will
|
||||
* recurse until it has retrieved that number of transactions or
|
||||
* it has reached the end of the account's transaction history.
|
||||
*
|
||||
* @param {Remote} remote
|
||||
* @param {RippleAddress} options.account
|
||||
* @param {Number} [-1] options.ledger_index_min
|
||||
* @param {Number} [-1] options.ledger_index_max
|
||||
* @param {Boolean} [false] options.earliestFirst
|
||||
* @param {Boolean} [false] options.binary
|
||||
* @param {Boolean} [false] options.exclude_failed
|
||||
* @param {Number} [DEFAULT_RESULTS_PER_PAGE] options.min
|
||||
* @param {Number} [DEFAULT_RESULTS_PER_PAGE] options.max
|
||||
* @param {Array of Strings} options.types Possible values are "payment",
|
||||
* "offercreate", "offercancel", "trustset", "accountset"
|
||||
* @param {opaque value} options.marker
|
||||
* @param {Array of Transactions} options.previous_transactions
|
||||
* Included automatically when this function is called recursively
|
||||
* @param {Express.js Response} res
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @callback
|
||||
* @param {Error} error
|
||||
* @param {Array of transactions in JSON format} transactions
|
||||
*/
|
||||
function getAccountTransactions(api, options, callback) {
|
||||
try {
|
||||
validate.address(options.account);
|
||||
} catch(err) {
|
||||
return callback(err);
|
||||
}
|
||||
function getAccountTransactions(address, options, callback) {
|
||||
validate.address(address);
|
||||
|
||||
if (!options.min) {
|
||||
options.min = module.exports.DEFAULT_RESULTS_PER_PAGE;
|
||||
}
|
||||
if (!options.max) {
|
||||
options.max = Math.max(options.min,
|
||||
module.exports.DEFAULT_RESULTS_PER_PAGE);
|
||||
}
|
||||
if (!options.limit) {
|
||||
options.limit = module.exports.DEFAULT_LIMIT;
|
||||
}
|
||||
|
||||
function queryTransactions(async_callback) {
|
||||
getTransactionsHelper(api, options, async_callback);
|
||||
}
|
||||
|
||||
function filterTransactions(transactions, async_callback) {
|
||||
async_callback(null, transactionFilter(transactions, options));
|
||||
}
|
||||
|
||||
function sortTransactions(transactions, async_callback) {
|
||||
const compare = options.earliestFirst ? utils.compareTransactions :
|
||||
_.rearg(utils.compareTransactions, 1, 0);
|
||||
transactions.sort(compare);
|
||||
async_callback(null, transactions);
|
||||
}
|
||||
|
||||
function mergeAndTruncateResults(txns, async_callback) {
|
||||
let transactions = txns;
|
||||
if (options.previous_transactions
|
||||
&& options.previous_transactions.length > 0) {
|
||||
transactions = options.previous_transactions.concat(transactions);
|
||||
}
|
||||
if (options.offset && options.offset > 0) {
|
||||
const offset_remaining = options.offset - transactions.length;
|
||||
transactions = transactions.slice(options.offset);
|
||||
options.offset = offset_remaining;
|
||||
}
|
||||
if (transactions.length > options.max) {
|
||||
transactions = transactions.slice(0, options.max);
|
||||
}
|
||||
async_callback(null, transactions);
|
||||
}
|
||||
|
||||
function asyncWaterfallCallback(error, transactions) {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
if (!options.min || transactions.length >= options.min || !options.marker) {
|
||||
callback(null, transactions);
|
||||
} else {
|
||||
options.previous_transactions = transactions;
|
||||
setImmediate(function() {
|
||||
getAccountTransactions(api, options, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const steps = [
|
||||
queryTransactions,
|
||||
filterTransactions,
|
||||
sortTransactions,
|
||||
mergeAndTruncateResults
|
||||
];
|
||||
|
||||
async.waterfall(steps, asyncWaterfallCallback);
|
||||
const limit = options.limit || DEFAULT_LIMIT;
|
||||
const compare = options.earliestFirst ? utils.compareTransactions :
|
||||
_.rearg(utils.compareTransactions, 1, 0);
|
||||
getAccountTransactionsRecursive(
|
||||
this.remote, address, limit, null, options, (error, transactions) => {
|
||||
return error ? callback(error) : callback(null, transactions.sort(compare));
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DEFAULT_LIMIT: 200,
|
||||
DEFAULT_RESULTS_PER_PAGE: DEFAULT_RESULTS_PER_PAGE,
|
||||
NUM_TRANSACTION_TYPES: 5,
|
||||
DEFAULT_LEDGER_BUFFER: 3,
|
||||
getTransaction: utils.wrapCatch(getTransaction),
|
||||
getAccountTransactions: getAccountTransactions
|
||||
getAccountTransactions: utils.wrapCatch(getAccountTransactions)
|
||||
};
|
||||
|
||||
@@ -58,12 +58,10 @@ function signum(num) {
|
||||
* @returns {Number} [-1, 0, 1]
|
||||
*/
|
||||
function compareTransactions(first, second) {
|
||||
if (first.ledger_index === second.ledger_index) {
|
||||
return signum(
|
||||
Number(first.meta.TransactionIndex) -
|
||||
Number(second.meta.TransactionIndex));
|
||||
if (first.ledgerVersion === second.ledgerVersion) {
|
||||
return signum(Number(first.indexInLedger) - Number(second.indexInLedger));
|
||||
}
|
||||
return Number(first.ledger_index) < Number(second.ledger_index) ? -1 : 1;
|
||||
return Number(first.ledgerVersion) < Number(second.ledgerVersion) ? -1 : 1;
|
||||
}
|
||||
|
||||
function attachDate(api, baseTransactions, callback) {
|
||||
|
||||
@@ -22,6 +22,8 @@ const MockPRNG = require('./mock-prng');
|
||||
const sjcl = require('../src').sjcl;
|
||||
const submitResponse = require('./fixtures/submit-response');
|
||||
const transactionResponse = require('./fixtures/transaction-response');
|
||||
const accountTransactionsResponse =
|
||||
require('./fixtures/account-transactions-response');
|
||||
|
||||
function checkResult(expected, done, error, response) {
|
||||
if (error) {
|
||||
@@ -91,4 +93,10 @@ describe('RippleAPI', function() {
|
||||
this.api.getTransaction(hashes.VALID_TRANSACTION_HASH, {},
|
||||
_.partial(checkResult, transactionResponse, done));
|
||||
});
|
||||
|
||||
it('getAccountTransactions', function(done) {
|
||||
const options = {types: ['payment', 'order'], outgoing: true, limit: 2};
|
||||
this.api.getAccountTransactions(address, options,
|
||||
_.partial(checkResult, accountTransactionsResponse, done));
|
||||
});
|
||||
});
|
||||
|
||||
180
test/fixtures/account-transactions-response.json
vendored
Normal file
180
test/fixtures/account-transactions-response.json
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
[
|
||||
{
|
||||
"type": "payment",
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"specification": {
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"currency": "XRP",
|
||||
"value": "1.112209"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"paths": "[[{\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":48,\"type_hex\":\"0000000000000030\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":49,\"type_hex\":\"0000000000000031\"}]]",
|
||||
"allowPartialPayment": false,
|
||||
"noDirectRipple": false
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"currency": "USD",
|
||||
"value": "-0.001"
|
||||
},
|
||||
{
|
||||
"counterparty": "r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr",
|
||||
"currency": "USD",
|
||||
"value": "0.001002"
|
||||
}
|
||||
],
|
||||
"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM": [
|
||||
{
|
||||
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"currency": "USD",
|
||||
"value": "0.001"
|
||||
}
|
||||
],
|
||||
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59": [
|
||||
{
|
||||
"counterparty": "",
|
||||
"currency": "XRP",
|
||||
"value": "-1.101208"
|
||||
}
|
||||
],
|
||||
"r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr": [
|
||||
{
|
||||
"counterparty": "",
|
||||
"currency": "XRP",
|
||||
"value": "1.101198"
|
||||
},
|
||||
{
|
||||
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"currency": "USD",
|
||||
"value": "-0.001002"
|
||||
}
|
||||
]
|
||||
},
|
||||
"orderbookChanges": {
|
||||
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59": [
|
||||
{
|
||||
"taker_pays": {
|
||||
"currency": "XRP",
|
||||
"counterparty": "",
|
||||
"value": "-1.101198"
|
||||
},
|
||||
"taker_gets": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"value": "-0.001002"
|
||||
},
|
||||
"sequence": 58,
|
||||
"status": "open"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ledgerVersion": 348860,
|
||||
"indexInLedger": 0,
|
||||
"sequence": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "payment",
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"specification": {
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"currency": "XRP",
|
||||
"value": "1.112209"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"paths": "[[{\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":48,\"type_hex\":\"0000000000000030\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":49,\"type_hex\":\"0000000000000031\"}]]",
|
||||
"allowPartialPayment": false,
|
||||
"noDirectRipple": false
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"currency": "USD",
|
||||
"value": "-0.001"
|
||||
},
|
||||
{
|
||||
"counterparty": "r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr",
|
||||
"currency": "USD",
|
||||
"value": "0.001002"
|
||||
}
|
||||
],
|
||||
"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM": [
|
||||
{
|
||||
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"currency": "USD",
|
||||
"value": "0.001"
|
||||
}
|
||||
],
|
||||
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59": [
|
||||
{
|
||||
"counterparty": "",
|
||||
"currency": "XRP",
|
||||
"value": "-1.101208"
|
||||
}
|
||||
],
|
||||
"r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr": [
|
||||
{
|
||||
"counterparty": "",
|
||||
"currency": "XRP",
|
||||
"value": "1.101198"
|
||||
},
|
||||
{
|
||||
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"currency": "USD",
|
||||
"value": "-0.001002"
|
||||
}
|
||||
]
|
||||
},
|
||||
"orderbookChanges": {
|
||||
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59": [
|
||||
{
|
||||
"taker_pays": {
|
||||
"currency": "XRP",
|
||||
"counterparty": "",
|
||||
"value": "-1.101198"
|
||||
},
|
||||
"taker_gets": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"value": "-0.001002"
|
||||
},
|
||||
"sequence": 58,
|
||||
"status": "open"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ledgerVersion": 348860,
|
||||
"indexInLedger": 0,
|
||||
"sequence": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
209
test/fixtures/acct-tx-response.js
vendored
Normal file
209
test/fixtures/acct-tx-response.js
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/* eslint-disable max-len */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const hashes = require('./hashes');
|
||||
const addresses = require('./addresses');
|
||||
const SerializedObject = require('../../src/core').SerializedObject;
|
||||
|
||||
module.exports = function(request, options={}) {
|
||||
_.defaults(options, {
|
||||
memos: [],
|
||||
hash: hashes.VALID_TRANSACTION_HASH,
|
||||
validated: true
|
||||
});
|
||||
|
||||
const tx = {
|
||||
Account: addresses.ACCOUNT,
|
||||
Amount: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.001'
|
||||
},
|
||||
Destination: addresses.ISSUER,
|
||||
Fee: '10',
|
||||
Flags: 0,
|
||||
Memos: options.memos,
|
||||
Paths: [
|
||||
[
|
||||
{
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
type: 48,
|
||||
type_hex: '0000000000000030'
|
||||
},
|
||||
{
|
||||
account: addresses.OTHER_ACCOUNT,
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}
|
||||
]
|
||||
],
|
||||
SendMax: '1112209',
|
||||
Sequence: 4,
|
||||
SigningPubKey: '02BC8C02199949B15C005B997E7C8594574E9B02BA2D0628902E0532989976CF9D',
|
||||
TransactionType: 'Payment',
|
||||
TxnSignature: '304502204EE3E9D1B01D8959B08450FCA9E22025AF503DEF310E34A93863A85CAB3C0BC5022100B61F5B567F77026E8DEED89EED0B7CAF0E6C96C228A2A65216F0DC2D04D52083'
|
||||
};
|
||||
|
||||
const meta = {
|
||||
AffectedNodes: [
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5E03E788E09BB000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
OwnerNode: '0000000000000000',
|
||||
Sequence: 58,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '5.648998'
|
||||
},
|
||||
TakerPays: '6208248802'
|
||||
},
|
||||
LedgerEntryType: 'Offer',
|
||||
LedgerIndex: '3CFB3C79D4F1BDB1EE5245259372576D926D9A875713422F7169A6CC60AFA68B',
|
||||
PreviousFields: {
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '5.65'
|
||||
},
|
||||
TakerPays: '6209350000'
|
||||
},
|
||||
PreviousTxnID: '8F571C346688D89AC1F737AE3B6BB5D976702B171CC7B4DE5CA3D444D5B8D6B4',
|
||||
PreviousTxnLgrSeq: 348433
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '-0.001'
|
||||
},
|
||||
Flags: 131072,
|
||||
HighLimit: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '1'
|
||||
},
|
||||
HighNode: '0000000000000000',
|
||||
LowLimit: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '0'
|
||||
},
|
||||
LowNode: '0000000000000002'
|
||||
},
|
||||
LedgerEntryType: 'RippleState',
|
||||
LedgerIndex: '4BD1874F8F3A60EDB0C23F5BD43E07953C2B8741B226648310D113DE2B486F01',
|
||||
PreviousFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '0'
|
||||
}
|
||||
},
|
||||
PreviousTxnID: '5B2006DAD0B3130F57ACF7CC5CCAC2EEBCD4B57AAA091A6FD0A24B073D08ABB8',
|
||||
PreviousTxnLgrSeq: 343703
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.ACCOUNT,
|
||||
Balance: '9998898762',
|
||||
Flags: 0,
|
||||
OwnerCount: 3,
|
||||
Sequence: 5
|
||||
},
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
LedgerIndex: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05',
|
||||
PreviousFields: {
|
||||
Balance: '9999999970',
|
||||
Sequence: 4
|
||||
},
|
||||
PreviousTxnID: '53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8',
|
||||
PreviousTxnLgrSeq: 343570
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: 'r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr',
|
||||
Balance: '912695302618',
|
||||
Flags: 0,
|
||||
OwnerCount: 10,
|
||||
Sequence: 59
|
||||
},
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
LedgerIndex: 'F3E119AAA87AF3607CF87F5523BB8278A83BCB4142833288305D767DD30C392A',
|
||||
PreviousFields: {
|
||||
Balance: '912694201420'
|
||||
},
|
||||
PreviousTxnID: '8F571C346688D89AC1F737AE3B6BB5D976702B171CC7B4DE5CA3D444D5B8D6B4',
|
||||
PreviousTxnLgrSeq: 348433
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '-5.5541638883365'
|
||||
},
|
||||
Flags: 131072,
|
||||
HighLimit: {
|
||||
currency: 'USD',
|
||||
issuer: 'r9tGqzZgKxVFvzKFdUqXAqTzazWBUia8Qr',
|
||||
value: '1000'
|
||||
},
|
||||
HighNode: '0000000000000000',
|
||||
LowLimit: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.OTHER_ACCOUNT,
|
||||
value: '0'
|
||||
},
|
||||
LowNode: '000000000000000C'
|
||||
},
|
||||
LedgerEntryType: 'RippleState',
|
||||
LedgerIndex: 'FA1255C2E0407F1945BCF9351257C7C5C28B0F5F09BB81C08D35A03E9F0136BC',
|
||||
PreviousFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '-5.5551658883365'
|
||||
}
|
||||
},
|
||||
PreviousTxnID: '8F571C346688D89AC1F737AE3B6BB5D976702B171CC7B4DE5CA3D444D5B8D6B4',
|
||||
PreviousTxnLgrSeq: 348433
|
||||
}
|
||||
}
|
||||
],
|
||||
TransactionIndex: 0,
|
||||
TransactionResult: 'tesSUCCESS'
|
||||
};
|
||||
|
||||
return JSON.stringify({
|
||||
id: request.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
transactions: [
|
||||
{
|
||||
ledger_index: 348860,
|
||||
tx_blob: SerializedObject.from_json(tx).to_hex(),
|
||||
meta: SerializedObject.from_json(meta).to_hex(),
|
||||
validated: options.validated
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
||||
3
test/fixtures/mock.js
vendored
3
test/fixtures/mock.js
vendored
@@ -2,9 +2,12 @@
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const addresses = require('./addresses');
|
||||
const accountTransactionsResponse = require('./acct-tx-response');
|
||||
const SerializedObject = require('ripple-lib').SerializedObject;
|
||||
const BASE_LEDGER_INDEX = 8819951;
|
||||
|
||||
module.exports.accountTransactionsResponse = accountTransactionsResponse;
|
||||
|
||||
module.exports.subscribeResponse = function(request) {
|
||||
return JSON.stringify({
|
||||
id: request.id,
|
||||
|
||||
1
test/fixtures/transaction-response.json
vendored
1
test/fixtures/transaction-response.json
vendored
@@ -84,6 +84,7 @@
|
||||
]
|
||||
},
|
||||
"ledgerVersion": 348860,
|
||||
"indexInLedger": 0,
|
||||
"sequence": 4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,5 +112,13 @@ module.exports = function(port) {
|
||||
}
|
||||
});
|
||||
|
||||
mock.on('request_account_tx', function(request, conn) {
|
||||
if (request.account === addresses.ACCOUNT) {
|
||||
conn.send(fixtures.accountTransactionsResponse(request));
|
||||
} else {
|
||||
assert(false, 'Unrecognized account address: ' + request.account);
|
||||
}
|
||||
});
|
||||
|
||||
return mock;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user