mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-21 04:35:49 +00:00
Add getTrustlines and unit test
This commit is contained in:
@@ -10,13 +10,11 @@
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"ledgerVersion": {
|
||||
"anyOf": [
|
||||
{"enum": ["current", "closed", "validated"]},
|
||||
{"$ref": "ledgerVersion"},
|
||||
{"type": "string", "format": "ledgerHash"}
|
||||
]
|
||||
"ledgerHash": {
|
||||
"type": "string",
|
||||
"format": "ledgerHash"
|
||||
},
|
||||
"ledgerVersion": {"$ref": "ledgerVersion"},
|
||||
"minLedgerVersion": {"$ref": "ledgerVersion"},
|
||||
"maxLedgerVersion": {"$ref": "ledgerVersion"},
|
||||
"marker": {
|
||||
|
||||
30
src/api/ledger/parse/account-trustline.js
Normal file
30
src/api/ledger/parse/account-trustline.js
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
|
||||
// rippled 'account_lines' returns a different format for
|
||||
// trustlines than 'tx'
|
||||
function parseAccountTrustline(trustline) {
|
||||
const specification = utils.removeUndefined({
|
||||
limit: trustline.limit,
|
||||
currency: trustline.currency,
|
||||
counterparty: trustline.account,
|
||||
qualityIn: trustline.quality_in || undefined,
|
||||
qualityOut: trustline.quality_out || undefined,
|
||||
disableRippling: trustline.no_ripple,
|
||||
frozen: trustline.freeze,
|
||||
authorized: trustline.authorized
|
||||
});
|
||||
// rippled doesn't provide the counterparty's qualities
|
||||
const counterparty = utils.removeUndefined({
|
||||
limit: trustline.limit_peer,
|
||||
disableRippling: trustline.no_ripple_peer,
|
||||
frozen: trustline.freeze_peer,
|
||||
authorized: trustline.peer_authorized
|
||||
});
|
||||
const state = {
|
||||
balance: trustline.balance
|
||||
};
|
||||
return {specification, counterparty, state};
|
||||
}
|
||||
|
||||
module.exports = parseAccountTrustline;
|
||||
@@ -13,7 +13,7 @@ function parseTrustline(tx: Object): Object {
|
||||
counterparty: tx.LimitAmount.issuer,
|
||||
qualityIn: tx.QualityIn,
|
||||
qualityOut: tx.QualityOut,
|
||||
allowRippling: (tx.Flags & flags.NoRipple) === 0,
|
||||
disableRippling: (tx.Flags & flags.NoRipple) !== 0,
|
||||
frozen: (tx.Flags & flags.SetFreeze) !== 0,
|
||||
authorized: (tx.Flags & flags.SetAuth) !== 0
|
||||
};
|
||||
|
||||
@@ -81,25 +81,6 @@ function parseAccountTxTransaction(tx) {
|
||||
return parseTransaction(tx.tx);
|
||||
}
|
||||
|
||||
function getAccountTx(remote, address, limit, marker, options, callback) {
|
||||
const params = {
|
||||
account: address,
|
||||
ledger_index_min: options.ledgerVersion || options.minLedgerVersion || -1,
|
||||
ledger_index_max: options.ledgerVersion || options.maxLedgerVersion || -1,
|
||||
forward: options.earliestFirst,
|
||||
binary: options.binary,
|
||||
limit: Math.min(limit || DEFAULT_LIMIT, 10),
|
||||
marker: marker
|
||||
};
|
||||
|
||||
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') {
|
||||
@@ -117,27 +98,25 @@ function transactionFilter(address, filters, tx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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));
|
||||
function getAccountTx(remote, address, options, marker, limit, callback) {
|
||||
const params = {
|
||||
account: address,
|
||||
ledger_index_min: options.ledgerVersion || options.minLedgerVersion || -1,
|
||||
ledger_index_max: options.ledgerVersion || options.maxLedgerVersion || -1,
|
||||
forward: options.earliestFirst,
|
||||
binary: options.binary,
|
||||
limit: Math.min(limit || DEFAULT_LIMIT, 10),
|
||||
marker: marker
|
||||
};
|
||||
|
||||
remote.requestAccountTx(params, (error, data) => {
|
||||
return error ? callback(error) : callback(null, {
|
||||
marker: data.marker,
|
||||
results: data.transactions
|
||||
.filter((tx) => tx.validated)
|
||||
.map(parseAccountTxTransaction)
|
||||
.filter(_.partial(transactionFilter, address, options))
|
||||
});
|
||||
} else {
|
||||
callback(null, filteredTransactions.slice(0, limit));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,9 +126,9 @@ function getAccountTransactions(address, options, callback) {
|
||||
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));
|
||||
const getter = _.partial(getAccountTx, this.remote, address, options);
|
||||
utils.getRecursive(getter, limit, (error, data) => {
|
||||
return error ? callback(error) : callback(null, data.sort(compare));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,127 +1,48 @@
|
||||
/* globals Promise: true */
|
||||
/* eslint-disable valid-jsdoc */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const validate = utils.common.validate;
|
||||
const parseAccountTrustline = require('./parse/account-trustline');
|
||||
|
||||
const DefaultPageLimit = 200;
|
||||
function currencyFilter(currency, trustline) {
|
||||
return currency === null || trustline.specification.currency === currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all trustlines for a given account
|
||||
*
|
||||
* Notes:
|
||||
* In order to use paging, you must provide at least ledger as a query parameter
|
||||
* Additionally, any limit lower than 10 will be bumped up to 10.
|
||||
*
|
||||
* @url
|
||||
* @param {String} request.params.account - account to retrieve trustlines for
|
||||
*
|
||||
* @query
|
||||
* @param {String ISO 4217 Currency Code} [request.query.currency]
|
||||
* - only request trustlines with given currency
|
||||
* @param {RippleAddress} [request.query.counterparty]
|
||||
* - only request trustlines with given counterparty
|
||||
* @param {String} [request.query.marker] - start position in response paging
|
||||
* @param {Number String} [request.query.limit] - max results per response
|
||||
* @param {Number String} [request.query.ledger] - identifier
|
||||
*
|
||||
*/
|
||||
function getTrustLines(account, options, callback) {
|
||||
function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
|
||||
callback) {
|
||||
const requestOptions = {
|
||||
account: address,
|
||||
ledger: ledgerVersion,
|
||||
marker: marker,
|
||||
limit: Math.max(limit, 10),
|
||||
peer: options.counterparty
|
||||
};
|
||||
|
||||
const currency = options.currency ? options.currency.toUpperCase() : null;
|
||||
remote.requestAccountLines(requestOptions, (error, data) => {
|
||||
return error ? callback(error) :
|
||||
callback(null, {
|
||||
marker: data.marker,
|
||||
results: data.lines.map(parseAccountTrustline)
|
||||
.filter(_.partial(currencyFilter, currency))
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*:: type Options = {currency: string, counterparty: string,
|
||||
limit: number, ledgerVersion: number} */
|
||||
function getTrustlines(account: string, options: Options,
|
||||
callback: () => void): void {
|
||||
validate.address(account);
|
||||
validate.options(options);
|
||||
|
||||
const self = this;
|
||||
|
||||
const currencyRE = new RegExp(options.currency ?
|
||||
('^' + options.currency.toUpperCase() + '$') : /./);
|
||||
|
||||
function getAccountLines(prevResult) {
|
||||
const isAggregate = options.limit === undefined;
|
||||
if (prevResult && (!isAggregate || !prevResult.marker)) {
|
||||
return Promise.resolve(prevResult);
|
||||
const defaultLimit = 100;
|
||||
const limit = options.limit || defaultLimit;
|
||||
const ledgerVersion = options.ledgerVersion
|
||||
|| this.remote.getLedgerSequence();
|
||||
const getter = _.partial(getAccountLines, this.remote, account,
|
||||
ledgerVersion, options);
|
||||
utils.getRecursive(getter, limit, callback);
|
||||
}
|
||||
|
||||
const promise = new Promise(function(resolve, reject) {
|
||||
let accountLinesRequest;
|
||||
let marker;
|
||||
let ledger;
|
||||
let limit;
|
||||
|
||||
if (prevResult) {
|
||||
marker = prevResult.marker;
|
||||
limit = prevResult.limit;
|
||||
ledger = prevResult.ledger_index;
|
||||
} else {
|
||||
marker = options.marker;
|
||||
limit = options.limit || DefaultPageLimit;
|
||||
ledger = utils.parseLedger(options.ledger);
|
||||
}
|
||||
|
||||
accountLinesRequest = self.remote.requestAccountLines({
|
||||
account: account,
|
||||
marker: marker,
|
||||
limit: limit,
|
||||
ledger: ledger
|
||||
});
|
||||
|
||||
if (options.counterparty) {
|
||||
accountLinesRequest.message.peer = options.counterparty;
|
||||
}
|
||||
|
||||
accountLinesRequest.once('error', reject);
|
||||
accountLinesRequest.once('success', function(nextResult) {
|
||||
|
||||
const lines = [ ];
|
||||
nextResult.lines.forEach(function(line) {
|
||||
if (!currencyRE.test(line.currency)) {
|
||||
return;
|
||||
}
|
||||
lines.push({
|
||||
account: account,
|
||||
counterparty: line.account,
|
||||
currency: line.currency,
|
||||
limit: line.limit,
|
||||
reciprocated_limit: line.limit_peer,
|
||||
account_allows_rippling: line.no_ripple ? !line.no_ripple : true,
|
||||
counterparty_allows_rippling: line.no_ripple_peer
|
||||
? !line.no_ripple_peer : true,
|
||||
account_trustline_frozen: line.freeze ? line.freeze : false,
|
||||
counterparty_trustline_frozen: line.freeze_peer
|
||||
? line.freeze_peer : false
|
||||
});
|
||||
});
|
||||
|
||||
nextResult.lines = prevResult ? prevResult.lines.concat(lines) : lines;
|
||||
resolve([nextResult]);
|
||||
});
|
||||
accountLinesRequest.request();
|
||||
});
|
||||
|
||||
return promise.spread(getAccountLines);
|
||||
}
|
||||
|
||||
function respondWithTrustlines(result) {
|
||||
const promise = new Promise(function(resolve) {
|
||||
const trustlines = {};
|
||||
|
||||
if (result.marker) {
|
||||
trustlines.marker = result.marker;
|
||||
}
|
||||
|
||||
trustlines.limit = result.limit;
|
||||
trustlines.ledger = result.ledger_index;
|
||||
trustlines.validated = result.validated;
|
||||
trustlines.trustlines = result.lines;
|
||||
|
||||
resolve(callback(null, trustlines));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
getAccountLines()
|
||||
.then(respondWithTrustlines)
|
||||
.catch(callback);
|
||||
}
|
||||
|
||||
module.exports.getTrustLines = getTrustLines;
|
||||
module.exports.getTrustlines = getTrustlines;
|
||||
|
||||
@@ -6,6 +6,29 @@ const asyncify = require('simple-asyncify');
|
||||
const common = require('../common');
|
||||
const ripple = common.core;
|
||||
|
||||
// If the marker is omitted from a response, you have reached the end
|
||||
// getter(marker, limit, callback), callback(error, {marker, results})
|
||||
function getRecursiveRecur(getter, marker, limit, callback) {
|
||||
getter(marker, limit, (error, data) => {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
const remaining = limit - data.results.length;
|
||||
if (remaining > 0 && data.marker !== undefined) {
|
||||
getRecursiveRecur(getter, data.marker, remaining, (_error, results) => {
|
||||
return _error ? callback(_error) :
|
||||
callback(null, data.results.concat(results));
|
||||
});
|
||||
} else {
|
||||
return callback(null, data.results.slice(0, limit));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getRecursive(getter, limit, callback) {
|
||||
getRecursiveRecur(getter, undefined, limit, callback);
|
||||
}
|
||||
|
||||
function renameCounterpartyToIssuer(amount) {
|
||||
if (amount === undefined) {
|
||||
return undefined;
|
||||
@@ -99,6 +122,7 @@ module.exports = {
|
||||
renameCounterpartyToIssuer: renameCounterpartyToIssuer,
|
||||
renameCounterpartyToIssuerInOrder: renameCounterpartyToIssuerInOrder,
|
||||
attachDate: attachDate,
|
||||
getRecursive: getRecursive,
|
||||
wrapCatch: common.wrapCatch,
|
||||
common: common
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ const TrustSetFlags = {
|
||||
frozed: {set: 'SetFreeze', unset: 'ClearFreeze'}
|
||||
};
|
||||
|
||||
function createTrustLineTransaction(account, trustline) {
|
||||
function createTrustlineTransaction(account, trustline) {
|
||||
validate.address(account);
|
||||
validate.trustline(trustline);
|
||||
|
||||
@@ -27,9 +27,9 @@ function createTrustLineTransaction(account, trustline) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
function prepareTrustLine(account, trustline, instructions, callback) {
|
||||
const transaction = createTrustLineTransaction(account, trustline);
|
||||
function prepareTrustline(account, trustline, instructions, callback) {
|
||||
const transaction = createTrustlineTransaction(account, trustline);
|
||||
utils.createTxJSON(transaction, this.remote, instructions, callback);
|
||||
}
|
||||
|
||||
module.exports = utils.wrapCatch(prepareTrustLine);
|
||||
module.exports = utils.wrapCatch(prepareTrustline);
|
||||
|
||||
@@ -24,6 +24,7 @@ const submitResponse = require('./fixtures/submit-response');
|
||||
const transactionResponse = require('./fixtures/transaction-response');
|
||||
const accountTransactionsResponse =
|
||||
require('./fixtures/account-transactions-response');
|
||||
const trustlinesResponse = require('./fixtures/trustlines-response');
|
||||
|
||||
function checkResult(expected, done, error, response) {
|
||||
if (error) {
|
||||
@@ -99,4 +100,10 @@ describe('RippleAPI', function() {
|
||||
this.api.getAccountTransactions(address, options,
|
||||
_.partial(checkResult, accountTransactionsResponse, done));
|
||||
});
|
||||
|
||||
it('getTrustlines', function(done) {
|
||||
const options = {currency: 'USD'};
|
||||
this.api.getTrustlines(address, options,
|
||||
_.partial(checkResult, trustlinesResponse, done));
|
||||
});
|
||||
});
|
||||
|
||||
1
test/fixtures/acct-tx-response.js
vendored
1
test/fixtures/acct-tx-response.js
vendored
@@ -196,6 +196,7 @@ module.exports = function(request, options={}) {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
marker: request.marker === undefined ? 'ABC' : undefined,
|
||||
transactions: [
|
||||
{
|
||||
ledger_index: 348860,
|
||||
|
||||
99
test/fixtures/trustlines-response.json
vendored
Normal file
99
test/fixtures/trustlines-response.json
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
[
|
||||
{
|
||||
"specification": {
|
||||
"limit": "5",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"disableRippling": true,
|
||||
"frozen": true
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "0"
|
||||
},
|
||||
"state": {
|
||||
"balance": "2.497605752725159"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specification": {
|
||||
"limit": "5000",
|
||||
"currency": "USD",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "0"
|
||||
},
|
||||
"state": {
|
||||
"balance": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specification": {
|
||||
"limit": "1",
|
||||
"currency": "USD",
|
||||
"counterparty": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "0"
|
||||
},
|
||||
"state": {
|
||||
"balance": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specification": {
|
||||
"limit": "1",
|
||||
"currency": "USD",
|
||||
"counterparty": "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X",
|
||||
"disableRippling": true
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "0"
|
||||
},
|
||||
"state": {
|
||||
"balance": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specification": {
|
||||
"limit": "500",
|
||||
"currency": "USD",
|
||||
"counterparty": "rfF3PNkwkq1DygW2wum2HK3RGfgkJjdPVD",
|
||||
"disableRippling": true
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "0"
|
||||
},
|
||||
"state": {
|
||||
"balance": "35"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specification": {
|
||||
"limit": "0",
|
||||
"currency": "USD",
|
||||
"counterparty": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "100",
|
||||
"disableRippling": true
|
||||
},
|
||||
"state": {
|
||||
"balance": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"specification": {
|
||||
"limit": "0",
|
||||
"currency": "USD",
|
||||
"counterparty": "rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF",
|
||||
"frozen": true
|
||||
},
|
||||
"counterparty": {
|
||||
"limit": "1"
|
||||
},
|
||||
"state": {
|
||||
"balance": "0"
|
||||
}
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user