Convert from Flow to Typescript (#816)

* convert to typescript
* add docs for custom node typing
* update webpack, gulpfile
This commit is contained in:
Fred K. Schott
2017-12-24 00:39:18 -08:00
committed by Elliot Lee
parent 5979ff6197
commit 8204f6c648
86 changed files with 1629 additions and 1532 deletions

View File

@@ -1,21 +1,22 @@
/* eslint-disable no-var, no-param-reassign */ /* eslint-disable no-var, no-param-reassign */
/* these eslint rules are disabled because gulp does not support babel yet */ /* these eslint rules are disabled because gulp does not support babel yet */
'use strict'; 'use strict';
var _ = require('lodash'); const _ = require('lodash');
var gulp = require('gulp'); const fs = require('fs');
var uglify = require('gulp-uglify'); const path = require('path');
var rename = require('gulp-rename'); const assert = require('assert');
var webpack = require('webpack'); const gulp = require('gulp');
var bump = require('gulp-bump'); const rename = require('gulp-rename');
var argv = require('yargs').argv; const webpack = require('webpack');
var assert = require('assert'); const bump = require('gulp-bump');
var fs = require('fs'); const argv = require('yargs').argv;
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
var pkg = require('./package.json'); var pkg = require('./package.json');
var uglifyOptions = { var uglifyOptions = {
mangle: { mangle: {
except: ['_', 'RippleError', 'RippledError', 'UnexpectedError', reserved: ['_', 'RippleError', 'RippledError', 'UnexpectedError',
'LedgerVersionError', 'ConnectionError', 'NotConnectedError', 'LedgerVersionError', 'ConnectionError', 'NotConnectedError',
'DisconnectedError', 'TimeoutError', 'ResponseFormatError', 'DisconnectedError', 'TimeoutError', 'ResponseFormatError',
'ValidationError', 'NotFoundError', 'MissingLedgerHistoryError', 'ValidationError', 'NotFoundError', 'MissingLedgerHistoryError',
@@ -24,17 +25,17 @@ var uglifyOptions = {
} }
}; };
function webpackConfig(extension, overrides) { function getWebpackConfig(extension, overrides) {
overrides = overrides || {}; overrides = overrides || {};
var defaults = { let defaults = {
cache: true, cache: true,
externals: [{ externals: [{
'lodash': '_' 'lodash': '_'
}], }],
entry: './src/index.js', entry: './src/index.ts',
output: { output: {
library: 'ripple', library: 'ripple',
path: './build/', path: path.join(__dirname, 'build/'),
filename: ['ripple-', extension].join(pkg.version) filename: ['ripple-', extension].join(pkg.version)
}, },
plugins: [ plugins: [
@@ -44,18 +45,21 @@ function webpackConfig(extension, overrides) {
'./setup-api-web') './setup-api-web')
], ],
module: { module: {
loaders: [{ rules: [{
test: /jayson/, test: /jayson/,
loader: 'null' use: 'null',
}, { }, {
test: /\.js$/, test: /\.ts$/,
exclude: [/node_modules/], use: 'ts-loader',
loader: 'babel-loader' exclude: /node_modules/,
}, { }, {
test: /\.json/, test: /\.json/,
loader: 'json-loader' use: 'json-loader',
}] }]
} },
resolve: {
extensions: [ '.ts', '.js' ]
},
}; };
return _.assign({}, defaults, overrides); return _.assign({}, defaults, overrides);
} }
@@ -78,7 +82,7 @@ function webpackConfigForWebTest(testFileName, path) {
filename: match[1] + '-test.js' filename: match[1] + '-test.js'
} }
}; };
return webpackConfig('.js', configOverrides); return getWebpackConfig('.js', configOverrides);
} }
gulp.task('build-tests', function(callback) { gulp.task('build-tests', function(callback) {
@@ -112,30 +116,29 @@ function createBuildLink(callback) {
} }
gulp.task('build', function(callback) { gulp.task('build', function(callback) {
webpack(webpackConfig('.js'), createBuildLink(callback)); webpack(getWebpackConfig('.js'), createBuildLink(callback));
}); });
gulp.task('build-min', ['build'], function() { gulp.task('build-min', function(callback) {
return gulp.src(['./build/ripple-', '.js'].join(pkg.version)) const webpackConfig = getWebpackConfig('-min.js');
.pipe(uglify(uglifyOptions)) webpackConfig.plugins.push(new UglifyJsPlugin({uglifyOptions}));
.pipe(rename(['ripple-', '-min.js'].join(pkg.version))) webpack(webpackConfig, function() {
.pipe(gulp.dest('./build/'))
.on('end', function() {
createLink('./build/ripple-' + pkg.version + '-min.js', createLink('./build/ripple-' + pkg.version + '-min.js',
'./build/ripple-latest-min.js'); './build/ripple-latest-min.js');
callback();
}); });
}); });
gulp.task('build-debug', function(callback) { gulp.task('build-debug', function(callback) {
var configOverrides = {debug: true, devtool: 'eval'}; const webpackConfig = getWebpackConfig('-debug.js', {devtool: 'eval'});
webpack(webpackConfig('-debug.js', configOverrides), callback); webpackConfig.plugins.unshift(new webpack.LoaderOptionsPlugin({debug: true}));
webpack(webpackConfig, callback);
}); });
/** /**
* Generate a WebPack external for a given unavailable module which replaces * Generate a WebPack external for a given unavailable module which replaces
* that module's constructor with an error-thrower * that module's constructor with an error-thrower
*/ */
function buildUseError(cons) { function buildUseError(cons) {
return ('var {<CONS>:function(){throw new Error(' return ('var {<CONS>:function(){throw new Error('
+ '"Class is unavailable in this build: <CONS>")}}') + '"Class is unavailable in this build: <CONS>")}}')
@@ -145,7 +148,7 @@ function buildUseError(cons) {
gulp.task('build-core', function(callback) { gulp.task('build-core', function(callback) {
var configOverrides = { var configOverrides = {
cache: false, cache: false,
entry: './src/remote.js', entry: './src/remote.ts',
externals: [{ externals: [{
'./transaction': buildUseError('Transaction'), './transaction': buildUseError('Transaction'),
'./orderbook': buildUseError('OrderBook'), './orderbook': buildUseError('OrderBook'),
@@ -153,10 +156,10 @@ gulp.task('build-core', function(callback) {
'./serializedobject': buildUseError('SerializedObject') './serializedobject': buildUseError('SerializedObject')
}], }],
plugins: [ plugins: [
new webpack.optimize.UglifyJsPlugin() new UglifyJsPlugin()
] ]
}; };
webpack(webpackConfig('-core.js', configOverrides), callback); webpack(getWebpackConfig('-core.js', configOverrides), callback);
}); });
gulp.task('bower-build', ['build'], function() { gulp.task('bower-build', ['build'], function() {

9
custom_typings/node.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
/**
* This is an extension of Node's `process` object to include the browser
* property, which is added by webpack.
*/
interface AmbiguousProcess extends NodeJS.Process {
browser?: true
}
declare var process: AmbiguousProcess;

View File

@@ -15,6 +15,8 @@
"test": "test" "test": "test"
}, },
"dependencies": { "dependencies": {
"@types/lodash": "^4.14.85",
"@types/ws": "^3.2.0",
"bignumber.js": "^4.1.0", "bignumber.js": "^4.1.0",
"https-proxy-agent": "^1.0.0", "https-proxy-agent": "^1.0.0",
"jsonschema": "^1.1.1", "jsonschema": "^1.1.1",
@@ -27,25 +29,16 @@
"ws": "^3.3.1" "ws": "^3.3.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^8.0.53",
"assert-diff": "^1.0.1", "assert-diff": "^1.0.1",
"babel-cli": "^6.26.0",
"babel-core": "^6.4.0",
"babel-eslint": "^6.0.4",
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13",
"babel-preset-flow": "^6.23.0",
"babel-preset-stage-1": "^6.3.13",
"babel-register": "^6.3.13",
"coveralls": "^2.13.1", "coveralls": "^2.13.1",
"doctoc": "^0.15.0", "doctoc": "^0.15.0",
"ejs": "^2.3.4", "ejs": "^2.3.4",
"eslint": "^2.9.0", "eslint": "^2.9.0",
"eventemitter2": "^0.4.14", "eventemitter2": "^0.4.14",
"flow-bin": "^0.59.0",
"gulp": "^3.8.10", "gulp": "^3.8.10",
"gulp-bump": "^0.1.13", "gulp-bump": "^0.1.13",
"gulp-rename": "^1.2.0", "gulp-rename": "^1.2.0",
"gulp-uglify": "^1.1.0",
"http-server": "^0.8.5", "http-server": "^0.8.5",
"istanbul": "^1.1.0-alpha.1", "istanbul": "^1.1.0-alpha.1",
"jayson": "^1.2.2", "jayson": "^1.2.2",
@@ -55,8 +48,12 @@
"mocha-in-sauce": "^0.0.1", "mocha-in-sauce": "^0.0.1",
"mocha-junit-reporter": "^1.9.1", "mocha-junit-reporter": "^1.9.1",
"null-loader": "^0.1.1", "null-loader": "^0.1.1",
"webpack": "^1.5.3", "ts-loader": "^3.2.0",
"yargs": "^1.3.1" "ts-node": "^3.3.0",
"typescript": "^2.6.1",
"uglifyjs-webpack-plugin": "^1.1.4",
"webpack": "^3.10.0",
"yargs": "^8.0.2"
}, },
"scripts": { "scripts": {
"build": "gulp", "build": "gulp",
@@ -64,11 +61,11 @@
"docgen": "node --harmony scripts/build_docs.js", "docgen": "node --harmony scripts/build_docs.js",
"clean": "rm -rf dist/npm", "clean": "rm -rf dist/npm",
"typecheck": "flow check", "typecheck": "flow check",
"compile": "babel -D --optional runtime -d dist/npm/ src/", "compile": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/ && tsc",
"watch": "babel -w -D --optional runtime -d dist/npm/ src/", "watch": "tsc -w",
"compile-with-source-maps": "babel -D --optional runtime -s -t -d dist/npm/ src/", "compile-with-source-maps": "babel -D --optional runtime -s -t -d dist/npm/ src/",
"prepublish": "npm run clean && npm run compile", "prepublish": "npm run clean && npm run compile",
"test": "babel-node ./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha", "test": "istanbul cover _mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls", "coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "if ! [ -f .eslintrc ]; then curl -o .eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'parser: babel-eslint' >> .eslintrc; fi; eslint -c .eslintrc src/", "lint": "if ! [ -f .eslintrc ]; then curl -o .eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'parser: babel-eslint' >> .eslintrc; fi; eslint -c .eslintrc src/",
"perf": "./scripts/perf_test.sh", "perf": "./scripts/perf_test.sh",

View File

@@ -1,7 +1,5 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import events from 'events' import {EventEmitter} from 'events'
import {Connection, errors, validate} from './common' import {Connection, errors, validate} from './common'
import * as server from './server/server' import * as server from './server/server'
const connect = server.connect const connect = server.connect
@@ -56,7 +54,7 @@ type APIOptions = {
// prevent access to non-validated ledger versions // prevent access to non-validated ledger versions
class RestrictedConnection extends Connection { class RestrictedConnection extends Connection {
request(request, timeout) { request(request: any, timeout?: number) {
const ledger_index = request.ledger_index const ledger_index = request.ledger_index
if (ledger_index !== undefined && ledger_index !== 'validated') { if (ledger_index !== undefined && ledger_index !== 'validated') {
if (!_.isNumber(ledger_index) || ledger_index > this._ledgerVersion) { if (!_.isNumber(ledger_index) || ledger_index > this._ledgerVersion) {
@@ -69,7 +67,7 @@ class RestrictedConnection extends Connection {
} }
} }
class RippleAPI extends events.EventEmitter { class RippleAPI extends EventEmitter {
_feeCushion: number _feeCushion: number
connection: RestrictedConnection connection: RestrictedConnection
@@ -80,11 +78,11 @@ class RippleAPI extends events.EventEmitter {
RangeSet, RangeSet,
ledgerUtils, ledgerUtils,
schemaValidator schemaValidator
}; }
constructor(options: APIOptions = {}) { constructor(options: APIOptions = {}) {
validate.apiOptions(options)
super() super()
validate.apiOptions(options)
this._feeCushion = options.feeCushion || 1.2 this._feeCushion = options.feeCushion || 1.2
const serverURL = options.server const serverURL = options.server
if (serverURL !== undefined) { if (serverURL !== undefined) {
@@ -107,51 +105,49 @@ class RippleAPI extends events.EventEmitter {
this.connection = new RestrictedConnection(null, options) this.connection = new RestrictedConnection(null, options)
} }
} }
connect = connect
disconnect = disconnect
isConnected = isConnected
getServerInfo = getServerInfo
getFee = getFee
getLedgerVersion = getLedgerVersion
getTransaction = getTransaction
getTransactions = getTransactions
getTrustlines = getTrustlines
getBalances = getBalances
getBalanceSheet = getBalanceSheet
getPaths = getPaths
getOrders = getOrders
getOrderbook = getOrderbook
getSettings = getSettings
getAccountInfo = getAccountInfo
getPaymentChannel = getPaymentChannel
getLedger = getLedger
preparePayment = preparePayment
prepareTrustline = prepareTrustline
prepareOrder = prepareOrder
prepareOrderCancellation = prepareOrderCancellation
prepareEscrowCreation = prepareEscrowCreation
prepareEscrowExecution = prepareEscrowExecution
prepareEscrowCancellation = prepareEscrowCancellation
preparePaymentChannelCreate = preparePaymentChannelCreate
preparePaymentChannelFund = preparePaymentChannelFund
preparePaymentChannelClaim = preparePaymentChannelClaim
prepareSettings = prepareSettings
sign = sign
combine = combine
submit = submit
generateAddress = generateAddressAPI
computeLedgerHash = computeLedgerHash
signPaymentChannelClaim = signPaymentChannelClaim
verifyPaymentChannelClaim = verifyPaymentChannelClaim
errors = errors
} }
_.assign(RippleAPI.prototype, {
connect,
disconnect,
isConnected,
getServerInfo,
getFee,
getLedgerVersion,
getTransaction,
getTransactions,
getTrustlines,
getBalances,
getBalanceSheet,
getPaths,
getOrders,
getOrderbook,
getSettings,
getAccountInfo,
getPaymentChannel,
getLedger,
preparePayment,
prepareTrustline,
prepareOrder,
prepareOrderCancellation,
prepareEscrowCreation,
prepareEscrowExecution,
prepareEscrowCancellation,
preparePaymentChannelCreate,
preparePaymentChannelFund,
preparePaymentChannelClaim,
prepareSettings,
sign,
combine,
submit,
generateAddress: generateAddressAPI,
computeLedgerHash,
signPaymentChannelClaim,
verifyPaymentChannelClaim,
errors
})
export { export {
RippleAPI RippleAPI
} }

View File

@@ -3,11 +3,15 @@ import * as _ from 'lodash'
import {RippleAPI} from './api' import {RippleAPI} from './api'
class RippleAPIBroadcast extends RippleAPI { class RippleAPIBroadcast extends RippleAPI {
// TODO: Should this default to 0, or null/undefined?
ledgerVersion: number = 0
private _apis: RippleAPI[]
constructor(servers, options) { constructor(servers, options) {
super(options) super(options)
this.ledgerVersion = 0
const apis = servers.map(server => new RippleAPI( const apis: RippleAPI[] = servers.map(server => new RippleAPI(
_.assign({}, options, {server}) _.assign({}, options, {server})
)) ))
@@ -21,14 +25,14 @@ class RippleAPIBroadcast extends RippleAPI {
}) })
// connection methods must be overridden to apply to all api instances // connection methods must be overridden to apply to all api instances
this.connect = function() { this.connect = async function() {
return Promise.all(apis.map(api => api.connect())) await Promise.all(apis.map(api => api.connect()))
} }
this.disconnect = function() { this.disconnect = async function() {
return Promise.all(apis.map(api => api.disconnect())) await Promise.all(apis.map(api => api.disconnect()))
} }
this.isConnected = function() { this.isConnected = function() {
return _.every(apis.map(api => api.isConnected())) return apis.map(api => api.isConnected()).every(Boolean)
} }
// synchronous methods are all passed directly to the first api instance // synchronous methods are all passed directly to the first api instance
@@ -53,12 +57,11 @@ class RippleAPIBroadcast extends RippleAPI {
} }
getMethodNames() { getMethodNames() {
const methodNames = [] const methodNames: string[] = []
for (const name in RippleAPI.prototype) { const rippleAPI = this._apis[0]
if (RippleAPI.prototype.hasOwnProperty(name)) { for (const name of Object.getOwnPropertyNames(rippleAPI)) {
if (typeof RippleAPI.prototype[name] === 'function') { if (typeof rippleAPI[name] === 'function') {
methodNames.push(name) methodNames.push(name)
}
} }
} }
return methodNames return methodNames

View File

@@ -1,18 +1,17 @@
function setPrototypeOf(object, prototype) { function setPrototypeOf(object, prototype) {
// Object.setPrototypeOf not supported on Internet Explorer 9 // Object.setPrototypeOf not supported on Internet Explorer 9
/* eslint-disable */
Object.setPrototypeOf ? Object.setPrototypeOf(object, prototype) : Object.setPrototypeOf ? Object.setPrototypeOf(object, prototype) :
// @ts-ignore: Specifically a fallback for IE9
object.__proto__ = prototype object.__proto__ = prototype
/* eslint-enable */
} }
function getConstructorName(object) { function getConstructorName(object: Object): string {
// hack for internet explorer // hack for internet explorer
return process.browser ? if (!object.constructor.name) {
object.constructor.toString().match(/^function\s+([^(]*)/)[1] : return object.constructor.toString().match(/^function\s+([^(]*)/)![1]
object.constructor.name }
return object.constructor.name
} }
export { export {

View File

@@ -1,9 +1,7 @@
import * as _ from 'lodash' import * as _ from 'lodash'
import events from 'events' import {EventEmitter} from 'events'
import WebSocket from 'ws' import {parse as parseUrl} from 'url'
import urlLib from 'url' import * as WebSocket from 'ws'
import RangeSet from './rangeset' import RangeSet from './rangeset'
import {RippledError, DisconnectedError, NotConnectedError, import {RippledError, DisconnectedError, NotConnectedError,
TimeoutError, ResponseFormatError, ConnectionError, TimeoutError, ResponseFormatError, ConnectionError,
@@ -15,12 +13,48 @@ function isStreamMessageType(type) {
type === 'path_find' type === 'path_find'
} }
class Connection extends events.EventEmitter { interface ConnectionOptions {
constructor(url, options = {}) { trace?: boolean,
proxy?: string
proxyAuthorization?: string
authorization?: string
trustedCertificates?: string[]
key?: string
passphrase?: string
certificate?: string
timeout?: number
}
class Connection extends EventEmitter {
private _url: string
private _trace: boolean
private _console?: Console
private _proxyURL?: string
private _proxyAuthorization?: string
private _authorization?: string
private _trustedCertificates?: string[]
private _key?: string
private _passphrase?: string
private _certificate?: string
private _timeout: number
private _isReady: boolean = false
private _ws: null|WebSocket = null
protected _ledgerVersion: null|number = null
private _availableLedgerVersions = new RangeSet()
private _nextRequestID: number = 1
private _retry: number = 0
private _retryTimer: null|NodeJS.Timer = null
private _onOpenErrorBound: null| null|((...args: any[]) => void) = null
private _onUnexpectedCloseBound: null|((...args: any[]) => void) = null
private _fee_base: null|number = null
private _fee_ref: null|number = null
constructor(url, options: ConnectionOptions = {}) {
super() super()
this.setMaxListeners(Infinity) this.setMaxListeners(Infinity)
this._url = url this._url = url
this._trace = options.trace this._trace = options.trace || false
if (this._trace) { if (this._trace) {
// for easier unit testing // for easier unit testing
this._console = console this._console = console
@@ -33,17 +67,6 @@ class Connection extends events.EventEmitter {
this._passphrase = options.passphrase this._passphrase = options.passphrase
this._certificate = options.certificate this._certificate = options.certificate
this._timeout = options.timeout || (20 * 1000) this._timeout = options.timeout || (20 * 1000)
this._isReady = false
this._ws = null
this._ledgerVersion = null
this._availableLedgerVersions = new RangeSet()
this._nextRequestID = 1
this._retry = 0
this._retryTimer = null
this._onOpenErrorBound = null
this._onUnexpectedCloseBound = null
this._fee_base = null
this._fee_ref = null
} }
_updateLedgerVersions(data) { _updateLedgerVersions(data) {
@@ -63,7 +86,7 @@ class Connection extends events.EventEmitter {
} }
// return value is array of arguments to Connection.emit // return value is array of arguments to Connection.emit
_parseMessage(message) { _parseMessage(message): [string, Object] | ['error', string, string, Object] {
const data = JSON.parse(message) const data = JSON.parse(message)
if (data.type === 'response') { if (data.type === 'response') {
if (!(Number.isInteger(data.id) && data.id >= 0)) { if (!(Number.isInteger(data.id) && data.id >= 0)) {
@@ -83,10 +106,10 @@ class Connection extends events.EventEmitter {
} }
_onMessage(message) { _onMessage(message) {
let parameters
if (this._trace) { if (this._trace) {
this._console.log(message) this._console!.log(message)
} }
let parameters
try { try {
parameters = this._parseMessage(message) parameters = this._parseMessage(message)
} catch (error) { } catch (error) {
@@ -95,7 +118,7 @@ class Connection extends events.EventEmitter {
} }
// we don't want this inside the try/catch or exceptions in listener // we don't want this inside the try/catch or exceptions in listener
// will be caught // will be caught
this.emit(...parameters) this.emit.apply(this, parameters)
} }
get _state() { get _state() {
@@ -112,11 +135,11 @@ class Connection extends events.EventEmitter {
_onUnexpectedClose(beforeOpen, resolve, reject, code) { _onUnexpectedClose(beforeOpen, resolve, reject, code) {
if (this._onOpenErrorBound) { if (this._onOpenErrorBound) {
this._ws.removeListener('error', this._onOpenErrorBound) this._ws!.removeListener('error', this._onOpenErrorBound)
this._onOpenErrorBound = null this._onOpenErrorBound = null
} }
// just in case // just in case
this._ws.removeAllListeners('open') this._ws!.removeAllListeners('open')
this._ws = null this._ws = null
this._isReady = false this._isReady = false
if (beforeOpen) { if (beforeOpen) {
@@ -155,8 +178,10 @@ class Connection extends events.EventEmitter {
} }
_clearReconnectTimer() { _clearReconnectTimer() {
clearTimeout(this._retryTimer) if (this._retryTimer !== null) {
this._retryTimer = null clearTimeout(this._retryTimer)
this._retryTimer = null
}
} }
_onOpen() { _onOpen() {
@@ -172,7 +197,7 @@ class Connection extends events.EventEmitter {
command: 'subscribe', command: 'subscribe',
streams: ['ledger'] streams: ['ledger']
} }
return this.request(request).then(data => { return this.request(request).then((data: any) => {
if (_.isEmpty(data) || !data.ledger_index) { if (_.isEmpty(data) || !data.ledger_index) {
// rippled instance doesn't have validated ledgers // rippled instance doesn't have validated ledgers
return this._disconnect(false).then(() => { return this._disconnect(false).then(() => {
@@ -186,7 +211,8 @@ class Connection extends events.EventEmitter {
this._retry = 0 this._retry = 0
this._ws.on('error', error => { this._ws.on('error', error => {
if (process.browser && error && error.type === 'error') { // TODO: "type" does not exist on official error type, safe to remove?
if (process.browser && error && (<any>error).type === 'error') {
// we are in browser, ignore error - `close` event will be fired // we are in browser, ignore error - `close` event will be fired
// after error // after error
return return
@@ -223,11 +249,11 @@ class Connection extends events.EventEmitter {
reject(new NotConnectedError(error && error.message)) reject(new NotConnectedError(error && error.message))
} }
_createWebSocket() { _createWebSocket(): WebSocket {
const options = {} const options: WebSocket.ClientOptions = {}
if (this._proxyURL !== undefined) { if (this._proxyURL !== undefined) {
const parsedURL = urlLib.parse(this._url) const parsedURL = parseUrl(this._url)
const parsedProxyURL = urlLib.parse(this._proxyURL) const parsedProxyURL = parseUrl(this._proxyURL)
const proxyOverrides = _.omitBy({ const proxyOverrides = _.omitBy({
secureEndpoint: (parsedURL.protocol === 'wss:'), secureEndpoint: (parsedURL.protocol === 'wss:'),
secureProxy: (parsedProxyURL.protocol === 'https:'), secureProxy: (parsedProxyURL.protocol === 'https:'),
@@ -337,7 +363,7 @@ class Connection extends events.EventEmitter {
return this.disconnect().then(() => this.connect()) return this.disconnect().then(() => this.connect())
} }
_whenReady(promise) { _whenReady<T>(promise: Promise<T>): Promise<T> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this._shouldBeConnected) { if (!this._shouldBeConnected) {
reject(new NotConnectedError()) reject(new NotConnectedError())
@@ -349,44 +375,44 @@ class Connection extends events.EventEmitter {
}) })
} }
getLedgerVersion() { getLedgerVersion(): Promise<number> {
return this._whenReady(Promise.resolve(this._ledgerVersion)) return this._whenReady(Promise.resolve(this._ledgerVersion!))
} }
hasLedgerVersions(lowLedgerVersion, highLedgerVersion) { hasLedgerVersions(lowLedgerVersion, highLedgerVersion): Promise<boolean> {
return this._whenReady(Promise.resolve( return this._whenReady(Promise.resolve(
this._availableLedgerVersions.containsRange( this._availableLedgerVersions.containsRange(
lowLedgerVersion, highLedgerVersion || this._ledgerVersion))) lowLedgerVersion, highLedgerVersion || this._ledgerVersion)))
} }
hasLedgerVersion(ledgerVersion) { hasLedgerVersion(ledgerVersion): Promise<boolean> {
return this.hasLedgerVersions(ledgerVersion, ledgerVersion) return this.hasLedgerVersions(ledgerVersion, ledgerVersion)
} }
getFeeBase() { getFeeBase(): Promise<number> {
return this._whenReady(Promise.resolve(Number(this._fee_base))) return this._whenReady(Promise.resolve(Number(this._fee_base)))
} }
getFeeRef() { getFeeRef(): Promise<number> {
return this._whenReady(Promise.resolve(Number(this._fee_ref))) return this._whenReady(Promise.resolve(Number(this._fee_ref)))
} }
_send(message) { _send(message: string): Promise<void> {
if (this._trace) { if (this._trace) {
this._console.log(message) this._console.log(message)
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this._ws.send(message, undefined, (error, result) => { this._ws.send(message, undefined, error => {
if (error) { if (error) {
reject(new DisconnectedError(error.message)) reject(new DisconnectedError(error.message))
} else { } else {
resolve(result) resolve()
} }
}) })
}) })
} }
request(request, timeout) { request(request, timeout?: number): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!this._shouldBeConnected) { if (!this._shouldBeConnected) {
reject(new NotConnectedError()) reject(new NotConnectedError())

View File

@@ -1,33 +1,28 @@
import util from 'util' import {inspect} from 'util'
import * as browserHacks from './browser-hacks' import * as browserHacks from './browser-hacks'
// this is needed because extending builtins doesn't work in babel 6.x class RippleError extends Error {
function extendableBuiltin(cls) {
function ExtendableBuiltin() {
cls.apply(this, arguments)
}
ExtendableBuiltin.prototype = Object.create(cls.prototype)
browserHacks.setPrototypeOf(ExtendableBuiltin, cls)
return ExtendableBuiltin
}
class RippleError extends extendableBuiltin(Error) { name: string
constructor(message, data) { message: string
data?: any
constructor(message = '', data?: any) {
super(message) super(message)
this.name = browserHacks.getConstructorName(this) this.name = browserHacks.getConstructorName(this)
this.message = message this.message = message
this.data = data this.data = data
if (Error.captureStackTrace) { if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor.name) Error.captureStackTrace(this, this.constructor)
} }
} }
toString() { toString() {
let result = '[' + this.name + '(' + this.message let result = '[' + this.name + '(' + this.message
if (this.data) { if (this.data) {
result += ', ' + util.inspect(this.data) result += ', ' + inspect(this.data)
} }
result += ')]' result += ')]'
return result return result
@@ -62,21 +57,21 @@ class ResponseFormatError extends ConnectionError {}
class ValidationError extends RippleError {} class ValidationError extends RippleError {}
class NotFoundError extends RippleError { class NotFoundError extends RippleError {
constructor(message) { constructor(message = 'Not found') {
super(message || 'Not found') super(message)
} }
} }
class MissingLedgerHistoryError extends RippleError { class MissingLedgerHistoryError extends RippleError {
constructor(message) { constructor(message?: string) {
super(message || 'Server is missing ledger history in the specified range') super(message || 'Server is missing ledger history in the specified range')
} }
} }
class PendingLedgerVersionError extends RippleError { class PendingLedgerVersionError extends RippleError {
constructor(message) { constructor(message?: string) {
super(message || 'maxLedgerVersion is greater than server\'s' super(message || 'maxLedgerVersion is greater than server\'s most recent ' +
+ ' most recent validated ledger') ' validated ledger')
} }
} }

View File

@@ -1,12 +1,12 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import assert from 'assert' import * as assert from 'assert'
function mergeIntervals(intervals: Array<[number, number]>) { type Interval = [number, number]
const stack = [[-Infinity, -Infinity]]
_.forEach(_.sortBy(intervals, x => x[0]), interval => { function mergeIntervals(intervals: Interval[]): Interval[] {
const lastInterval = stack.pop() const stack: Interval[] = [[-Infinity, -Infinity]]
_.sortBy(intervals, x => x[0]).forEach(interval => {
const lastInterval: Interval = stack.pop()!
if (interval[0] <= lastInterval[1] + 1) { if (interval[0] <= lastInterval[1] + 1) {
stack.push([lastInterval[0], Math.max(interval[1], lastInterval[1])]) stack.push([lastInterval[0], Math.max(interval[1], lastInterval[1])])
} else { } else {

View File

@@ -1,9 +1,6 @@
// flow is disabled for this file until support for requiring json is added:
// https://github.com/facebook/flow/issues/167
import * as _ from 'lodash' import * as _ from 'lodash'
import assert from 'assert' import * as assert from 'assert'
import {Validator} from 'jsonschema' const {Validator} = require('jsonschema')
import {ValidationError} from './errors' import {ValidationError} from './errors'
import {isValidAddress} from 'ripple-address-codec' import {isValidAddress} from 'ripple-address-codec'
import {isValidSecret} from './utils' import {isValidSecret} from './utils'
@@ -111,20 +108,20 @@ function loadSchemas() {
require('./schemas/input/verify-payment-channel-claim.json'), require('./schemas/input/verify-payment-channel-claim.json'),
require('./schemas/input/combine.json') require('./schemas/input/combine.json')
] ]
const titles = _.map(schemas, schema => schema.title) const titles = schemas.map(schema => schema.title)
const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1)) const duplicates = _.keys(_.pickBy(_.countBy(titles), count => count > 1))
assert(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates) assert(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates)
const v = new Validator() const validator = new Validator()
// Register custom format validators that ignore undefined instances // Register custom format validators that ignore undefined instances
// since jsonschema will still call the format validator on a missing // since jsonschema will still call the format validator on a missing
// (optional) property // (optional) property
v.customFormats.address = function(instance) { validator.customFormats.address = function(instance) {
if (instance === undefined) { if (instance === undefined) {
return true return true
} }
return isValidAddress(instance) return isValidAddress(instance)
} }
v.customFormats.secret = function(instance) { validator.customFormats.secret = function(instance) {
if (instance === undefined) { if (instance === undefined) {
return true return true
} }
@@ -132,19 +129,19 @@ function loadSchemas() {
} }
// Register under the root URI '/' // Register under the root URI '/'
_.forEach(schemas, schema => v.addSchema(schema, '/' + schema.title)) _.forEach(schemas, schema => validator.addSchema(schema, '/' + schema.title))
return v return validator
} }
const v = loadSchemas() const schemaValidator = loadSchemas()
function schemaValidate(schemaName: string, object: any): void { function schemaValidate(schemaName: string, object: any): void {
// Lookup under the root URI '/' // Lookup under the root URI '/'
const schema = v.getSchema('/' + schemaName) const schema = schemaValidator.getSchema('/' + schemaName)
if (schema === undefined) { if (schema === undefined) {
throw new ValidationError('no schema for ' + schemaName) throw new ValidationError('no schema for ' + schemaName)
} }
const result = v.validate(object, schema) const result = schemaValidator.validate(object, schema)
if (!result.valid) { if (!result.valid) {
throw new ValidationError(result.errors.join()) throw new ValidationError(result.errors.join())
} }

View File

@@ -1,6 +1,6 @@
import * as _ from 'lodash' import * as _ from 'lodash'
import {convertKeysFromSnakeCaseToCamelCase} from './utils' import {convertKeysFromSnakeCaseToCamelCase} from './utils'
import type Connection from './connection' import Connection from './connection'
export type GetServerInfoResponse = { export type GetServerInfoResponse = {
buildVersion: string, buildVersion: string,
@@ -60,16 +60,19 @@ function getServerInfo(connection: Connection): Promise<GetServerInfoResponse> {
}) })
} }
// TODO: This was originally annotated to return a number, but actually
// returned a toString'ed number. Should this actually be returning a number?
function computeFeeFromServerInfo(cushion: number, function computeFeeFromServerInfo(cushion: number,
serverInfo: GetServerInfoResponse serverInfo: GetServerInfoResponse
): number { ): string {
return (Number(serverInfo.validatedLedger.baseFeeXRP) return (Number(serverInfo.validatedLedger.baseFeeXRP)
* Number(serverInfo.loadFactor) * cushion).toString() * Number(serverInfo.loadFactor) * cushion).toString()
} }
function getFee(connection: Connection, cushion: number) { function getFee(connection: Connection, cushion: number): Promise<string> {
return getServerInfo(connection).then( return getServerInfo(connection).then(serverInfo => {
_.partial(computeFeeFromServerInfo, cushion)) return computeFeeFromServerInfo(cushion, serverInfo)
})
} }
export { export {

View File

@@ -1,5 +1,3 @@
/* @flow */
export type RippledAmountIOU = { export type RippledAmountIOU = {
currency: string, currency: string,
@@ -13,6 +11,7 @@ export type RippledAmount = string | RippledAmountIOU
export type Amount = { export type Amount = {
value: string, value: string,
currency: string, currency: string,
issuer?: string,
counterparty?: string counterparty?: string
} }
@@ -21,12 +20,14 @@ export type Amount = {
export type LaxLaxAmount = { export type LaxLaxAmount = {
currency: string, currency: string,
value?: string, value?: string,
issuer?: string,
counterparty?: string counterparty?: string
} }
// A currency-counterparty pair, or just currency if it's XRP // A currency-counterparty pair, or just currency if it's XRP
export type Issue = { export type Issue = {
currency: string, currency: string,
issuer?: string,
counterparty?: string counterparty?: string
} }
@@ -53,3 +54,10 @@ export type Memo = {
format?: string, format?: string,
data?: string data?: string
} }
export type ApiMemo = {
MemoData?: string,
MemoType?: string,
MemoFormat?: string
}

View File

@@ -1,10 +1,8 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import {deriveKeypair} from 'ripple-keypairs' const {deriveKeypair} = require('ripple-keypairs')
import type {Amount, RippledAmount} from './types' import {Amount, RippledAmount} from './types'
function isValidSecret(secret: string): boolean { function isValidSecret(secret: string): boolean {
try { try {
@@ -27,7 +25,6 @@ function toRippledAmount(amount: Amount): RippledAmount {
if (amount.currency === 'XRP') { if (amount.currency === 'XRP') {
return xrpToDrops(amount.value) return xrpToDrops(amount.value)
} }
// $FlowFixMe: amount.issuer is not a Amount type property. Safe to remove?
return { return {
currency: amount.currency, currency: amount.currency,
issuer: amount.counterparty ? amount.counterparty : issuer: amount.counterparty ? amount.counterparty :
@@ -53,8 +50,8 @@ function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
return obj return obj
} }
function removeUndefined(obj: Object): Object { function removeUndefined<T extends object>(obj: T): T {
return _.omitBy(obj, _.isUndefined) return _.omitBy(obj, _.isUndefined) as T
} }
/** /**

View File

@@ -1,5 +1,3 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import {ValidationError} from './errors' import {ValidationError} from './errors'
import {schemaValidate} from './schema-validator' import {schemaValidate} from './schema-validator'

View File

@@ -1,18 +1,31 @@
import {EventEmitter} from 'events'
// Define the global WebSocket class found on the native browser
import events from 'events' declare class WebSocket {
onclose?: Function
function unsused() {} onopen?: Function
onerror?: Function
onmessage?: Function
readyState: number
constructor(url: string)
close()
send(message: string)
}
/** /**
* Provides `EventEmitter` interface for native browser `WebSocket`, * Provides `EventEmitter` interface for native browser `WebSocket`,
* same, as `ws` package provides. * same, as `ws` package provides.
*/ */
class WSWrapper extends events.EventEmitter { class WSWrapper extends EventEmitter {
constructor(url, protocols = null, websocketOptions = {}) {
private _ws: WebSocket
static CONNECTING = 0
static OPEN = 1
static CLOSING = 2
static CLOSED = 3
constructor(url, _protocols: any, _websocketOptions: any) {
super() super()
unsused(protocols)
unsused(websocketOptions)
this.setMaxListeners(Infinity) this.setMaxListeners(Infinity)
this._ws = new WebSocket(url) this._ws = new WebSocket(url)
@@ -50,10 +63,5 @@ class WSWrapper extends events.EventEmitter {
} }
WSWrapper.CONNECTING = 0 export = WSWrapper
WSWrapper.OPEN = 1
WSWrapper.CLOSING = 2
WSWrapper.CLOSED = 3
export default WSWrapper

View File

@@ -1,6 +1,6 @@
/* eslint-disable new-cap */ /* eslint-disable new-cap */
import assert from 'assert' import * as assert from 'assert'
import * as _ from 'lodash' import * as _ from 'lodash'
import jayson from 'jayson' import jayson from 'jayson'
import {RippleAPI} from './api' import {RippleAPI} from './api'

View File

@@ -1,5 +1,3 @@
/* @flow */
import {validate, removeUndefined, dropsToXrp} from '../common' import {validate, removeUndefined, dropsToXrp} from '../common'
type AccountData = { type AccountData = {

View File

@@ -1,9 +1,7 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import {validate} from '../common' import {validate} from '../common'
import type {Amount} from '../common/types' import {Amount} from '../common/types'
type BalanceSheetOptions = { type BalanceSheetOptions = {
excludeAddresses?: Array<string>, excludeAddresses?: Array<string>,
@@ -20,7 +18,7 @@ type GetBalanceSheet = {
} }
function formatBalanceSheet(balanceSheet): GetBalanceSheet { function formatBalanceSheet(balanceSheet): GetBalanceSheet {
const result = {} const result: GetBalanceSheet = {}
if (!_.isUndefined(balanceSheet.balances)) { if (!_.isUndefined(balanceSheet.balances)) {
result.balances = [] result.balances = []
@@ -39,8 +37,10 @@ function formatBalanceSheet(balanceSheet): GetBalanceSheet {
}) })
} }
if (!_.isUndefined(balanceSheet.obligations)) { if (!_.isUndefined(balanceSheet.obligations)) {
result.obligations = _.map(balanceSheet.obligations, (value, currency) => result.obligations = _.map(
({currency, value})) balanceSheet.obligations as {[key: string]: string},
(value, currency) => ({currency, value})
)
} }
return result return result

View File

@@ -1,9 +1,7 @@
/* @flow */
import * as utils from './utils' import * as utils from './utils'
import {validate} from '../common' import {validate} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import type {TrustlinesOptions, Trustline} from './trustlines-types' import {TrustlinesOptions, Trustline} from './trustlines-types'
type Balance = { type Balance = {

View File

@@ -1,8 +1,6 @@
/* @flow */
import {validate} from '../common' import {validate} from '../common'
import parseLedger from './parse/ledger' import parseLedger from './parse/ledger'
import type {GetLedger} from './types' import {GetLedger} from './types'
type LedgerOptions = { type LedgerOptions = {
ledgerVersion?: number, ledgerVersion?: number,

View File

@@ -1,12 +1,10 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import parseOrderbookOrder from './parse/orderbook-order' import parseOrderbookOrder from './parse/orderbook-order'
import {validate} from '../common' import {validate} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import type {OrdersOptions, OrderSpecification} from './types' import {OrdersOptions, OrderSpecification} from './types'
import type {Amount, Issue} from '../common/types' import {Amount, Issue} from '../common/types'
type Orderbook = { type Orderbook = {
base: Issue, base: Issue,
@@ -36,21 +34,25 @@ type GetOrderbook = {
// account is to specify a "perspective", which affects which unfunded offers // account is to specify a "perspective", which affects which unfunded offers
// are returned // are returned
function getBookOffers(connection: Connection, account: string, function getBookOffers(connection: Connection, account: string,
ledgerVersion?: number, limit?: number, takerGets: Issue, ledgerVersion: number|undefined, limit: number|undefined, takerGets: Issue,
takerPays: Issue takerPays: Issue
): Promise<Object[]> { ): Promise<Object[]> {
return connection.request(utils.renameCounterpartyToIssuerInOrder({ const orderData = utils.renameCounterpartyToIssuerInOrder({
command: 'book_offers',
taker_gets: takerGets, taker_gets: takerGets,
taker_pays: takerPays, taker_pays: takerPays
})
return connection.request({
command: 'book_offers',
taker_gets: orderData.taker_gets,
taker_pays: orderData.taker_pays,
ledger_index: ledgerVersion || 'validated', ledger_index: ledgerVersion || 'validated',
limit: limit, limit: limit,
taker: account taker: account
})).then(data => data.offers) }).then(data => data.offers)
} }
function isSameIssue(a: Amount, b: Amount) { function isSameIssue(a: Amount, b: Amount) {
return a.currency === b.currency && a.counterparty === b.counterparty return a.currency === b.currency && a.issuer === b.issuer
} }
function directionFilter(direction: string, order: OrderbookItem) { function directionFilter(direction: string, order: OrderbookItem) {

View File

@@ -1,11 +1,9 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import {validate} from '../common' import {validate} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import parseAccountOrder from './parse/account-order' import parseAccountOrder from './parse/account-order'
import type {OrdersOptions, Order} from './types' import {OrdersOptions, Order} from './types'
type GetOrders = Array<Order> type GetOrders = Array<Order>
@@ -18,12 +16,10 @@ function requestAccountOffers(connection: Connection, address: string,
marker: marker, marker: marker,
limit: utils.clamp(limit, 10, 400), limit: utils.clamp(limit, 10, 400),
ledger_index: ledgerVersion ledger_index: ledgerVersion
}).then(data => { }).then(data => ({
return { marker: data.marker,
marker: data.marker, results: data.offers.map(_.partial(parseAccountOrder, address))
results: data.offers.map(_.partial(parseAccountOrder, address)) }))
}
})
} }
function getOrders(address: string, options: OrdersOptions = {} function getOrders(address: string, options: OrdersOptions = {}

View File

@@ -1,5 +1,3 @@
/* @flow */
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import parseAmount from './amount' import parseAmount from './amount'
import {parseTimestamp, adjustQualityForXRP} from './utils' import {parseTimestamp, adjustQualityForXRP} from './utils'
@@ -14,7 +12,7 @@ function computeQuality(takerGets, takerPays) {
// rippled 'account_offers' returns a different format for orders than 'tx' // rippled 'account_offers' returns a different format for orders than 'tx'
// the flags are also different // the flags are also different
function parseAccountOrder(address: string, order: Object): Object { function parseAccountOrder(address: string, order: any): Object {
const direction = (order.flags & orderFlags.Sell) === 0 ? 'buy' : 'sell' const direction = (order.flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
const takerGetsAmount = parseAmount(order.taker_gets) const takerGetsAmount = parseAmount(order.taker_gets)
const takerPaysAmount = parseAmount(order.taker_pays) const takerPaysAmount = parseAmount(order.taker_pays)

View File

@@ -1,11 +1,9 @@
/* @flow */
import {parseQuality} from './utils' import {parseQuality} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
type Trustline = { type Trustline = {
account: string, limit: number, currency: string, quality_in: ?number, account: string, limit: number, currency: string, quality_in: number|null,
quality_out: ?number, no_ripple: boolean, freeze: boolean, quality_out: number|null, no_ripple: boolean, freeze: boolean,
authorized: boolean, limit_peer: string, no_ripple_peer: boolean, authorized: boolean, limit_peer: string, no_ripple_peer: boolean,
freeze_peer: boolean, peer_authorized: boolean, balance: any freeze_peer: boolean, peer_authorized: boolean, balance: any
} }

View File

@@ -1,6 +1,6 @@
function parseAmendment(tx: Object) { function parseAmendment(tx: any) {
return { return {
amendment: tx.Amendment amendment: tx.Amendment
} }

View File

@@ -1,7 +1,5 @@
/* @flow */
import * as common from '../../common' import * as common from '../../common'
import type {Amount, RippledAmount} from '../../common/types' import {Amount, RippledAmount} from '../../common/types'
function parseAmount(amount: RippledAmount): Amount { function parseAmount(amount: RippledAmount): Amount {

View File

@@ -1,8 +1,6 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert' function parseOrderCancellation(tx: any): Object {
function parseOrderCancellation(tx: Object): Object {
assert(tx.TransactionType === 'OfferCancel') assert(tx.TransactionType === 'OfferCancel')
return { return {
orderSequence: tx.OfferSequence orderSequence: tx.OfferSequence

View File

@@ -1,10 +1,8 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseMemos} from './utils' import {parseMemos} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
function parseEscrowCancellation(tx: Object): Object { function parseEscrowCancellation(tx: any): Object {
assert(tx.TransactionType === 'EscrowCancel') assert(tx.TransactionType === 'EscrowCancel')
return removeUndefined({ return removeUndefined({

View File

@@ -1,11 +1,9 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import parseAmount from './amount' import parseAmount from './amount'
import {parseTimestamp, parseMemos} from './utils' import {parseTimestamp, parseMemos} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
function parseEscrowCreation(tx: Object): Object { function parseEscrowCreation(tx: any): Object {
assert(tx.TransactionType === 'EscrowCreate') assert(tx.TransactionType === 'EscrowCreate')
return removeUndefined({ return removeUndefined({

View File

@@ -1,10 +1,8 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseMemos} from './utils' import {parseMemos} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
function parseEscrowExecution(tx: Object): Object { function parseEscrowExecution(tx: any): Object {
assert(tx.TransactionType === 'EscrowFinish') assert(tx.TransactionType === 'EscrowFinish')
return removeUndefined({ return removeUndefined({

View File

@@ -2,7 +2,7 @@
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import {dropsToXrp} from '../../common' import {dropsToXrp} from '../../common'
function parseFeeUpdate(tx: Object) { function parseFeeUpdate(tx: any) {
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString() const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString()
return { return {
baseFeeXRP: dropsToXrp(baseFeeDrops), baseFeeXRP: dropsToXrp(baseFeeDrops),

View File

@@ -1,5 +1,3 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import {constants} from '../../common' import {constants} from '../../common'
@@ -15,8 +13,8 @@ function parseField(info, value) {
return value return value
} }
function parseFields(data: Object): Object { function parseFields(data: any): Object {
const settings = {} const settings: any = {}
for (const fieldName in AccountFields) { for (const fieldName in AccountFields) {
const fieldValue = data[fieldName] const fieldValue = data[fieldName]
if (fieldValue !== undefined) { if (fieldValue !== undefined) {
@@ -39,7 +37,7 @@ function parseFields(data: Object): Object {
if (data.signer_lists[0].SignerEntries) { if (data.signer_lists[0].SignerEntries) {
settings.signers.weights = _.map( settings.signers.weights = _.map(
data.signer_lists[0].SignerEntries, data.signer_lists[0].SignerEntries,
entry => { (entry: any) => {
return { return {
address: entry.SignerEntry.Account, address: entry.SignerEntry.Account,
weight: entry.SignerEntry.SignerWeight weight: entry.SignerEntry.SignerWeight

View File

@@ -1,9 +1,7 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import {removeUndefined, rippleTimeToISO8601} from '../../common' import {removeUndefined, rippleTimeToISO8601} from '../../common'
import parseTransaction from './transaction' import parseTransaction from './transaction'
import type {GetLedger} from '../types' import {GetLedger} from '../types'
function parseTransactionWrapper(ledgerVersion, tx) { function parseTransactionWrapper(ledgerVersion, tx) {
const transaction = _.assign({}, _.omit(tx, 'metaData'), { const transaction = _.assign({}, _.omit(tx, 'metaData'), {
@@ -41,9 +39,9 @@ function parseState(state) {
return {rawState: JSON.stringify(state)} return {rawState: JSON.stringify(state)}
} }
function parseLedger(ledger: Object): GetLedger { function parseLedger(ledger: any): GetLedger {
const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10) const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10)
return removeUndefined(_.assign({ return removeUndefined(Object.assign({
stateHash: ledger.account_hash, stateHash: ledger.account_hash,
closeTime: rippleTimeToISO8601(ledger.close_time), closeTime: rippleTimeToISO8601(ledger.close_time),
closeTimeResolution: ledger.close_time_resolution, closeTimeResolution: ledger.close_time_resolution,

View File

@@ -1,12 +1,10 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseTimestamp} from './utils' import {parseTimestamp} from './utils'
import parseAmount from './amount' import parseAmount from './amount'
import {removeUndefined, txFlags} from '../../common' import {removeUndefined, txFlags} from '../../common'
const flags = txFlags.OfferCreate const flags = txFlags.OfferCreate
function parseOrder(tx: Object): Object { function parseOrder(tx: any): Object {
assert(tx.TransactionType === 'OfferCreate') assert(tx.TransactionType === 'OfferCreate')
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell' const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell'

View File

@@ -1,5 +1,3 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import {parseTimestamp, adjustQualityForXRP} from './utils' import {parseTimestamp, adjustQualityForXRP} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
@@ -7,7 +5,7 @@ import {removeUndefined} from '../../common'
import {orderFlags} from './flags' import {orderFlags} from './flags'
import parseAmount from './amount' import parseAmount from './amount'
function parseOrderbookOrder(order: Object): Object { function parseOrderbookOrder(order: any): Object {
const direction = (order.Flags & orderFlags.Sell) === 0 ? 'buy' : 'sell' const direction = (order.Flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
const takerGetsAmount = parseAmount(order.TakerGets) const takerGetsAmount = parseAmount(order.TakerGets)
const takerPaysAmount = parseAmount(order.TakerPays) const takerPaysAmount = parseAmount(order.TakerPays)

View File

@@ -1,9 +1,7 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import parseAmount from './amount' import parseAmount from './amount'
import type {Amount, RippledAmount} from '../../common/types' import {Amount, RippledAmount} from '../../common/types'
import type {GetPaths, RippledPathsResponse} from '../pathfind-types' import {Path, GetPaths, RippledPathsResponse} from '../pathfind-types'
function parsePaths(paths) { function parsePaths(paths) {
return paths.map(steps => steps.map(step => return paths.map(steps => steps.map(step =>
@@ -15,7 +13,8 @@ function removeAnyCounterpartyEncoding(address: string, amount: Amount) {
_.omit(amount, 'counterparty') : amount _.omit(amount, 'counterparty') : amount
} }
function createAdjustment(address: string, adjustmentWithoutAddress: Object) { function createAdjustment(
address: string, adjustmentWithoutAddress: Object): any {
const amountKey = _.keys(adjustmentWithoutAddress)[0] const amountKey = _.keys(adjustmentWithoutAddress)[0]
const amount = adjustmentWithoutAddress[amountKey] const amount = adjustmentWithoutAddress[amountKey]
return _.set({address: address}, amountKey, return _.set({address: address}, amountKey,
@@ -23,8 +22,8 @@ function createAdjustment(address: string, adjustmentWithoutAddress: Object) {
} }
function parseAlternative(sourceAddress: string, destinationAddress: string, function parseAlternative(sourceAddress: string, destinationAddress: string,
destinationAmount: RippledAmount, alternative: Object destinationAmount: RippledAmount, alternative: any
) { ): Path {
// we use "maxAmount"/"minAmount" here so that the result can be passed // we use "maxAmount"/"minAmount" here so that the result can be passed
// directly to preparePayment // directly to preparePayment
const amounts = (alternative.destination_amount !== undefined) ? const amounts = (alternative.destination_amount !== undefined) ?
@@ -44,8 +43,8 @@ function parsePathfind(pathfindResult: RippledPathsResponse): GetPaths {
const sourceAddress = pathfindResult.source_account const sourceAddress = pathfindResult.source_account
const destinationAddress = pathfindResult.destination_account const destinationAddress = pathfindResult.destination_account
const destinationAmount = pathfindResult.destination_amount const destinationAmount = pathfindResult.destination_amount
return pathfindResult.alternatives.map(_.partial(parseAlternative, return pathfindResult.alternatives.map(alt =>
sourceAddress, destinationAddress, destinationAmount)) parseAlternative(sourceAddress, destinationAddress, destinationAmount, alt))
} }
export default parsePathfind export default parsePathfind

View File

@@ -1,11 +1,9 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {removeUndefined, txFlags} from '../../common' import {removeUndefined, txFlags} from '../../common'
import parseAmount from './amount' import parseAmount from './amount'
const claimFlags = txFlags.PaymentChannelClaim const claimFlags = txFlags.PaymentChannelClaim
function parsePaymentChannelClaim(tx: Object): Object { function parsePaymentChannelClaim(tx: any): Object {
assert(tx.TransactionType === 'PaymentChannelClaim') assert(tx.TransactionType === 'PaymentChannelClaim')
return removeUndefined({ return removeUndefined({

View File

@@ -1,11 +1,9 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseTimestamp} from './utils' import {parseTimestamp} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
import parseAmount from './amount' import parseAmount from './amount'
function parsePaymentChannelCreate(tx: Object): Object { function parsePaymentChannelCreate(tx: any): Object {
assert(tx.TransactionType === 'PaymentChannelCreate') assert(tx.TransactionType === 'PaymentChannelCreate')
return removeUndefined({ return removeUndefined({

View File

@@ -1,11 +1,9 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseTimestamp} from './utils' import {parseTimestamp} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
import parseAmount from './amount' import parseAmount from './amount'
function parsePaymentChannelFund(tx: Object): Object { function parsePaymentChannelFund(tx: any): Object {
assert(tx.TransactionType === 'PaymentChannelFund') assert(tx.TransactionType === 'PaymentChannelFund')
return removeUndefined({ return removeUndefined({

View File

@@ -1,23 +1,49 @@
/* @flow */
import {parseTimestamp} from './utils' import {parseTimestamp} from './utils'
import {removeUndefined, dropsToXrp} from '../../common' import {removeUndefined, dropsToXrp} from '../../common'
export type PaymentChannel = {
Sequence: number,
Account: string,
Amount: string,
Balance: string,
PublicKey: number,
Destination: string,
SettleDelay: number,
Expiration?: number,
CancelAfter?: number,
SourceTag?: number,
DestinationTag?: number,
OwnerNode: string,
LedgerEntryType: string,
PreviousTxnID: string,
PreviousTxnLgrSeq: number,
index: string
}
export type LedgerEntryResponse = {
node: PaymentChannel,
ledger_current_index?: number,
ledger_hash?: string,
ledger_index: number,
validated: boolean
}
type PaymentChannelResponse = { type PaymentChannelResponse = {
account: string, account: string,
balance: string, balance: string,
publicKey: number, publicKey: number,
destination: string, destination: string,
settleDelay: number, settleDelay: number,
expiration?: number, expiration?: string,
cancelAfter?: number, cancelAfter?: string,
sourceTag?: number, sourceTag?: number,
destinationTag?: number, destinationTag?: number,
previousAffectingTransactionID: string, previousAffectingTransactionID: string,
previousAffectingTransactionLedgerVersion: number previousAffectingTransactionLedgerVersion: number
} }
function parsePaymentChannel(data: Object): PaymentChannelResponse { function parsePaymentChannel(data: PaymentChannel): PaymentChannelResponse {
return removeUndefined({ return removeUndefined({
account: data.Account, account: data.Account,
amount: dropsToXrp(data.Amount), amount: dropsToXrp(data.Amount),

View File

@@ -1,7 +1,5 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import assert from 'assert' import * as assert from 'assert'
import * as utils from './utils' import * as utils from './utils'
import {txFlags, removeUndefined} from '../../common' import {txFlags, removeUndefined} from '../../common'
import parseAmount from './amount' import parseAmount from './amount'
@@ -19,7 +17,7 @@ function removeGenericCounterparty(amount, address) {
_.omit(amount, 'counterparty') : amount _.omit(amount, 'counterparty') : amount
} }
function parsePayment(tx: Object): Object { function parsePayment(tx: any): Object {
assert(tx.TransactionType === 'Payment') assert(tx.TransactionType === 'Payment')
const source = { const source = {

View File

@@ -1,20 +1,18 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import assert from 'assert' import * as assert from 'assert'
import {constants} from '../../common' import {constants} from '../../common'
const AccountFlags = constants.AccountFlags const AccountFlags = constants.AccountFlags
import parseFields from './fields' import parseFields from './fields'
function getAccountRootModifiedNode(tx: Object) { function getAccountRootModifiedNode(tx: any) {
const modifiedNodes = tx.meta.AffectedNodes.filter(node => const modifiedNodes = tx.meta.AffectedNodes.filter(node =>
node.ModifiedNode.LedgerEntryType === 'AccountRoot') node.ModifiedNode.LedgerEntryType === 'AccountRoot')
assert(modifiedNodes.length === 1) assert(modifiedNodes.length === 1)
return modifiedNodes[0].ModifiedNode return modifiedNodes[0].ModifiedNode
} }
function parseFlags(tx: Object) { function parseFlags(tx: any): any {
const settings = {} const settings: any = {}
if (tx.TransactionType !== 'AccountSet') { if (tx.TransactionType !== 'AccountSet') {
return settings return settings
} }
@@ -51,7 +49,7 @@ function parseFlags(tx: Object) {
return settings return settings
} }
function parseSettings(tx: Object) { function parseSettings(tx: any) {
const txType = tx.TransactionType const txType = tx.TransactionType
assert(txType === 'AccountSet' || txType === 'SetRegularKey' || assert(txType === 'AccountSet' || txType === 'SetRegularKey' ||
txType === 'SignerListSet') txType === 'SignerListSet')

View File

@@ -1,6 +1,4 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseOutcome} from './utils' import {parseOutcome} from './utils'
import {removeUndefined} from '../../common' import {removeUndefined} from '../../common'
import parsePayment from './payment' import parsePayment from './payment'
@@ -38,7 +36,7 @@ function parseTransactionType(type) {
return mapping[type] || null return mapping[type] || null
} }
function parseTransaction(tx: Object): Object { function parseTransaction(tx: any): any {
const type = parseTransactionType(tx.TransactionType) const type = parseTransactionType(tx.TransactionType)
const mapping = { const mapping = {
'payment': parsePayment, 'payment': parsePayment,
@@ -55,7 +53,7 @@ function parseTransaction(tx: Object): Object {
'feeUpdate': parseFeeUpdate, 'feeUpdate': parseFeeUpdate,
'amendment': parseAmendment 'amendment': parseAmendment
} }
const parser: Function = (mapping: Object)[type] const parser: Function = mapping[type]
assert(parser !== undefined, 'Unrecognized transaction type') assert(parser !== undefined, 'Unrecognized transaction type')
const specification = parser(tx) const specification = parser(tx)
const outcome = parseOutcome(tx) const outcome = parseOutcome(tx)

View File

@@ -1,6 +1,4 @@
/* @flow */ import * as assert from 'assert'
import assert from 'assert'
import {parseQuality} from './utils' import {parseQuality} from './utils'
import {txFlags, removeUndefined} from '../../common' import {txFlags, removeUndefined} from '../../common'
const flags = txFlags.TrustSet const flags = txFlags.TrustSet
@@ -15,7 +13,7 @@ function parseFlag(flagsValue, trueValue, falseValue) {
return undefined return undefined
} }
function parseTrustline(tx: Object): Object { function parseTrustline(tx: any): Object {
assert(tx.TransactionType === 'TrustSet') assert(tx.TransactionType === 'TrustSet')
return removeUndefined({ return removeUndefined({

View File

@@ -1,12 +1,10 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import transactionParser from 'ripple-lib-transactionparser' import transactionParser = require('ripple-lib-transactionparser')
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import * as common from '../../common' import * as common from '../../common'
import parseAmount from './amount' import parseAmount from './amount'
import type {Amount} from '../../common/types' import {Amount, Memo} from '../../common/types'
function adjustQualityForXRP( function adjustQualityForXRP(
quality: string, takerGetsCurrency: string, takerPaysCurrency: string quality: string, takerGetsCurrency: string, takerPaysCurrency: string
@@ -20,15 +18,18 @@ function adjustQualityForXRP(
(new BigNumber(quality)).shift(shift).toString() (new BigNumber(quality)).shift(shift).toString()
} }
function parseQuality(quality: ?number) { function parseQuality(quality?: number|null): number|undefined {
if (typeof quality === 'number') { if (typeof quality !== 'number') {
return (new BigNumber(quality)).shift(-9).toNumber() return undefined
} }
return undefined return (new BigNumber(quality)).shift(-9).toNumber()
} }
function parseTimestamp(rippleTime: number): string | void { function parseTimestamp(rippleTime?: number|null): string|undefined {
return rippleTime ? common.rippleTimeToISO8601(rippleTime) : undefined if (typeof rippleTime !== 'number') {
return undefined
}
return common.rippleTimeToISO8601(rippleTime)
} }
function removeEmptyCounterparty(amount) { function removeEmptyCounterparty(amount) {
@@ -51,11 +52,11 @@ function removeEmptyCounterpartyInOrderbookChanges(orderbookChanges) {
}) })
} }
function isPartialPayment(tx: Object) { function isPartialPayment(tx: any) {
return (tx.Flags & common.txFlags.Payment.PartialPayment) !== 0 return (tx.Flags & common.txFlags.Payment.PartialPayment) !== 0
} }
function parseDeliveredAmount(tx: Object): Amount | void { function parseDeliveredAmount(tx: any): Amount | void {
if (tx.TransactionType !== 'Payment' || if (tx.TransactionType !== 'Payment' ||
tx.meta.TransactionResult !== 'tesSUCCESS') { tx.meta.TransactionResult !== 'tesSUCCESS') {
@@ -95,7 +96,7 @@ function parseDeliveredAmount(tx: Object): Amount | void {
return undefined return undefined
} }
function parseOutcome(tx: Object): ?Object { function parseOutcome(tx: any): any|undefined {
const metadata = tx.meta || tx.metaData const metadata = tx.meta || tx.metaData
if (!metadata) { if (!metadata) {
return undefined return undefined
@@ -117,11 +118,11 @@ function parseOutcome(tx: Object): ?Object {
}) })
} }
function hexToString(hex: string): ?string { function hexToString(hex: string): string|undefined {
return hex ? new Buffer(hex, 'hex').toString('utf-8') : undefined return hex ? new Buffer(hex, 'hex').toString('utf-8') : undefined
} }
function parseMemos(tx: Object): ?Array<Object> { function parseMemos(tx: any): Array<Memo>|undefined {
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) { if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
return undefined return undefined
} }

View File

@@ -1,11 +1,9 @@
/* @flow */
import {Amount, LaxLaxAmount, RippledAmount, Adjustment, MaxAdjustment,
import type {Amount, LaxLaxAmount, RippledAmount, Adjustment, MaxAdjustment,
MinAdjustment} from '../common/types' MinAdjustment} from '../common/types'
type Path = { export type Path = {
source: Adjustment | MaxAdjustment, source: Adjustment | MaxAdjustment,
destination: Adjustment | MinAdjustment, destination: Adjustment | MinAdjustment,
paths: string paths: string
@@ -30,7 +28,7 @@ export type PathFindRequest = {
source_account: string, source_account: string,
destination_amount: RippledAmount, destination_amount: RippledAmount,
destination_account: string, destination_account: string,
source_currencies?: Array<string>, source_currencies?: {currency: string, issuer?: string}[],
send_max?: RippledAmount send_max?: RippledAmount
} }
@@ -49,7 +47,7 @@ export type RippledPathsResponse = {
destination_account: string, destination_account: string,
destination_amount: RippledAmount, destination_amount: RippledAmount,
destination_currencies?: Array<string>, destination_currencies?: Array<string>,
source_account?: string, source_account: string,
source_currencies?: Array<{currency: string}>, source_currencies?: Array<{currency: string}>,
full_reply?: boolean full_reply?: boolean
} }

View File

@@ -1,13 +1,11 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import {getXRPBalance} from './utils' import {getXRPBalance, renameCounterpartyToIssuer} from './utils'
import {validate, toRippledAmount, errors} from '../common' import {validate, toRippledAmount, errors} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import parsePathfind from './parse/pathfind' import parsePathfind from './parse/pathfind'
import type {RippledAmount} from '../common/types' import {RippledAmount, Amount} from '../common/types'
import type { import {
GetPaths, PathFind, RippledPathsResponse, PathFindRequest GetPaths, PathFind, RippledPathsResponse, PathFindRequest
} from './pathfind-types' } from './pathfind-types'
const NotFoundError = errors.NotFoundError const NotFoundError = errors.NotFoundError
@@ -24,7 +22,10 @@ function addParams(request: PathFindRequest, result: RippledPathsResponse
function requestPathFind(connection: Connection, pathfind: PathFind function requestPathFind(connection: Connection, pathfind: PathFind
): Promise<RippledPathsResponse> { ): Promise<RippledPathsResponse> {
const destinationAmount = _.assign({value: -1}, pathfind.destination.amount) const destinationAmount: Amount = _.assign(
{value: '-1'},
pathfind.destination.amount
)
const request: PathFindRequest = { const request: PathFindRequest = {
command: 'ripple_path_find', command: 'ripple_path_find',
source_account: pathfind.source.address, source_account: pathfind.source.address,
@@ -41,8 +42,8 @@ function requestPathFind(connection: Connection, pathfind: PathFind
request.destination_amount.issuer = request.destination_account request.destination_amount.issuer = request.destination_account
} }
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) { if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
request.source_currencies = pathfind.source.currencies.map(amount => request.source_currencies = pathfind.source.currencies.map(
_.omit(toRippledAmount(amount), 'value')) amount => renameCounterpartyToIssuer(amount))
} }
if (pathfind.source.amount) { if (pathfind.source.amount) {
if (pathfind.destination.amount.value !== undefined) { if (pathfind.destination.amount.value !== undefined) {
@@ -50,7 +51,7 @@ function requestPathFind(connection: Connection, pathfind: PathFind
+ ' and destination.amount.value in getPaths') + ' and destination.amount.value in getPaths')
} }
request.send_max = toRippledAmount(pathfind.source.amount) request.send_max = toRippledAmount(pathfind.source.amount)
if (request.send_max.currency && !request.send_max.issuer) { if (typeof request.send_max !== 'string' && !request.send_max.issuer) {
request.send_max.issuer = pathfind.source.address request.send_max.issuer = pathfind.source.address
} }
} }
@@ -62,6 +63,7 @@ function addDirectXrpPath(paths: RippledPathsResponse, xrpBalance: string
): RippledPathsResponse { ): RippledPathsResponse {
// Add XRP "path" only if the source acct has enough XRP to make the payment // Add XRP "path" only if the source acct has enough XRP to make the payment
const destinationAmount = paths.destination_amount const destinationAmount = paths.destination_amount
// @ts-ignore: destinationAmount can be a currency amount object! Fix!
if ((new BigNumber(xrpBalance)).greaterThanOrEqualTo(destinationAmount)) { if ((new BigNumber(xrpBalance)).greaterThanOrEqualTo(destinationAmount)) {
paths.alternatives.unshift({ paths.alternatives.unshift({
paths_computed: [], paths_computed: [],
@@ -93,11 +95,13 @@ function filterSourceFundsLowPaths(pathfind: PathFind,
): RippledPathsResponse { ): RippledPathsResponse {
if (pathfind.source.amount && if (pathfind.source.amount &&
pathfind.destination.amount.value === undefined && paths.alternatives) { pathfind.destination.amount.value === undefined && paths.alternatives) {
paths.alternatives = _.filter(paths.alternatives, alt => { paths.alternatives = _.filter(paths.alternatives, alt =>
return alt.source_amount && !!alt.source_amount &&
pathfind.source.amount && !!pathfind.source.amount &&
// TODO: Returns false when alt.source_amount is a string. Fix?
typeof alt.source_amount !== 'string' &&
new BigNumber(alt.source_amount.value).eq(pathfind.source.amount.value) new BigNumber(alt.source_amount.value).eq(pathfind.source.amount.value)
}) )
} }
return paths return paths
} }

View File

@@ -1,35 +1,9 @@
/* @flow */ import parsePaymentChannel, {
LedgerEntryResponse, PaymentChannel
import parsePaymentChannel from './parse/payment-channel' } from './parse/payment-channel'
import {validate, errors} from '../common' import {validate, errors} from '../common'
const NotFoundError = errors.NotFoundError const NotFoundError = errors.NotFoundError
type PaymentChannel = {
Sequence: number,
Account: string,
Balance: string,
PublicKey: number,
Destination: string,
SettleDelay: number,
Expiration?: number,
CancelAfter?: number,
SourceTag?: number,
DestinationTag?: number,
OwnerNode: string,
LedgerEntryType: string,
PreviousTxnID: string,
PreviousTxnLgrSeq: number,
index: string
}
type LedgerEntryResponse = {
node: PaymentChannel,
ledger_current_index?: number,
ledger_hash?: string,
ledger_index: number,
validated: boolean
}
function formatResponse(response: LedgerEntryResponse) { function formatResponse(response: LedgerEntryResponse) {
if (response.node !== undefined && if (response.node !== undefined &&
response.node.LedgerEntryType === 'PayChannel') { response.node.LedgerEntryType === 'PayChannel') {

View File

@@ -1,5 +1,3 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import parseFields from './parse/fields' import parseFields from './parse/fields'
import {validate, constants} from '../common' import {validate, constants} from '../common'
@@ -19,10 +17,10 @@ type GetSettings = {
noFreeze?: boolean, noFreeze?: boolean,
globalFreeze?: boolean, globalFreeze?: boolean,
defaultRipple?: boolean, defaultRipple?: boolean,
emailHash?: ?string, emailHash?: string|null,
messageKey?: string, messageKey?: string,
domain?: string, domain?: string,
transferRate?: ?number, transferRate?: number|null,
regularKey?: string regularKey?: string
} }

View File

@@ -1,7 +1,5 @@
/* @flow */
import {Amount, Memo} from '../common/types'
import type {Amount, Memo} from '../common/types'
type Outcome = { type Outcome = {
result: string, result: string,
@@ -87,7 +85,10 @@ export type Order = {
totalPrice: Amount, totalPrice: Amount,
immediateOrCancel?: boolean, immediateOrCancel?: boolean,
fillOrKill?: boolean, fillOrKill?: boolean,
passive?: boolean passive?: boolean,
expirationTime?: string,
orderToReplace?: number,
memos?: Memo[]
} }
type OrderTransaction = { type OrderTransaction = {
@@ -133,3 +134,10 @@ export type TransactionOptions = {
export type TransactionType = PaymentTransaction | OrderTransaction | export type TransactionType = PaymentTransaction | OrderTransaction |
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction
export type TransactionResponse = TransactionType & {
hash: string,
ledger_index: number,
meta: any,
validated?: boolean
}

View File

@@ -1,13 +1,13 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import parseTransaction from './parse/transaction' import parseTransaction from './parse/transaction'
import {validate, errors} from '../common' import {validate, errors} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import type {TransactionType, TransactionOptions} from './transaction-types' import {
TransactionType, TransactionResponse, TransactionOptions
} from './transaction-types'
function attachTransactionDate(connection: Connection, tx: Object function attachTransactionDate(connection: Connection, tx: any
): Promise<TransactionType> { ): Promise<TransactionType> {
if (tx.date) { if (tx.date) {
return Promise.resolve(tx) return Promise.resolve(tx)
@@ -40,7 +40,7 @@ function attachTransactionDate(connection: Connection, tx: Object
}) })
} }
function isTransactionInRange(tx: Object, options: TransactionOptions) { function isTransactionInRange(tx: any, options: TransactionOptions) {
return (!options.minLedgerVersion return (!options.minLedgerVersion
|| tx.ledger_index >= options.minLedgerVersion) || tx.ledger_index >= options.minLedgerVersion)
&& (!options.maxLedgerVersion && (!options.maxLedgerVersion
@@ -70,10 +70,10 @@ function convertError(connection: Connection, options: TransactionOptions,
return Promise.resolve(_error) return Promise.resolve(_error)
} }
function formatResponse(options: TransactionOptions, tx: TransactionType function formatResponse(options: TransactionOptions, tx: TransactionResponse
): TransactionType { ): TransactionType {
if (tx.validated !== true || !isTransactionInRange(tx, options)) { if (tx.validated !== true || !isTransactionInRange(tx, options)) {
throw new errors.NotFoundError('Transaction not found') throw new errors.NotFoundError('Transaction not found')
} }
return parseTransaction(tx) return parseTransaction(tx)
} }
@@ -89,7 +89,7 @@ function getTransaction(id: string, options: TransactionOptions = {}
} }
return utils.ensureLedgerVersion.call(this, options).then(_options => { return utils.ensureLedgerVersion.call(this, options).then(_options => {
return this.connection.request(request).then(tx => return this.connection.request(request).then((tx: TransactionResponse) =>
attachTransactionDate(this.connection, tx) attachTransactionDate(this.connection, tx)
).then(_.partial(formatResponse, _options)) ).then(_.partial(formatResponse, _options))
.catch(error => { .catch(error => {

View File

@@ -1,14 +1,12 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import binary from 'ripple-binary-codec' import binary = require('ripple-binary-codec')
import {computeTransactionHash} from 'ripple-hashes' const {computeTransactionHash} = require('ripple-hashes')
import * as utils from './utils' import * as utils from './utils'
import parseTransaction from './parse/transaction' import parseTransaction from './parse/transaction'
import getTransaction from './transaction' import getTransaction from './transaction'
import {validate, errors} from '../common' import {validate, errors} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import type {TransactionType} from './transaction-types' import {TransactionType} from './transaction-types'
type TransactionsOptions = { type TransactionsOptions = {
@@ -46,14 +44,15 @@ function parseAccountTxTransaction(tx) {
} }
function counterpartyFilter(filters, tx: TransactionType) { function counterpartyFilter(filters, tx: TransactionType) {
if (tx.address === filters.counterparty || ( if (tx.address === filters.counterparty) {
tx.specification && (
(tx.specification.destination &&
tx.specification.destination.address === filters.counterparty) ||
(tx.specification.counterparty === filters.counterparty)
))) {
return true return true
} }
const specification: any = tx.specification
if (specification && ((specification.destination &&
specification.destination.address === filters.counterparty) ||
(specification.counterparty === filters.counterparty))) {
return true
}
return false return false
} }
@@ -127,9 +126,9 @@ function checkForLedgerGaps(connection: Connection,
// the range of ledgers spanned by those transactions // the range of ledgers spanned by those transactions
if (options.limit && transactions.length === options.limit) { if (options.limit && transactions.length === options.limit) {
if (options.earliestFirst) { if (options.earliestFirst) {
maxLedgerVersion = _.last(transactions).outcome.ledgerVersion maxLedgerVersion = _.last(transactions)!.outcome.ledgerVersion
} else { } else {
minLedgerVersion = _.last(transactions).outcome.ledgerVersion minLedgerVersion = _.last(transactions)!.outcome.ledgerVersion
} }
} }
@@ -169,8 +168,8 @@ function getTransactions(address: string, options: TransactionsOptions = {}
const ledgerVersion = tx.outcome.ledgerVersion const ledgerVersion = tx.outcome.ledgerVersion
const bound = options.earliestFirst ? const bound = options.earliestFirst ?
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion} {minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion}
const newOptions = _.assign({}, defaults, options, {startTx: tx}, bound) const startOptions = _.assign({}, defaults, options, {startTx: tx}, bound)
return getTransactionsInternal(this.connection, address, newOptions) return getTransactionsInternal(this.connection, address, startOptions)
}) })
} }
const newOptions = _.assign({}, defaults, options) const newOptions = _.assign({}, defaults, options)

View File

@@ -1,5 +1,4 @@
/* @flow */ import {Memo} from '../common/types'
export type TrustLineSpecification = { export type TrustLineSpecification = {
currency: string, currency: string,
@@ -9,7 +8,8 @@ export type TrustLineSpecification = {
qualityOut?: number, qualityOut?: number,
ripplingDisabled?: boolean, ripplingDisabled?: boolean,
authorized?: boolean, authorized?: boolean,
frozen?: boolean frozen?: boolean,
memos?: Memo[]
} }
export type Trustline = { export type Trustline = {

View File

@@ -1,20 +1,22 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import {validate} from '../common' import {validate} from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import parseAccountTrustline from './parse/account-trustline' import parseAccountTrustline from './parse/account-trustline'
import type {TrustlinesOptions, Trustline} from './trustlines-types' import {TrustlinesOptions, Trustline} from './trustlines-types'
type GetTrustlinesResponse = Array<Trustline> type GetTrustlinesResponse = Array<Trustline>
interface GetAccountLinesResponse {
marker?: any,
results: Trustline[]
}
function currencyFilter(currency: string, trustline: Trustline) { function currencyFilter(currency: string, trustline: Trustline) {
return currency === null || trustline.specification.currency === currency return currency === null || trustline.specification.currency === currency
} }
function formatResponse(options: TrustlinesOptions, data) { function formatResponse(options: TrustlinesOptions, data: any) {
return { return {
marker: data.marker, marker: data.marker,
results: data.lines.map(parseAccountTrustline) results: data.lines.map(parseAccountTrustline)
@@ -25,7 +27,7 @@ function formatResponse(options: TrustlinesOptions, data) {
function getAccountLines(connection: Connection, address: string, function getAccountLines(connection: Connection, address: string,
ledgerVersion: number, options: TrustlinesOptions, marker: string, ledgerVersion: number, options: TrustlinesOptions, marker: string,
limit: number limit: number
): Promise<GetTrustlinesResponse> { ): Promise<GetAccountLinesResponse> {
const request = { const request = {
command: 'account_lines', command: 'account_lines',
account: address, account: address,

View File

@@ -1,7 +1,5 @@
/* @flow */
import {Amount} from '../common/types'
import type {Amount} from '../common/types'
export type OrdersOptions = { export type OrdersOptions = {
limit?: number, limit?: number,
@@ -30,16 +28,17 @@ export type Order = {
} }
export type GetLedger = { export type GetLedger = {
accepted: boolean, // TODO: properties in type don't match response object. Fix!
closed: boolean, // accepted: boolean,
// closed: boolean,
stateHash: string, stateHash: string,
closeTime: number, closeTime: string,
closeTimeResolution: number, closeTimeResolution: number,
closeFlags: number, closeFlags: number,
ledgerHash: string, ledgerHash: string,
ledgerVersion: number, ledgerVersion: number,
parentLedgerHash: string, parentLedgerHash: string,
parentCloseTime: number, parentCloseTime: string,
totalDrops: string, totalDrops: string,
transactionHash: string, transactionHash: string,
transactions?: Array<Object>, transactions?: Array<Object>,

View File

@@ -1,18 +1,16 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import assert from 'assert' import * as assert from 'assert'
import * as common from '../common' import * as common from '../common'
import type {Connection} from '../common' import {Connection} from '../common'
import type {TransactionType} from './transaction-types' import {TransactionType} from './transaction-types'
import type {Issue} from '../common/types' import {Issue} from '../common/types'
type RecursiveData = { type RecursiveData = {
marker: string, marker: string,
results: Array<any> results: Array<any>
} }
type Getter = (marker: ?string, limit: number) => Promise<RecursiveData> type Getter = (marker?: string, limit?: number) => Promise<RecursiveData>
function clamp(value: number, min: number, max: number): number { function clamp(value: number, min: number, max: number): number {
assert(min <= max, 'Illegal clamp bounds') assert(min <= max, 'Illegal clamp bounds')
@@ -32,7 +30,8 @@ function getXRPBalance(connection: Connection, address: string,
} }
// If the marker is omitted from a response, you have reached the end // If the marker is omitted from a response, you have reached the end
function getRecursiveRecur(getter: Getter, marker?: string, limit: number function getRecursiveRecur(
getter: Getter, marker: string | undefined, limit: number
): Promise<Array<any>> { ): Promise<Array<any>> {
return getter(marker, limit).then(data => { return getter(marker, limit).then(data => {
const remaining = limit - data.results.length const remaining = limit - data.results.length
@@ -49,15 +48,15 @@ function getRecursive(getter: Getter, limit?: number): Promise<Array<any>> {
return getRecursiveRecur(getter, undefined, limit || Infinity) return getRecursiveRecur(getter, undefined, limit || Infinity)
} }
function renameCounterpartyToIssuer(amount?: Issue): ?{issuer?: string} { function renameCounterpartyToIssuer<T>(
if (amount === undefined) { obj: T & {counterparty?: string, issuer?: string}
return undefined ): (T & {issuer?: string}) {
} const issuer = (obj.counterparty !== undefined) ?
const issuer = amount.counterparty === undefined ? obj.counterparty :
(amount.issuer !== undefined ? amount.issuer : undefined) : ((obj.issuer !== undefined) ? obj.issuer : undefined)
amount.counterparty const withIssuer = Object.assign({}, obj, {issuer})
const withIssuer = _.assign({}, amount, {issuer: issuer}) delete withIssuer.counterparty
return _.omit(withIssuer, 'counterparty') return withIssuer
} }
type RequestBookOffersArgs = {taker_gets: Issue, taker_pays: Issue} type RequestBookOffersArgs = {taker_gets: Issue, taker_pays: Issue}
@@ -65,7 +64,7 @@ type RequestBookOffersArgs = {taker_gets: Issue, taker_pays: Issue}
function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) { function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
const taker_gets = renameCounterpartyToIssuer(order.taker_gets) const taker_gets = renameCounterpartyToIssuer(order.taker_gets)
const taker_pays = renameCounterpartyToIssuer(order.taker_pays) const taker_pays = renameCounterpartyToIssuer(order.taker_pays)
const changes = {taker_gets: taker_gets, taker_pays: taker_pays} const changes = {taker_gets, taker_pays}
return _.assign({}, order, _.omitBy(changes, _.isUndefined)) return _.assign({}, order, _.omitBy(changes, _.isUndefined))
} }
@@ -78,12 +77,7 @@ function signum(num) {
* If two transactions took place in the same ledger, sort * If two transactions took place in the same ledger, sort
* them based on TransactionIndex * them based on TransactionIndex
* See: https://ripple.com/build/transactions/ * See: https://ripple.com/build/transactions/
*
* @param {Object} first
* @param {Object} second
* @returns {Number} [-1, 0, 1]
*/ */
function compareTransactions(first: TransactionType, second: TransactionType function compareTransactions(first: TransactionType, second: TransactionType
): number { ): number {
if (!first.outcome || !second.outcome) { if (!first.outcome || !second.outcome) {
@@ -104,13 +98,13 @@ function hasCompleteLedgerRange(connection: Connection,
} }
function isPendingLedgerVersion(connection: Connection, function isPendingLedgerVersion(connection: Connection,
maxLedgerVersion: ?number maxLedgerVersion?: number
): Promise<boolean> { ): Promise<boolean> {
return connection.getLedgerVersion().then(ledgerVersion => return connection.getLedgerVersion().then(ledgerVersion =>
ledgerVersion < (maxLedgerVersion || 0)) ledgerVersion < (maxLedgerVersion || 0))
} }
function ensureLedgerVersion(options: Object function ensureLedgerVersion(options: any
): Promise<Object> { ): Promise<Object> {
if (Boolean(options) && options.ledgerVersion !== undefined && if (Boolean(options) && options.ledgerVersion !== undefined &&
options.ledgerVersion !== null options.ledgerVersion !== null
@@ -125,6 +119,7 @@ export {
getXRPBalance, getXRPBalance,
ensureLedgerVersion, ensureLedgerVersion,
compareTransactions, compareTransactions,
renameCounterpartyToIssuer,
renameCounterpartyToIssuerInOrder, renameCounterpartyToIssuerInOrder,
getRecursive, getRecursive,
hasCompleteLedgerRange, hasCompleteLedgerRange,

View File

@@ -1,6 +1,4 @@
/* @flow */ import keypairs = require('ripple-keypairs')
import keypairs from 'ripple-keypairs'
import * as common from '../common' import * as common from '../common'
const {errors, validate} = common const {errors, validate} = common

View File

@@ -1,10 +1,8 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import hashes = require('ripple-hashes')
import * as common from '../common' import * as common from '../common'
import hashes from 'ripple-hashes'
function convertLedgerHeader(header) { function convertLedgerHeader(header): any {
return { return {
account_hash: header.stateHash, account_hash: header.stateHash,
close_time: common.iso8601ToRippleTime(header.closeTime), close_time: common.iso8601ToRippleTime(header.closeTime),
@@ -31,7 +29,7 @@ function computeTransactionHash(ledger, version) {
if (ledger.rawTransactions === undefined) { if (ledger.rawTransactions === undefined) {
return ledger.transactionHash return ledger.transactionHash
} }
const transactions = JSON.parse(ledger.rawTransactions) const transactions: any[] = JSON.parse(ledger.rawTransactions)
const txs = _.map(transactions, tx => { const txs = _.map(transactions, tx => {
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {}) const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {})
const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'), const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'),
@@ -62,7 +60,7 @@ function computeStateHash(ledger, version) {
const sLCF_SHAMapV2 = 0x02 const sLCF_SHAMapV2 = 0x02
function computeLedgerHash(ledger: Object): string { function computeLedgerHash(ledger: any): string {
const version = ((ledger.closeFlags & sLCF_SHAMapV2) === 0) ? 1 : 2 const version = ((ledger.closeFlags & sLCF_SHAMapV2) === 0) ? 1 : 2
const subhashes = { const subhashes = {
transactionHash: computeTransactionHash(ledger, version), transactionHash: computeTransactionHash(ledger, version),

View File

@@ -1,8 +1,6 @@
/* @flow */
import * as common from '../common' import * as common from '../common'
import keypairs from 'ripple-keypairs' import keypairs = require('ripple-keypairs')
import binary from 'ripple-binary-codec' import binary = require('ripple-binary-codec')
const {validate, xrpToDrops} = common const {validate, xrpToDrops} = common
function signPaymentChannelClaim(channel: string, amount: string, function signPaymentChannelClaim(channel: string, amount: string,

View File

@@ -1,9 +1,6 @@
/* @flow */ import keypairs = require('ripple-keypairs')
import binary = require('ripple-binary-codec')
import * as common from '../common' import {validate, xrpToDrops} from '../common'
import keypairs from 'ripple-keypairs'
import binary from 'ripple-binary-codec'
const {validate, xrpToDrops} = common
function verifyPaymentChannelClaim(channel: string, amount: string, function verifyPaymentChannelClaim(channel: string, amount: string,
signature: string, publicKey: string signature: string, publicKey: string

View File

@@ -1,7 +1,5 @@
/* @flow */
import * as common from '../common' import * as common from '../common'
import type {GetServerInfoResponse} from '../common/serverinfo' import {GetServerInfoResponse} from '../common/serverinfo'
function isConnected(): boolean { function isConnected(): boolean {
return this.connection.isConnected() return this.connection.isConnected()
@@ -23,12 +21,12 @@ function getServerInfo(): Promise<GetServerInfoResponse> {
return common.serverInfo.getServerInfo(this.connection) return common.serverInfo.getServerInfo(this.connection)
} }
function getFee(): Promise<number> { function getFee(): Promise<string> {
const cushion = this._feeCushion || 1.2 const cushion = this._feeCushion || 1.2
return common.serverInfo.getFee(this.connection, cushion) return common.serverInfo.getFee(this.connection, cushion)
} }
function formatLedgerClose(ledgerClose: Object): Object { function formatLedgerClose(ledgerClose: any): Object {
return { return {
baseFeeXRP: common.dropsToXrp(ledgerClose.fee_base), baseFeeXRP: common.dropsToXrp(ledgerClose.fee_base),
ledgerHash: ledgerClose.ledger_hash, ledgerHash: ledgerClose.ledger_hash,

View File

@@ -1,7 +1,5 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import binary from 'ripple-binary-codec' import binary = require('ripple-binary-codec')
import * as utils from './utils' import * as utils from './utils'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import {decodeAddress} from 'ripple-address-codec' import {decodeAddress} from 'ripple-address-codec'
@@ -21,7 +19,9 @@ function compareSigners(a, b) {
function combine(signedTransactions: Array<string>): Object { function combine(signedTransactions: Array<string>): Object {
validate.combine({signedTransactions}) validate.combine({signedTransactions})
const txs = _.map(signedTransactions, binary.decode) // TODO: signedTransactions is an array of strings in the documentation, but
// tests and this code handle it as an array of objects. Fix!
const txs: any[] = _.map(signedTransactions, binary.decode)
const tx = _.omit(txs[0], 'Signers') const tx = _.omit(txs[0], 'Signers')
if (!_.every(txs, _tx => _.isEqual(tx, _.omit(_tx, 'Signers')))) { if (!_.every(txs, _tx => _.isEqual(tx, _.omit(_tx, 'Signers')))) {
throw new utils.common.errors.ValidationError( throw new utils.common.errors.ValidationError(

View File

@@ -1,10 +1,8 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
const validate = utils.common.validate const validate = utils.common.validate
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import type {Memo} from '../common/types' import {Memo} from '../common/types'
type EscrowCancellation = { type EscrowCancellation = {
owner: string, owner: string,
@@ -15,7 +13,7 @@ type EscrowCancellation = {
function createEscrowCancellationTransaction(account: string, function createEscrowCancellationTransaction(account: string,
payment: EscrowCancellation payment: EscrowCancellation
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
TransactionType: 'EscrowCancel', TransactionType: 'EscrowCancel',
Account: account, Account: account,
Owner: payment.owner, Owner: payment.owner,

View File

@@ -1,11 +1,9 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import {validate, iso8601ToRippleTime, xrpToDrops} from '../common' import {validate, iso8601ToRippleTime, xrpToDrops} from '../common'
const ValidationError = utils.common.errors.ValidationError const ValidationError = utils.common.errors.ValidationError
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import type {Memo} from '../common/types' import {Memo} from '../common/types'
type EscrowCreation = { type EscrowCreation = {
amount: string, amount: string,
@@ -21,7 +19,7 @@ type EscrowCreation = {
function createEscrowCreationTransaction(account: string, function createEscrowCreationTransaction(account: string,
payment: EscrowCreation payment: EscrowCreation
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
TransactionType: 'EscrowCreate', TransactionType: 'EscrowCreate',
Account: account, Account: account,
Destination: payment.destination, Destination: payment.destination,

View File

@@ -1,11 +1,9 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
const validate = utils.common.validate const validate = utils.common.validate
const ValidationError = utils.common.errors.ValidationError const ValidationError = utils.common.errors.ValidationError
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import type {Memo} from '../common/types' import {Memo} from '../common/types'
type EscrowExecution = { type EscrowExecution = {
owner: string, owner: string,
@@ -18,7 +16,7 @@ type EscrowExecution = {
function createEscrowExecutionTransaction(account: string, function createEscrowExecutionTransaction(account: string,
payment: EscrowExecution payment: EscrowExecution
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
TransactionType: 'EscrowFinish', TransactionType: 'EscrowFinish',
Account: account, Account: account,
Owner: payment.owner, Owner: payment.owner,

View File

@@ -1,11 +1,9 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
const offerFlags = utils.common.txFlags.OfferCreate const offerFlags = utils.common.txFlags.OfferCreate
import {validate, iso8601ToRippleTime} from '../common' import {validate, iso8601ToRippleTime} from '../common'
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import type {Order} from '../ledger/transaction-types' import {Order} from '../ledger/transaction-types'
function createOrderTransaction(account: string, order: Order): Object { function createOrderTransaction(account: string, order: Order): Object {
const takerPays = utils.common.toRippledAmount(order.direction === 'buy' ? const takerPays = utils.common.toRippledAmount(order.direction === 'buy' ?
@@ -13,7 +11,7 @@ function createOrderTransaction(account: string, order: Order): Object {
const takerGets = utils.common.toRippledAmount(order.direction === 'buy' ? const takerGets = utils.common.toRippledAmount(order.direction === 'buy' ?
order.totalPrice : order.quantity) order.totalPrice : order.quantity)
const txJSON: Object = { const txJSON: any = {
TransactionType: 'OfferCreate', TransactionType: 'OfferCreate',
Account: account, Account: account,
TakerGets: takerGets, TakerGets: takerGets,

View File

@@ -1,14 +1,12 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
const validate = utils.common.validate const validate = utils.common.validate
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
function createOrderCancellationTransaction(account: string, function createOrderCancellationTransaction(account: string,
orderCancellation: Object orderCancellation: any
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
TransactionType: 'OfferCancel', TransactionType: 'OfferCancel',
Account: account, Account: account,
OfferSequence: orderCancellation.orderSequence OfferSequence: orderCancellation.orderSequence

View File

@@ -1,10 +1,8 @@
/* @flow */
import * as utils from './utils' import * as utils from './utils'
const ValidationError = utils.common.errors.ValidationError const ValidationError = utils.common.errors.ValidationError
const claimFlags = utils.common.txFlags.PaymentChannelClaim const claimFlags = utils.common.txFlags.PaymentChannelClaim
import {validate, xrpToDrops} from '../common' import {validate, xrpToDrops} from '../common'
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
type PaymentChannelClaim = { type PaymentChannelClaim = {
channel: string, channel: string,
@@ -19,7 +17,7 @@ type PaymentChannelClaim = {
function createPaymentChannelClaimTransaction(account: string, function createPaymentChannelClaimTransaction(account: string,
claim: PaymentChannelClaim claim: PaymentChannelClaim
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
Account: account, Account: account,
TransactionType: 'PaymentChannelClaim', TransactionType: 'PaymentChannelClaim',
Channel: claim.channel, Channel: claim.channel,

View File

@@ -1,8 +1,6 @@
/* @flow */
import * as utils from './utils' import * as utils from './utils'
import {validate, iso8601ToRippleTime, xrpToDrops} from '../common' import {validate, iso8601ToRippleTime, xrpToDrops} from '../common'
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
type PaymentChannelCreate = { type PaymentChannelCreate = {
amount: string, amount: string,
@@ -17,7 +15,7 @@ type PaymentChannelCreate = {
function createPaymentChannelCreateTransaction(account: string, function createPaymentChannelCreateTransaction(account: string,
paymentChannel: PaymentChannelCreate paymentChannel: PaymentChannelCreate
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
Account: account, Account: account,
TransactionType: 'PaymentChannelCreate', TransactionType: 'PaymentChannelCreate',
Amount: xrpToDrops(paymentChannel.amount), Amount: xrpToDrops(paymentChannel.amount),

View File

@@ -1,8 +1,6 @@
/* @flow */
import * as utils from './utils' import * as utils from './utils'
import {validate, iso8601ToRippleTime, xrpToDrops} from '../common' import {validate, iso8601ToRippleTime, xrpToDrops} from '../common'
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
type PaymentChannelFund = { type PaymentChannelFund = {
channel: string, channel: string,
@@ -13,7 +11,7 @@ type PaymentChannelFund = {
function createPaymentChannelFundTransaction(account: string, function createPaymentChannelFundTransaction(account: string,
fund: PaymentChannelFund fund: PaymentChannelFund
): Object { ): Object {
const txJSON: Object = { const txJSON: any = {
Account: account, Account: account,
TransactionType: 'PaymentChannelFund', TransactionType: 'PaymentChannelFund',
Channel: fund.channel, Channel: fund.channel,

View File

@@ -1,19 +1,17 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
const validate = utils.common.validate const validate = utils.common.validate
const toRippledAmount = utils.common.toRippledAmount const toRippledAmount = utils.common.toRippledAmount
const paymentFlags = utils.common.txFlags.Payment const paymentFlags = utils.common.txFlags.Payment
const ValidationError = utils.common.errors.ValidationError const ValidationError = utils.common.errors.ValidationError
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import type {Amount, Adjustment, MaxAdjustment, import {Amount, Adjustment, MaxAdjustment,
MinAdjustment, Memo} from '../common/types' MinAdjustment, Memo} from '../common/types'
type Payment = { type Payment = {
source: Adjustment | MaxAdjustment, source: Adjustment & MaxAdjustment,
destination: Adjustment | MinAdjustment, destination: Adjustment & MinAdjustment,
paths?: string, paths?: string,
memos?: Array<Memo>, memos?: Array<Memo>,
// A 256-bit hash that can be used to identify a particular payment // A 256-bit hash that can be used to identify a particular payment
@@ -92,7 +90,7 @@ function createPaymentTransaction(address: string, paymentArgument: Payment
createMaximalAmount(payment.destination.minAmount) : createMaximalAmount(payment.destination.minAmount) :
(payment.destination.amount || payment.destination.minAmount) (payment.destination.amount || payment.destination.minAmount)
const txJSON: Object = { const txJSON: any = {
TransactionType: 'Payment', TransactionType: 'Payment',
Account: payment.source.address, Account: payment.source.address,
Destination: payment.destination.address, Destination: payment.destination.address,

View File

@@ -1,14 +1,18 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import assert from 'assert' import * as assert from 'assert'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import * as utils from './utils' import * as utils from './utils'
const validate = utils.common.validate const validate = utils.common.validate
const AccountFlagIndices = utils.common.constants.AccountFlagIndices const AccountFlagIndices = utils.common.constants.AccountFlagIndices
const AccountFields = utils.common.constants.AccountFields const AccountFields = utils.common.constants.AccountFields
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import {Memo} from '../common/types'
type WeightedSigner = {address: string, weight: number}
type SettingsSigners = {
threshold?: number,
weights: WeightedSigner[]
}
type Settings = { type Settings = {
passwordSpent?: boolean, passwordSpent?: boolean,
requireDestinationTag?: boolean, requireDestinationTag?: boolean,
@@ -19,25 +23,23 @@ type Settings = {
noFreeze?: boolean, noFreeze?: boolean,
globalFreeze?: boolean, globalFreeze?: boolean,
defaultRipple?: boolean, defaultRipple?: boolean,
emailHash?: ?string, emailHash?: string,
messageKey?: string, messageKey?: string,
domain?: string, domain?: string,
transferRate?: ?number, transferRate?: number,
regularKey?: string, regularKey?: string,
signers?: { signers?: SettingsSigners,
threshold?: number, memos?: Memo[]
weights: {address: string, weight: number}[],
},
} }
// Emptry string passed to setting will clear it // Emptry string passed to setting will clear it
const CLEAR_SETTING = null const CLEAR_SETTING = null
function setTransactionFlags(txJSON: Object, values: Settings) { function setTransactionFlags(txJSON: any, values: Settings) {
const keys = Object.keys(values) const keys = Object.keys(values)
assert(keys.length === 1, 'ERROR: can only set one setting per transaction') assert(keys.length === 1, 'ERROR: can only set one setting per transaction')
const flagName = keys[0] const flagName = keys[0]
const value = (values: Object)[flagName] const value = values[flagName]
const index = AccountFlagIndices[flagName] const index = AccountFlagIndices[flagName]
if (index !== undefined) { if (index !== undefined) {
if (value) { if (value) {
@@ -89,7 +91,7 @@ function convertTransferRate(transferRate: number | string): number | string {
return (new BigNumber(transferRate)).shift(9).toNumber() return (new BigNumber(transferRate)).shift(9).toNumber()
} }
function formatSignerEntry(signer: Object): Object { function formatSignerEntry(signer: WeightedSigner): Object {
return { return {
SignerEntry: { SignerEntry: {
Account: signer.address, Account: signer.address,
@@ -100,7 +102,7 @@ function formatSignerEntry(signer: Object): Object {
function createSettingsTransactionWithoutMemos( function createSettingsTransactionWithoutMemos(
account: string, settings: Settings account: string, settings: Settings
): Object { ): any {
if (settings.regularKey !== undefined) { if (settings.regularKey !== undefined) {
const removeRegularKey = { const removeRegularKey = {
TransactionType: 'SetRegularKey', TransactionType: 'SetRegularKey',
@@ -121,7 +123,7 @@ function createSettingsTransactionWithoutMemos(
} }
} }
const txJSON: Object = { const txJSON: any = {
TransactionType: 'AccountSet', TransactionType: 'AccountSet',
Account: account Account: account
} }

View File

@@ -1,18 +1,16 @@
/* @flow */
import * as utils from './utils' import * as utils from './utils'
import keypairs from 'ripple-keypairs' import keypairs = require('ripple-keypairs')
import binary from 'ripple-binary-codec' import binary = require('ripple-binary-codec')
import {computeBinaryTransactionHash} from 'ripple-hashes' import {computeBinaryTransactionHash} from 'ripple-hashes'
const validate = utils.common.validate const validate = utils.common.validate
function computeSignature(tx: Object, privateKey: string, signAs: ?string) { function computeSignature(tx: Object, privateKey: string, signAs?: string) {
const signingData = signAs ? const signingData = signAs ?
binary.encodeForMultisigning(tx, signAs) : binary.encodeForSigning(tx) binary.encodeForMultisigning(tx, signAs) : binary.encodeForSigning(tx)
return keypairs.sign(signingData, privateKey) return keypairs.sign(signingData, privateKey)
} }
function sign(txJSON: string, secret: string, options: Object = {} function sign(txJSON: string, secret: string, options: {signAs?: string} = {}
): {signedTransaction: string; id: string} { ): {signedTransaction: string; id: string} {
validate.sign({txJSON, secret}) validate.sign({txJSON, secret})
// we can't validate that the secret matches the account because // we can't validate that the secret matches the account because

View File

@@ -1,9 +1,7 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import * as utils from './utils' import * as utils from './utils'
import {validate} from '../common' import {validate} from '../common'
import type {Submit} from './types' import {Submit} from './types'
function isImmediateRejection(engineResult: string): boolean { function isImmediateRejection(engineResult: string): boolean {
// note: "tel" errors mean the local server refused to process the // note: "tel" errors mean the local server refused to process the

View File

@@ -1,12 +1,10 @@
/* @flow */
import * as _ from 'lodash' import * as _ from 'lodash'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import * as utils from './utils' import * as utils from './utils'
const validate = utils.common.validate const validate = utils.common.validate
const trustlineFlags = utils.common.txFlags.TrustSet const trustlineFlags = utils.common.txFlags.TrustSet
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import type {TrustLineSpecification} from '../ledger/trustlines-types' import {TrustLineSpecification} from '../ledger/trustlines-types'
function convertQuality(quality) { function convertQuality(quality) {
return (new BigNumber(quality)).shift(9).truncated().toNumber() return (new BigNumber(quality)).shift(9).truncated().toNumber()
@@ -21,7 +19,7 @@ function createTrustlineTransaction(account: string,
value: trustline.limit value: trustline.limit
} }
const txJSON: Object = { const txJSON: any = {
TransactionType: 'TrustSet', TransactionType: 'TrustSet',
Account: account, Account: account,
LimitAmount: limit, LimitAmount: limit,

View File

@@ -1,5 +1,3 @@
/* @flow */
export type Instructions = { export type Instructions = {
sequence?: number, sequence?: number,

View File

@@ -1,12 +1,11 @@
/* @flow */
import * as _ from 'lodash'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import * as common from '../common' import * as common from '../common'
import {Memo, ApiMemo} from '../common/types'
const txFlags = common.txFlags const txFlags = common.txFlags
import type {Instructions, Prepare} from './types' import {Instructions, Prepare} from './types'
import {RippleAPI} from '../api'
function formatPrepareResponse(txJSON: Object): Object { function formatPrepareResponse(txJSON: any): Prepare {
const instructions = { const instructions = {
fee: common.dropsToXrp(txJSON.Fee), fee: common.dropsToXrp(txJSON.Fee),
sequence: txJSON.Sequence, sequence: txJSON.Sequence,
@@ -15,7 +14,7 @@ function formatPrepareResponse(txJSON: Object): Object {
} }
return { return {
txJSON: JSON.stringify(txJSON), txJSON: JSON.stringify(txJSON),
instructions: _.omitBy(instructions, _.isUndefined) instructions
} }
} }
@@ -31,7 +30,7 @@ function scaleValue(value, multiplier, extra = 0) {
return (new BigNumber(value)).times(multiplier).plus(extra).toString() return (new BigNumber(value)).times(multiplier).plus(extra).toString()
} }
function prepareTransaction(txJSON: Object, api: Object, function prepareTransaction(txJSON: any, api: RippleAPI,
instructions: Instructions instructions: Instructions
): Promise<Prepare> { ): Promise<Prepare> {
common.validate.instructions(instructions) common.validate.instructions(instructions)
@@ -104,17 +103,16 @@ function prepareTransaction(txJSON: Object, api: Object,
]).then(() => formatPrepareResponse(txJSON)) ]).then(() => formatPrepareResponse(txJSON))
} }
function convertStringToHex(string: string) { function convertStringToHex(string: string): string {
return string ? (new Buffer(string, 'utf8')).toString('hex').toUpperCase() : return new Buffer(string, 'utf8').toString('hex').toUpperCase()
undefined
} }
function convertMemo(memo: Object): Object { function convertMemo(memo: Memo): {Memo: ApiMemo} {
return { return {
Memo: common.removeUndefined({ Memo: common.removeUndefined({
MemoData: convertStringToHex(memo.data), MemoData: memo.data ? convertStringToHex(memo.data) : undefined,
MemoType: convertStringToHex(memo.type), MemoType: memo.type ? convertStringToHex(memo.type) : undefined,
MemoFormat: convertStringToHex(memo.format) MemoFormat: memo.format ? convertStringToHex(memo.format) : undefined
}) })
} }
} }

View File

@@ -1455,9 +1455,14 @@ describe('RippleAPI', function() {
}); });
it('ledger utils - renameCounterpartyToIssuerInOrder', function() { it('ledger utils - renameCounterpartyToIssuerInOrder', function() {
const order = {taker_gets: {issuer: '1'}}; const order = {
const expected = {taker_gets: {issuer: '1'}}; taker_gets: {counterparty: '1'},
taker_pays: {counterparty: '1'}
};
const expected = {
taker_gets: {issuer: '1'},
taker_pays: {issuer: '1'}
};
assert.deepEqual(utils.renameCounterpartyToIssuerInOrder(order), expected); assert.deepEqual(utils.renameCounterpartyToIssuerInOrder(order), expected);
}); });

View File

@@ -1 +1 @@
--reporter spec --timeout 5000 --slow 500 --compilers js:babel-register --reporter spec --timeout 5000 --slow 500 --require ts-node/register

26
tsconfig.json Normal file
View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es6",
"lib": [
"es2017"
],
"outDir": "dist/npm",
"rootDir": "src",
"module": "commonjs",
"moduleResolution": "node",
"strictNullChecks": false,
"noImplicitAny": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": false,
"preserveConstEnums": false,
"suppressImplicitAnyIndexErrors": false,
"declaration": false,
"sourceMap": true,
"skipLibCheck": true
},
"include": [
"custom_typings/**/*.ts",
"src/**/*.ts"
]
}

1923
yarn.lock

File diff suppressed because it is too large Load Diff