BREAKING CHANGE: getFee returns promise, express fee in XRP in instructions response, use rawRequest to start decoupling Remote from API

This commit is contained in:
Chris Clark
2015-10-21 16:04:35 -07:00
parent 5aa212471c
commit cd17d6940f
52 changed files with 277 additions and 184 deletions

View File

@@ -26,6 +26,12 @@ class ConnectionError extends Error {
} }
} }
class NotConnectedError extends ConnectionError {
constructor(message) {
super(message);
}
}
class DisconnectedError extends ConnectionError { class DisconnectedError extends ConnectionError {
constructor(message) { constructor(message) {
super(message); super(message);
@@ -50,6 +56,7 @@ class Connection extends EventEmitter {
this._url = url; this._url = url;
this._timeout = options.timeout || (20 * 1000); this._timeout = options.timeout || (20 * 1000);
this._ws = null; this._ws = null;
this._ledgerVersion = null;
this._nextRequestID = 1; this._nextRequestID = 1;
} }
@@ -62,6 +69,9 @@ class Connection extends EventEmitter {
} }
this.emit(data.id.toString(), data); this.emit(data.id.toString(), data);
} else if (isStreamMessageType(data.type)) { } else if (isStreamMessageType(data.type)) {
if (data.type === 'ledgerClosed') {
this._ledgerVersion = Number(data.ledger_index);
}
this.emit(data.type, data); this.emit(data.type, data);
} else if (data.type === undefined && data.error) { } else if (data.type === undefined && data.error) {
this.emit('error', data.error, data.error_message); // e.g. slowDown this.emit('error', data.error, data.error_message); // e.g. slowDown
@@ -77,12 +87,34 @@ class Connection extends EventEmitter {
return this._ws ? this._ws.readyState : WebSocket.CLOSED; return this._ws ? this._ws.readyState : WebSocket.CLOSED;
} }
get _shouldBeConnected() {
return this._ws !== null;
}
_onUnexpectedClose() { _onUnexpectedClose() {
this._ledgerVersion = null;
this.connect().then(); this.connect().then();
} }
_onOpen() {
const subscribeRequest = {
command: 'subscribe',
streams: ['ledger']
};
return this.request(subscribeRequest).then(() => {
const ledgerRequest = {
command: 'ledger',
ledger_index: 'validated'
};
return this.request(ledgerRequest).then(info => {
this._ledgerVersion = Number(info.ledger.ledger_index);
this.emit('connected');
});
});
}
connect() { connect() {
return new Promise((resolve) => { return new Promise((resolve, reject) => {
if (this.state === WebSocket.OPEN) { if (this.state === WebSocket.OPEN) {
resolve(); resolve();
} else if (this.state === WebSocket.CONNECTING) { } else if (this.state === WebSocket.CONNECTING) {
@@ -91,7 +123,7 @@ class Connection extends EventEmitter {
this._ws = new WebSocket(this._url); this._ws = new WebSocket(this._url);
this._ws.on('message', this._onMessage.bind(this)); this._ws.on('message', this._onMessage.bind(this));
this._ws.once('close', () => this._onUnexpectedClose); this._ws.once('close', () => this._onUnexpectedClose);
this._ws.once('open', resolve); this._ws.once('open', () => this._onOpen().then(resolve, reject));
} }
}); });
} }
@@ -104,7 +136,11 @@ class Connection extends EventEmitter {
this._ws.once('close', resolve); this._ws.once('close', resolve);
} else { } else {
this._ws.removeListener('close', this._onUnexpectedClose); this._ws.removeListener('close', this._onUnexpectedClose);
this._ws.once('close', resolve); this._ws.once('close', () => {
this._ws = null;
this._ledgerVersion = null;
resolve();
});
this._ws.close(); this._ws.close();
} }
}); });
@@ -114,6 +150,19 @@ class Connection extends EventEmitter {
return this.disconnect().then(() => this.connect()); return this.disconnect().then(() => this.connect());
} }
getLedgerVersion() {
return new Promise((resolve, reject) => {
const ledgerVersion = this._ledgerVersion;
if (!this._shouldBeConnected) {
reject(new NotConnectedError());
} else if (this.state === WebSocket.OPEN && ledgerVersion !== null) {
resolve(ledgerVersion);
} else {
this.once('connected', () => resolve(this._ledgerVersion));
}
});
}
_send(message) { _send(message) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this._ws.send(message, undefined, (error, result) => { this._ws.send(message, undefined, (error, result) => {
@@ -131,13 +180,18 @@ class Connection extends EventEmitter {
if (this.state === WebSocket.OPEN) { if (this.state === WebSocket.OPEN) {
this._send(message).then(resolve, reject); this._send(message).then(resolve, reject);
} else { } else {
this._ws.once('open', () => this._send(message).then(resolve, reject)); this._ws.once('connected', () =>
this._send(message).then(resolve, reject));
} }
}); });
} }
request(request, timeout) { request(request, timeout) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this._shouldBeConnected) {
reject(new NotConnectedError());
}
let timer = null; let timer = null;
const self = this; const self = this;
const id = this._nextRequestID; const id = this._nextRequestID;
@@ -179,6 +233,7 @@ class Connection extends EventEmitter {
this._ws.once('close', onDisconnect); this._ws.once('close', onDisconnect);
// JSON.stringify automatically removes keys with value of 'undefined'
const message = JSON.stringify(Object.assign({}, request, {id})); const message = JSON.stringify(Object.assign({}, request, {id}));
this._sendWhenReady(message).then(() => { this._sendWhenReady(message).then(() => {

View File

@@ -8,12 +8,14 @@ module.exports = {
errors: require('./errors'), errors: require('./errors'),
validate: require('./validate'), validate: require('./validate'),
txFlags: require('./txflags').txFlags, txFlags: require('./txflags').txFlags,
serverInfo: require('./serverinfo'),
dropsToXrp: utils.dropsToXrp, dropsToXrp: utils.dropsToXrp,
xrpToDrops: utils.xrpToDrops, xrpToDrops: utils.xrpToDrops,
toRippledAmount: utils.toRippledAmount, toRippledAmount: utils.toRippledAmount,
generateAddress: utils.generateAddress, generateAddress: utils.generateAddress,
composeAsync: utils.composeAsync, composeAsync: utils.composeAsync,
wrapCatch: utils.wrapCatch, wrapCatch: utils.wrapCatch,
removeUndefined: utils.removeUndefined,
convertErrors: utils.convertErrors, convertErrors: utils.convertErrors,
convertExceptions: utils.convertExceptions, convertExceptions: utils.convertExceptions,
convertKeysFromSnakeCaseToCamelCase: convertKeysFromSnakeCaseToCamelCase:

View File

@@ -4,6 +4,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"trace": {"type": "boolean"}, "trace": {"type": "boolean"},
"feeCushion": {"$ref": "value"},
"servers": { "servers": {
"type": "array", "type": "array",
"items": { "items": {

View File

@@ -0,0 +1,67 @@
'use strict';
const _ = require('lodash');
const {RippledNetworkError} = require('./errors');
const {promisify, convertKeysFromSnakeCaseToCamelCase} = require('./utils');
export type GetServerInfoResponse = {
buildVersion: string,
completeLedgers: string,
hostid: string,
ioLatencyMs: number,
load?: {
jobTypes: Array<Object>,
threads: number
},
lastClose: {
convergeTimeS: number,
proposers: number
},
loadFactor: number,
peers: number,
pubkeyNode: string,
pubkeyValidator?: string,
serverState: string,
validatedLedger: {
age: number,
baseFeeXrp: number,
hash: string,
reserveBaseXrp: number,
reserveIncXrp: number,
seq: number
},
validationQuorum: number
}
function getServerInfoAsync(remote,
callback: (err: any, data?: GetServerInfoResponse) => void
): void {
remote.rawRequest({command: 'server_info'}, (error, response) => {
if (error) {
const message = _.get(error, ['remote', 'error_message'], error.message);
callback(new RippledNetworkError(message));
} else {
callback(null, convertKeysFromSnakeCaseToCamelCase(response.info));
}
});
}
function getServerInfo(remote: Object): Promise<GetServerInfoResponse> {
return promisify(getServerInfoAsync)(remote);
}
function computeFeeFromServerInfo(cushion: number,
serverInfo: GetServerInfoResponse
): number {
return (Number(serverInfo.validatedLedger.baseFeeXrp)
* Number(serverInfo.loadFactor) * cushion).toString();
}
function getFee(remote: Object, cushion: number) {
return getServerInfo(remote).then(
_.partial(computeFeeFromServerInfo, cushion));
}
module.exports = {
getServerInfo,
getFee
};

View File

@@ -115,6 +115,10 @@ function promisify(asyncFunction: AsyncFunction): Function {
return es6promisify(wrapCatch(asyncFunction)); return es6promisify(wrapCatch(asyncFunction));
} }
function removeUndefined(obj: Object): Object {
return _.omit(obj, _.isUndefined);
}
module.exports = { module.exports = {
core, core,
dropsToXrp, dropsToXrp,
@@ -126,5 +130,6 @@ module.exports = {
convertExceptions, convertExceptions,
convertErrors, convertErrors,
convertKeysFromSnakeCaseToCamelCase, convertKeysFromSnakeCaseToCamelCase,
promisify promisify,
removeUndefined
}; };

View File

@@ -47,6 +47,7 @@ function RippleAPI(options: {}) {
EventEmitter.call(this); EventEmitter.call(this);
} }
const _options = _.assign({}, options, {automatic_resubmission: false}); const _options = _.assign({}, options, {automatic_resubmission: false});
this._feeCushion = _options.feeCushion || 1.2;
this.remote = new common.core.Remote(_options); this.remote = new common.core.Remote(_options);
this.remote.on('ledger_closed', message => { this.remote.on('ledger_closed', message => {
this.emit('ledgerClosed', server.formatLedgerClose(message)); this.emit('ledgerClosed', server.formatLedgerClose(message));

View File

@@ -2,10 +2,7 @@
'use strict'; 'use strict';
const utils = require('./utils'); const utils = require('./utils');
const removeUndefined = require('./parse/utils').removeUndefined; const {validate, composeAsync, convertErrors, removeUndefined} = utils.common;
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
type AccountData = { type AccountData = {
Sequence: number, Sequence: number,
@@ -62,11 +59,12 @@ function getAccountInfoAsync(account: string, options: AccountInfoOptions,
validate.getAccountInfoOptions(options); validate.getAccountInfoOptions(options);
const request = { const request = {
command: 'account_info',
account: account, account: account,
ledger: options.ledgerVersion || 'validated' ledger_index: options.ledgerVersion || 'validated'
}; };
this.remote.requestAccountInfo(request, this.remote.rawRequest(request,
composeAsync(formatAccountInfo, convertErrors(callback))); composeAsync(formatAccountInfo, convertErrors(callback)));
} }

View File

@@ -3,9 +3,7 @@
const _ = require('lodash'); const _ = require('lodash');
const utils = require('./utils'); const utils = require('./utils');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
import type {Amount} from '../common/types.js'; import type {Amount} from '../common/types.js';
type BalanceSheetOptions = { type BalanceSheetOptions = {
@@ -55,12 +53,13 @@ function getBalanceSheetAsync(address: string, options: BalanceSheetOptions,
validate.address(address); validate.address(address);
validate.getBalanceSheetOptions(options); validate.getBalanceSheetOptions(options);
const requestOptions = Object.assign({}, { const request = {
command: 'gateway_balances',
account: address, account: address,
strict: true, strict: true,
hotwallet: options.excludeAddresses, hotwallet: options.excludeAddresses,
ledger: options.ledgerVersion ledger_index: options.ledgerVersion
}); };
const requestCallback = composeAsync( const requestCallback = composeAsync(
formatBalanceSheet, convertErrors(callback)); formatBalanceSheet, convertErrors(callback));
@@ -71,11 +70,11 @@ function getBalanceSheetAsync(address: string, options: BalanceSheetOptions,
return; return;
} }
if (_.isUndefined(requestOptions.ledger)) { if (_.isUndefined(request.ledger_index)) {
requestOptions.ledger = ledgerVersion; request.ledger_index = ledgerVersion;
} }
this.remote.requestGatewayBalances(requestOptions, requestCallback); this.remote.rawRequest(request, requestCallback);
}); });
} }

View File

@@ -4,11 +4,8 @@ const _ = require('lodash');
const async = require('async'); const async = require('async');
const utils = require('./utils'); const utils = require('./utils');
const getTrustlines = require('./trustlines'); const getTrustlines = require('./trustlines');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
import type {Remote, GetLedgerSequenceCallback} from '../../core/remote'; import type {Remote, GetLedgerSequenceCallback} from '../../core/remote';
import type {TrustlinesOptions, Trustline} from './trustlines-types.js'; import type {TrustlinesOptions, Trustline} from './trustlines-types.js';

View File

@@ -1,9 +1,7 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
const utils = require('./utils'); const utils = require('./utils');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseLedger = require('./parse/ledger'); const parseLedger = require('./parse/ledger');
import type {GetLedger} from './types.js'; import type {GetLedger} from './types.js';
@@ -19,13 +17,14 @@ function getLedgerAsync(options: LedgerOptions, callback) {
validate.getLedgerOptions(options); validate.getLedgerOptions(options);
const request = { const request = {
ledger: options.ledgerVersion || 'validated', command: 'ledger',
ledger_index: options.ledgerVersion || 'validated',
expand: options.includeAllData, expand: options.includeAllData,
transactions: options.includeTransactions, transactions: options.includeTransactions,
accounts: options.includeState accounts: options.includeState
}; };
this.remote.requestLedger(request, this.remote.rawRequest(request,
composeAsync(response => parseLedger(response.ledger), composeAsync(response => parseLedger(response.ledger),
convertErrors(callback))); convertErrors(callback)));
} }

View File

@@ -3,9 +3,7 @@
const _ = require('lodash'); const _ = require('lodash');
const async = require('async'); const async = require('async');
const utils = require('./utils'); const utils = require('./utils');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseOrderbookOrder = require('./parse/orderbook-order'); const parseOrderbookOrder = require('./parse/orderbook-order');
import type {Remote} from '../../core/remote'; import type {Remote} from '../../core/remote';
import type {OrdersOptions, OrderSpecification} from './types.js'; import type {OrdersOptions, OrderSpecification} from './types.js';
@@ -42,10 +40,11 @@ function getBookOffers(remote: Remote, account: string,
ledgerVersion?: number, limit?: number, takerGets: Issue, ledgerVersion?: number, limit?: number, takerGets: Issue,
takerPays: Issue, callback takerPays: Issue, callback
) { ) {
remote.requestBookOffers(utils.renameCounterpartyToIssuerInOrder({ remote.rawRequest(utils.renameCounterpartyToIssuerInOrder({
command: 'book_offers',
taker_gets: takerGets, taker_gets: takerGets,
taker_pays: takerPays, taker_pays: takerPays,
ledger: ledgerVersion || 'validated', ledger_index: ledgerVersion || 'validated',
limit: limit, limit: limit,
taker: account taker: account
}), composeAsync(data => data.offers, convertErrors(callback))); }), composeAsync(data => data.offers, convertErrors(callback)));

View File

@@ -3,9 +3,7 @@
const _ = require('lodash'); const _ = require('lodash');
const async = require('async'); const async = require('async');
const utils = require('./utils'); const utils = require('./utils');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseAccountOrder = require('./parse/account-order'); const parseAccountOrder = require('./parse/account-order');
import type {Remote} from '../../core/remote'; import type {Remote} from '../../core/remote';
import type {OrdersOptions, Order} from './types.js'; import type {OrdersOptions, Order} from './types.js';
@@ -15,11 +13,12 @@ type GetOrders = Array<Order>
function requestAccountOffers(remote: Remote, address: string, function requestAccountOffers(remote: Remote, address: string,
ledgerVersion: number, marker: string, limit: number, callback ledgerVersion: number, marker: string, limit: number, callback
) { ) {
remote.requestAccountOffers({ remote.rawRequest({
command: 'account_offers',
account: address, account: address,
marker: marker, marker: marker,
limit: utils.clamp(limit, 10, 400), limit: utils.clamp(limit, 10, 400),
ledger: ledgerVersion ledger_index: ledgerVersion
}, },
composeAsync((data) => ({ composeAsync((data) => ({
marker: data.marker, marker: data.marker,

View File

@@ -22,10 +22,6 @@ function parseTimestamp(tx: {date: string}): string | void {
return tx.date ? (new Date(toTimestamp(tx.date))).toISOString() : undefined; return tx.date ? (new Date(toTimestamp(tx.date))).toISOString() : undefined;
} }
function removeUndefined(obj: Object): Object {
return _.omit(obj, _.isUndefined);
}
function removeEmptyCounterparty(amount) { function removeEmptyCounterparty(amount) {
if (amount.counterparty === '') { if (amount.counterparty === '') {
delete amount.counterparty; delete amount.counterparty;
@@ -76,7 +72,7 @@ function parseMemos(tx: Object): ?Array<Object> {
return undefined; return undefined;
} }
return tx.Memos.map((m) => { return tx.Memos.map((m) => {
return removeUndefined({ return utils.common.removeUndefined({
type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType), type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType),
format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat), format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat),
data: m.Memo.parsed_memo_data || hexToString(m.Memo.MemoData) data: m.Memo.parsed_memo_data || hexToString(m.Memo.MemoData)
@@ -87,10 +83,10 @@ function parseMemos(tx: Object): ?Array<Object> {
module.exports = { module.exports = {
parseOutcome, parseOutcome,
parseMemos, parseMemos,
removeUndefined,
adjustQualityForXRP, adjustQualityForXRP,
dropsToXrp: utils.common.dropsToXrp, dropsToXrp: utils.common.dropsToXrp,
constants: utils.common.constants, constants: utils.common.constants,
txFlags: utils.common.txFlags, txFlags: utils.common.txFlags,
core: utils.common.core core: utils.common.core,
removeUndefined: utils.common.removeUndefined
}; };

View File

@@ -5,12 +5,9 @@ const async = require('async');
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const utils = require('./utils'); const utils = require('./utils');
const parsePathfind = require('./parse/pathfind'); const parsePathfind = require('./parse/pathfind');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors, toRippledAmount} = utils.common;
const NotFoundError = utils.common.errors.NotFoundError; const NotFoundError = utils.common.errors.NotFoundError;
const ValidationError = utils.common.errors.ValidationError; const ValidationError = utils.common.errors.ValidationError;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const toRippledAmount = utils.common.toRippledAmount;
import type {Remote} from '../../core/remote'; import type {Remote} from '../../core/remote';
import type {RippledAmount} from '../common/types.js'; import type {RippledAmount} from '../common/types.js';
import type {GetPaths, PathFind, PathFindParams, import type {GetPaths, PathFind, PathFindParams,

View File

@@ -2,11 +2,9 @@
'use strict'; 'use strict';
const _ = require('lodash'); const _ = require('lodash');
const utils = require('./utils'); const utils = require('./utils');
const validate = utils.common.validate;
const parseFields = require('./parse/fields'); const parseFields = require('./parse/fields');
const composeAsync = utils.common.composeAsync; const {validate, composeAsync, convertErrors} = utils.common;
const AccountFlags = utils.common.constants.AccountFlags; const AccountFlags = utils.common.constants.AccountFlags;
const convertErrors = utils.common.convertErrors;
type SettingsOptions = { type SettingsOptions = {
ledgerVersion?: number ledgerVersion?: number
@@ -55,11 +53,12 @@ function getSettingsAsync(account: string, options: SettingsOptions, callback) {
validate.getSettingsOptions(options); validate.getSettingsOptions(options);
const request = { const request = {
command: 'account_info',
account: account, account: account,
ledger: options.ledgerVersion || 'validated' ledger_index: options.ledgerVersion || 'validated'
}; };
this.remote.requestAccountInfo(request, this.remote.rawRequest(request,
composeAsync(formatSettings, convertErrors(callback))); composeAsync(formatSettings, convertErrors(callback)));
} }

View File

@@ -4,9 +4,7 @@ const _ = require('lodash');
const async = require('async'); const async = require('async');
const utils = require('./utils'); const utils = require('./utils');
const parseTransaction = require('./parse/transaction'); const parseTransaction = require('./parse/transaction');
const validate = utils.common.validate; const {validate, convertErrors, errors} = utils.common;
const errors = utils.common.errors;
const convertErrors = utils.common.convertErrors;
const RippleError = require('../../core/rippleerror').RippleError; const RippleError = require('../../core/rippleerror').RippleError;
import type {Remote} from '../../core/remote'; import type {Remote} from '../../core/remote';
@@ -27,7 +25,12 @@ function attachTransactionDate(remote: Remote, tx: Object,
return; return;
} }
remote.requestLedger(tx.ledger_index, (error, data) => { const request = {
command: 'ledger',
ledger_index: tx.ledger_index
};
remote.rawRequest(request, (error, data) => {
if (error) { if (error) {
callback(new errors.NotFoundError('Transaction ledger not found')); callback(new errors.NotFoundError('Transaction ledger not found'));
} else if (typeof data.ledger.close_time === 'number') { } else if (typeof data.ledger.close_time === 'number') {
@@ -98,8 +101,8 @@ function getTransactionAsync(identifier: string, options: TransactionOptions,
} }
async.waterfall([ async.waterfall([
_.partial(remote.requestTx.bind(remote), _.partial(remote.rawRequest.bind(remote),
{hash: identifier, binary: false}), {command: 'tx', transaction: identifier, binary: false}),
_.partial(attachTransactionDate, remote) _.partial(attachTransactionDate, remote)
], maxLedgerGetter.bind(this)); ], maxLedgerGetter.bind(this));
} }

View File

@@ -2,15 +2,13 @@
/* eslint-disable max-params */ /* eslint-disable max-params */
'use strict'; 'use strict';
const _ = require('lodash'); const _ = require('lodash');
const binary = require('ripple-binary-codec');
const {computeTransactionHash} = require('ripple-hashes');
const utils = require('./utils'); const utils = require('./utils');
const parseTransaction = require('./parse/transaction'); const parseTransaction = require('./parse/transaction');
const getTransaction = require('./transaction'); const getTransaction = require('./transaction');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
import type {Remote} from '../../core/remote'; import type {Remote} from '../../core/remote';
import type {TransactionType} from './transaction-types'; import type {TransactionType} from './transaction-types';
@@ -32,11 +30,22 @@ type GetTransactionsResponse = Array<TransactionType>
type CallbackType = (err?: ?Error, data?: GetTransactionsResponse) => void type CallbackType = (err?: ?Error, data?: GetTransactionsResponse) => void
function parseBinaryTransaction(transaction) {
const tx = binary.decode(transaction.tx_blob);
tx.hash = computeTransactionHash(tx);
tx.ledger_index = transaction.ledger_index;
return {
tx: tx,
meta: binary.decode(transaction.meta),
validated: transaction.validated
};
}
function parseAccountTxTransaction(tx) { function parseAccountTxTransaction(tx) {
const _tx = tx.tx_blob ? parseBinaryTransaction(tx) : tx;
// rippled uses a different response format for 'account_tx' than 'tx' // rippled uses a different response format for 'account_tx' than 'tx'
tx.tx.meta = tx.meta; return parseTransaction(_.assign({}, _tx.tx,
tx.tx.validated = tx.validated; {meta: _tx.meta, validated: _tx.validated}));
return parseTransaction(tx.tx);
} }
function counterpartyFilter(filters, tx: TransactionType) { function counterpartyFilter(filters, tx: TransactionType) {
@@ -97,7 +106,8 @@ function formatPartialResponse(address: string,
function getAccountTx(remote: Remote, address: string, function getAccountTx(remote: Remote, address: string,
options: TransactionsOptions, marker: string, limit: number, callback options: TransactionsOptions, marker: string, limit: number, callback
) { ) {
const params = { const request = {
command: 'account_tx',
account: address, account: address,
// -1 is equivalent to earliest available validated ledger // -1 is equivalent to earliest available validated ledger
ledger_index_min: options.minLedgerVersion || -1, ledger_index_min: options.minLedgerVersion || -1,
@@ -109,7 +119,7 @@ function getAccountTx(remote: Remote, address: string,
marker: marker marker: marker
}; };
remote.requestAccountTx(params, remote.rawRequest(request,
composeAsync(_.partial(formatPartialResponse, address, options), composeAsync(_.partial(formatPartialResponse, address, options),
convertErrors(callback))); convertErrors(callback)));
} }

View File

@@ -3,9 +3,7 @@
const _ = require('lodash'); const _ = require('lodash');
const async = require('async'); const async = require('async');
const utils = require('./utils'); const utils = require('./utils');
const validate = utils.common.validate; const {validate, composeAsync, convertErrors} = utils.common;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseAccountTrustline = require('./parse/account-trustline'); const parseAccountTrustline = require('./parse/account-trustline');
import type {Remote} from '../../core/remote'; import type {Remote} from '../../core/remote';
@@ -29,15 +27,16 @@ function formatResponse(options: TrustlinesOptions, data) {
function getAccountLines(remote: Remote, address: string, ledgerVersion: number, function getAccountLines(remote: Remote, address: string, ledgerVersion: number,
options: TrustlinesOptions, marker: string, limit: number, callback options: TrustlinesOptions, marker: string, limit: number, callback
) { ) {
const requestOptions = { const request = {
command: 'account_lines',
account: address, account: address,
ledger: ledgerVersion, ledger_index: ledgerVersion,
marker: marker, marker: marker,
limit: utils.clamp(limit, 10, 400), limit: utils.clamp(limit, 10, 400),
peer: options.counterparty peer: options.counterparty
}; };
remote.requestAccountLines(requestOptions, remote.rawRequest(request,
composeAsync(_.partial(formatResponse, options), composeAsync(_.partial(formatResponse, options),
convertErrors(callback))); convertErrors(callback)));
} }

View File

@@ -26,7 +26,12 @@ function clamp(value: number, min: number, max: number): number {
function getXRPBalance(remote: Remote, address: string, ledgerVersion?: number, function getXRPBalance(remote: Remote, address: string, ledgerVersion?: number,
callback: Callback callback: Callback
): void { ): void {
remote.requestAccountInfo({account: address, ledger: ledgerVersion}, const request = {
command: 'account_info',
account: address,
ledger_index: ledgerVersion
};
remote.rawRequest(request,
composeAsync((data) => dropsToXrp(data.account_data.Balance), callback)); composeAsync((data) => dropsToXrp(data.account_data.Balance), callback));
} }

View File

@@ -1,66 +1,13 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
const _ = require('lodash');
const common = require('../common'); const common = require('../common');
import type {GetServerInfoResponse} from '../common/serverinfo';
type GetServerInfoResponse = {
buildVersion: string,
completeLedgers: string,
hostid: string,
ioLatencyMs: number,
load?: {
jobTypes: Array<Object>,
threads: number
},
lastClose: {
convergeTimeS: number,
proposers: number
},
loadFactor: number,
peers: number,
pubkeyNode: string,
pubkeyValidator?: string,
serverState: string,
validatedLedger: {
age: number,
baseFeeXrp: number,
hash: string,
reserveBaseXrp: number,
reserveIncXrp: number,
seq: number
},
validationQuorum: number
}
function isConnected(): boolean { function isConnected(): boolean {
const server = this.remote.getServer(); const server = this.remote.getServer();
return Boolean(server && server.isConnected()); return Boolean(server && server.isConnected());
} }
function getServerInfoAsync(
callback: (err: any, data?: GetServerInfoResponse) => void
): void {
this.remote.requestServerInfo((error, response) => {
if (error) {
const message = _.get(error, ['remote', 'error_message'], error.message);
callback(new common.errors.RippledNetworkError(message));
} else {
callback(null,
common.convertKeysFromSnakeCaseToCamelCase(response.info));
}
});
}
function getFee(): ?number {
if (!this.remote.getConnectedServers().length) {
throw new common.errors.RippledNetworkError('No servers available.');
}
const fee = this.remote.createTransaction()._computeFee();
return fee === undefined ? undefined : common.dropsToXrp(fee);
}
function getLedgerVersion(): Promise<number> { function getLedgerVersion(): Promise<number> {
return common.promisify(this.remote.getLedgerSequence).call(this.remote); return common.promisify(this.remote.getLedgerSequence).call(this.remote);
} }
@@ -86,7 +33,12 @@ function disconnect(): Promise<void> {
} }
function getServerInfo(): Promise<GetServerInfoResponse> { function getServerInfo(): Promise<GetServerInfoResponse> {
return common.promisify(getServerInfoAsync).call(this); return common.serverInfo.getServerInfo(this.remote);
}
function getFee(): Promise<number> {
const cushion = this._feeCushion || 1.2;
return common.serverInfo.getFee(this.remote, cushion);
} }
function rippleTimeToISO8601(rippleTime: string): string { function rippleTimeToISO8601(rippleTime: string): string {

View File

@@ -41,7 +41,7 @@ function prepareOrderAsync(account: string, order: Order,
instructions: Instructions, callback instructions: Instructions, callback
) { ) {
const txJSON = createOrderTransaction(account, order); const txJSON = createOrderTransaction(account, order);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareOrder(account: string, order: Order, function prepareOrder(account: string, order: Order,

View File

@@ -21,7 +21,7 @@ function prepareOrderCancellationAsync(account: string, sequence: number,
instructions: Instructions, callback instructions: Instructions, callback
) { ) {
const txJSON = createOrderCancellationTransaction(account, sequence); const txJSON = createOrderCancellationTransaction(account, sequence);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareOrderCancellation(account: string, sequence: number, function prepareOrderCancellation(account: string, sequence: number,

View File

@@ -145,7 +145,7 @@ function preparePaymentAsync(account: string, payment: Payment,
instructions: Instructions, callback instructions: Instructions, callback
) { ) {
const txJSON = createPaymentTransaction(account, payment); const txJSON = createPaymentTransaction(account, payment);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function preparePayment(account: string, payment: Payment, function preparePayment(account: string, payment: Payment,

View File

@@ -99,7 +99,7 @@ function prepareSettingsAsync(account: string, settings: Settings,
instructions: Instructions, callback instructions: Instructions, callback
) { ) {
const txJSON = createSettingsTransaction(account, settings); const txJSON = createSettingsTransaction(account, settings);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareSettings(account: string, settings: Object, function prepareSettings(account: string, settings: Object,

View File

@@ -35,7 +35,7 @@ function prepareSuspendedPaymentCancellationAsync(account: string,
) { ) {
const txJSON = const txJSON =
createSuspendedPaymentCancellationTransaction(account, payment); createSuspendedPaymentCancellationTransaction(account, payment);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareSuspendedPaymentCancellation(account: string, function prepareSuspendedPaymentCancellation(account: string,

View File

@@ -54,7 +54,7 @@ function prepareSuspendedPaymentCreationAsync(account: string,
payment: SuspendedPaymentCreation, instructions: Instructions, callback payment: SuspendedPaymentCreation, instructions: Instructions, callback
) { ) {
const txJSON = createSuspendedPaymentCreationTransaction(account, payment); const txJSON = createSuspendedPaymentCreationTransaction(account, payment);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareSuspendedPaymentCreation(account: string, function prepareSuspendedPaymentCreation(account: string,

View File

@@ -47,7 +47,7 @@ function prepareSuspendedPaymentExecutionAsync(account: string,
payment: SuspendedPaymentExecution, instructions: Instructions, callback payment: SuspendedPaymentExecution, instructions: Instructions, callback
) { ) {
const txJSON = createSuspendedPaymentExecutionTransaction(account, payment); const txJSON = createSuspendedPaymentExecutionTransaction(account, payment);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareSuspendedPaymentExecution(account: string, function prepareSuspendedPaymentExecution(account: string,

View File

@@ -54,7 +54,7 @@ function prepareTrustlineAsync(account: string,
trustline: TrustLineSpecification, instructions: Instructions, callback trustline: TrustLineSpecification, instructions: Instructions, callback
) { ) {
const txJSON = createTrustlineTransaction(account, trustline); const txJSON = createTrustlineTransaction(account, trustline);
utils.prepareTransaction(txJSON, this.remote, instructions, callback); utils.prepareTransaction(txJSON, this, instructions, callback);
} }
function prepareTrustline(account: string, function prepareTrustline(account: string,

View File

@@ -4,25 +4,16 @@ const _ = require('lodash');
const async = require('async'); const async = require('async');
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const common = require('../common'); const common = require('../common');
const composeAsync = common.composeAsync;
const txFlags = common.txFlags; const txFlags = common.txFlags;
import type {Remote} from '../../core/remote';
import type {Instructions} from './types.js'; import type {Instructions} from './types.js';
function removeUndefined(obj: Object): Object { function removeUndefined(obj: Object): Object {
return _.omit(obj, _.isUndefined); return _.omit(obj, _.isUndefined);
} }
function getFeeDrops(remote: Remote, callback) {
const feeUnits = 10; // all transactions currently have a fee of 10 fee units
remote.feeTxAsync(feeUnits, (err, data) => {
callback(err, data ? data.to_text() : undefined);
});
}
function formatPrepareResponse(txJSON: Object): Object { function formatPrepareResponse(txJSON: Object): Object {
const instructions = { const instructions = {
fee: txJSON.Fee, fee: common.dropsToXrp(txJSON.Fee),
sequence: txJSON.Sequence, sequence: txJSON.Sequence,
maxLedgerVersion: txJSON.LastLedgerSequence maxLedgerVersion: txJSON.LastLedgerSequence
}; };
@@ -42,7 +33,7 @@ function setCanonicalFlag(txJSON) {
type Callback = (err: ?(typeof Error), type Callback = (err: ?(typeof Error),
data: {txJSON: string, instructions: Instructions}) => void; data: {txJSON: string, instructions: Instructions}) => void;
function prepareTransaction(txJSON: Object, remote: Remote, function prepareTransaction(txJSON: Object, api: Object,
instructions: Instructions, callback: Callback instructions: Instructions, callback: Callback
): void { ): void {
common.validate.instructions(instructions); common.validate.instructions(instructions);
@@ -57,7 +48,7 @@ function prepareTransaction(txJSON: Object, remote: Remote,
} else { } else {
const offset = instructions.maxLedgerVersionOffset !== undefined ? const offset = instructions.maxLedgerVersionOffset !== undefined ?
instructions.maxLedgerVersionOffset : 3; instructions.maxLedgerVersionOffset : 3;
remote.getLedgerSequence((error, ledgerVersion) => { api.remote.getLedgerSequence((error, ledgerVersion) => {
txJSON.LastLedgerSequence = ledgerVersion + offset; txJSON.LastLedgerSequence = ledgerVersion + offset;
callback_(error); callback_(error);
}); });
@@ -69,14 +60,16 @@ function prepareTransaction(txJSON: Object, remote: Remote,
txJSON.Fee = common.xrpToDrops(instructions.fee); txJSON.Fee = common.xrpToDrops(instructions.fee);
callback_(); callback_();
} else { } else {
getFeeDrops(remote, composeAsync((serverFeeDrops) => { common.serverInfo.getFee(api.remote, api._feeCushion).then(fee => {
const feeDrops = common.xrpToDrops(fee);
if (instructions.maxFee !== undefined) { if (instructions.maxFee !== undefined) {
const maxFeeDrops = common.xrpToDrops(instructions.maxFee); const maxFeeDrops = common.xrpToDrops(instructions.maxFee);
txJSON.Fee = BigNumber.min(serverFeeDrops, maxFeeDrops).toString(); txJSON.Fee = BigNumber.min(feeDrops, maxFeeDrops).toString();
} else { } else {
txJSON.Fee = serverFeeDrops; txJSON.Fee = feeDrops;
} }
}, callback_)); callback_();
});
} }
} }
@@ -85,8 +78,12 @@ function prepareTransaction(txJSON: Object, remote: Remote,
txJSON.Sequence = instructions.sequence; txJSON.Sequence = instructions.sequence;
callback_(null, formatPrepareResponse(txJSON)); callback_(null, formatPrepareResponse(txJSON));
} else { } else {
remote.findAccount(account).getNextSequence(function(error, sequence) { const request = {
txJSON.Sequence = sequence; command: 'account_info',
account: account
};
api.remote.rawRequest(request, function(error, response) {
txJSON.Sequence = response.account_data.Sequence;
callback_(error, formatPrepareResponse(txJSON)); callback_(error, formatPrepareResponse(txJSON));
}); });
} }

View File

@@ -810,6 +810,12 @@ Remote.prototype.request = function(request) {
} }
}; };
Remote.prototype.rawRequest = function(message, callback) {
const request = new Request(this, message.command);
_.assign(request.message, _.omit(message, _.isUndefined));
request.request(callback);
};
/** /**
* Request ping * Request ping
* *

View File

@@ -607,7 +607,9 @@ describe('RippleAPI', function() {
}); });
it('getFee', function() { it('getFee', function() {
assert.strictEqual(this.api.getFee(), '0.000012'); return this.api.getFee().then(fee => {
assert.strictEqual(fee, '0.000012');
});
}); });
it('disconnect & isConnected', function() { it('disconnect & isConnected', function() {

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"OfferCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":23,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"OfferCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":23,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2148139008,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"TakerPays\":\"2000000\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2148139008,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"TakerPays\":\"2000000\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":\"10000\",\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":\"10000\",\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\",\"Amount\":{\"value\":\"9999999999999999e80\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"SendMax\":{\"value\":\"5\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"DeliverMin\":{\"value\":\"9999999999999999e80\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"Paths\":[[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"account\":\"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\",\"currency\":\"USD\"},{\"account\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\",\"Amount\":{\"value\":\"9999999999999999e80\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"SendMax\":{\"value\":\"5\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"DeliverMin\":{\"value\":\"9999999999999999e80\",\"currency\":\"USD\",\"issuer\":\"ra5nK24KXen9AHvsdFTKHSANinZseWnPcX\"},\"Paths\":[[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"},{\"account\":\"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn\"}],[{\"account\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\"},{\"currency\":\"XRP\"},{\"issuer\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\",\"currency\":\"USD\"},{\"account\":\"rfsEoNBUBbvkf4jPcFe2u9CyaQagLVHGfP\"},{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147942400,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"LTC\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\"},\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"Paths\":[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147942400,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"LTC\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\"},\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"Paths\":[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"WalletLocator\":\"0\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"WalletLocator\":\"0\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"ClearFlag\":1,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"ClearFlag\":1,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SetFlag\":1,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SetFlag\":1,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SetRegularKey\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"RegularKey\":\"rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SetRegularKey\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"RegularKey\":\"rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransferRate\":1000000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransferRate\":1000000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"CancelAfter\":494009529,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"CancelAfter\":494009529,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentFinish\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Method\":1,\"Digest\":\"8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4\",\"Proof\":\"7768617465766572\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentFinish\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Method\":1,\"Digest\":\"8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4\",\"Proof\":\"7768617465766572\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"0.1\",\"currency\":\"BTC\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"0.1\",\"currency\":\"BTC\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -1,7 +1,7 @@
{ {
"txJSON": "{\"Flags\":2149711872,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"10000\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"QualityIn\":910000000,\"QualityOut\":870000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}", "txJSON": "{\"Flags\":2149711872,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"10000\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"QualityIn\":910000000,\"QualityOut\":870000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": { "instructions": {
"fee": "12", "fee": "0.000012",
"sequence": 23, "sequence": 23,
"maxLedgerVersion": 8820051 "maxLedgerVersion": 8820051
} }

View File

@@ -40,7 +40,11 @@ function main() {
makeRequest(connection, request4) makeRequest(connection, request4)
]).then(() => { ]).then(() => {
console.log('Done'); console.log('Done');
process.exit(); });
connection.getLedgerVersion().then(console.log);
connection.on('ledgerClosed', ledger => {
console.log(ledger);
connection.getLedgerVersion().then(console.log);
}); });
}); });
} }

View File

@@ -176,10 +176,11 @@ describe('integration tests', function() {
it('getFee', function() { it('getFee', function() {
const fee = this.api.getFee(); return this.api.getFee().then(fee => {
assert.strictEqual(typeof fee, 'string'); assert.strictEqual(typeof fee, 'string');
assert(!isNaN(Number(fee))); assert(!isNaN(Number(fee)));
assert(parseFloat(fee) === Number(fee)); assert(parseFloat(fee) === Number(fee));
});
}); });