mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-11 08:15:48 +00:00
Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f6af4797f | ||
|
|
5985d9022e | ||
|
|
8abc87c27c | ||
|
|
f0feaca785 | ||
|
|
f811bd6c2d | ||
|
|
eeb6e6b39d | ||
|
|
327a8dc451 | ||
|
|
2fafa493a2 | ||
|
|
7617c3005c | ||
|
|
5cdbb71277 | ||
|
|
f9339c36bf | ||
|
|
67dc57e9d0 | ||
|
|
757f3190d1 | ||
|
|
0d94a15ee7 | ||
|
|
7f1c80da1b | ||
|
|
f74e11bce0 | ||
|
|
d4c843e8e3 | ||
|
|
bae190b282 | ||
|
|
d2cbd70da8 | ||
|
|
5da78ce583 | ||
|
|
14bbe3e30b | ||
|
|
e52e2bbc68 | ||
|
|
b56752e45b | ||
|
|
4632f511ab | ||
|
|
e17b6f172d | ||
|
|
eb04e878ba | ||
|
|
c71febd116 | ||
|
|
69c1ccbb6b | ||
|
|
499b8c8d8b | ||
|
|
ea009f9a84 | ||
|
|
dc784d4567 | ||
|
|
9ffc8a2c0b | ||
|
|
5b20fe573e | ||
|
|
7e466bb80f | ||
|
|
1f8418b447 | ||
|
|
ccfc57fc62 | ||
|
|
1d31fccd72 | ||
|
|
9ac1a89e48 | ||
|
|
bfc0696324 | ||
|
|
e33e782f9e | ||
|
|
f2b591d1b2 | ||
|
|
fe9af5153d | ||
|
|
0dfdd0a601 | ||
|
|
4acc42e1b6 | ||
|
|
7c9a179865 | ||
|
|
c6296a4918 | ||
|
|
cc399f1164 | ||
|
|
e4ffb96646 | ||
|
|
8d34428dac | ||
|
|
353637a0c0 | ||
|
|
00713d8ec1 | ||
|
|
d949881e9f | ||
|
|
5075441a69 | ||
|
|
94a852cb8b | ||
|
|
06f847c2d0 | ||
|
|
0c2f9d0e62 | ||
|
|
11ed6b124f | ||
|
|
8767fc0068 | ||
|
|
66b07623b0 | ||
|
|
4f3635eef0 | ||
|
|
f638833759 | ||
|
|
ab9d1936d9 | ||
|
|
0fefb2bd2c | ||
|
|
6740eee495 | ||
|
|
aa6020e00d | ||
|
|
7bfe4a6cd8 | ||
|
|
aa467681e4 | ||
|
|
6b8cd6151d | ||
|
|
0d6aaee12a | ||
|
|
dc03c6e0ac | ||
|
|
0f4d957d14 | ||
|
|
71a13224a1 | ||
|
|
8097ed60ba | ||
|
|
408bb74214 | ||
|
|
9433b43873 | ||
|
|
896bf48c79 | ||
|
|
3dd21a7e11 | ||
|
|
ed79a04018 | ||
|
|
ebfe20defb | ||
|
|
28b148348d | ||
|
|
fe099f2c8b | ||
|
|
107c8c9f0f | ||
|
|
39e818b3e5 | ||
|
|
588ffa3d5c | ||
|
|
691e4dd114 | ||
|
|
55bc42725f | ||
|
|
cce55b9361 | ||
|
|
c23c6e4fc9 | ||
|
|
afdd60efe8 | ||
|
|
8f6ea573ff |
4
.babelrc
Normal file
4
.babelrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["es2015", "stage-1"],
|
||||
"plugins": ["syntax-flow", "transform-flow-strip-types"]
|
||||
}
|
||||
@@ -4,6 +4,11 @@
|
||||
.*/ripple-lib/test/fixtures/.*
|
||||
.*/node_modules/flow-bin/.*
|
||||
.*/node_modules/webpack/.*
|
||||
.*/node_modules/babel-core/.*
|
||||
.*/node_modules/babel-eslint/.*
|
||||
.*/node_modules/babel-preset-es2015/.*
|
||||
.*/node_modules/babel-preset-stage-1/.*
|
||||
.*/node_modules/babel-register/.*
|
||||
|
||||
[include]
|
||||
./node_modules/
|
||||
|
||||
90
Gulpfile.js
90
Gulpfile.js
@@ -8,24 +8,49 @@ var rename = require('gulp-rename');
|
||||
var webpack = require('webpack');
|
||||
var bump = require('gulp-bump');
|
||||
var argv = require('yargs').argv;
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
|
||||
var pkg = require('./package.json');
|
||||
|
||||
var uglifyOptions = {
|
||||
mangle: {
|
||||
except: ['_', 'RippleError', 'RippledError', 'UnexpectedError',
|
||||
'LedgerVersionError', 'ConnectionError', 'NotConnectedError',
|
||||
'DisconnectedError', 'TimeoutError', 'ResponseFormatError',
|
||||
'ValidationError', 'NotFoundError', 'MissingLedgerHistoryError',
|
||||
'PendingLedgerVersionError'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
function webpackConfig(extension, overrides) {
|
||||
overrides = overrides || {};
|
||||
var defaults = {
|
||||
cache: true,
|
||||
externals: [{
|
||||
'lodash': '_'
|
||||
}],
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: './build/',
|
||||
filename: ['ripple-', extension].join(pkg.version)
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NormalModuleReplacementPlugin(/^ws$/, './wswrapper'),
|
||||
new webpack.NormalModuleReplacementPlugin(/^\.\/wallet$/, './wallet-web'),
|
||||
new webpack.NormalModuleReplacementPlugin(/^.*setup-api$/,
|
||||
'./setup-api-web')
|
||||
],
|
||||
module: {
|
||||
loaders: [{
|
||||
test: /jayson/,
|
||||
loader: 'null'
|
||||
}, {
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader?optional=runtime'
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader'
|
||||
}, {
|
||||
test: /\.json/,
|
||||
loader: 'json-loader'
|
||||
@@ -35,15 +60,70 @@ function webpackConfig(extension, overrides) {
|
||||
return _.assign({}, defaults, overrides);
|
||||
}
|
||||
|
||||
function webpackConfigForWebTest(testFileName, path) {
|
||||
var match = testFileName.match(/\/?([^\/]*)-test.js$/);
|
||||
if (!match) {
|
||||
assert(false, 'wrong filename:' + testFileName);
|
||||
}
|
||||
var configOverrides = {
|
||||
externals: [{
|
||||
'lodash': '_',
|
||||
'ripple-api': 'ripple',
|
||||
'net': 'null'
|
||||
}],
|
||||
entry: testFileName,
|
||||
output: {
|
||||
library: match[1].replace(/-/g, '_'),
|
||||
path: './test-compiled-for-web/' + (path ? path : ''),
|
||||
filename: match[1] + '-test.js'
|
||||
}
|
||||
};
|
||||
return webpackConfig('.js', configOverrides);
|
||||
}
|
||||
|
||||
gulp.task('build-tests', function(callback) {
|
||||
var times = 0;
|
||||
function done() {
|
||||
if (++times >= 5) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
webpack(webpackConfigForWebTest('./test/rangeset-test.js'), done);
|
||||
webpack(webpackConfigForWebTest('./test/connection-test.js'), done);
|
||||
webpack(webpackConfigForWebTest('./test/api-test.js'), done);
|
||||
webpack(webpackConfigForWebTest('./test/broadcast-api-test.js'), done);
|
||||
webpack(webpackConfigForWebTest('./test/integration/integration-test.js',
|
||||
'integration/'), done);
|
||||
});
|
||||
|
||||
function createLink(from, to) {
|
||||
if (fs.existsSync(to)) {
|
||||
fs.unlinkSync(to);
|
||||
}
|
||||
fs.linkSync(from, to);
|
||||
}
|
||||
|
||||
function createBuildLink(callback) {
|
||||
return function(err, res) {
|
||||
createLink('./build/ripple-' + pkg.version + '.js',
|
||||
'./build/ripple-latest.js');
|
||||
callback(err, res);
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('build', function(callback) {
|
||||
webpack(webpackConfig('.js'), callback);
|
||||
webpack(webpackConfig('.js'), createBuildLink(callback));
|
||||
});
|
||||
|
||||
gulp.task('build-min', ['build'], function() {
|
||||
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
||||
.pipe(uglify())
|
||||
.pipe(uglify(uglifyOptions))
|
||||
.pipe(rename(['ripple-', '-min.js'].join(pkg.version)))
|
||||
.pipe(gulp.dest('./build/'));
|
||||
.pipe(gulp.dest('./build/'))
|
||||
.on('end', function() {
|
||||
createLink('./build/ripple-' + pkg.version + '-min.js',
|
||||
'./build/ripple-latest-min.js');
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('build-debug', function(callback) {
|
||||
|
||||
16
HISTORY.md
16
HISTORY.md
@@ -1,3 +1,19 @@
|
||||
##0.16.5
|
||||
**Changes**
|
||||
+ [Filter insufficient source funds paths from pathfind results](https://github.com/ripple/ripple-lib/pull/688)
|
||||
|
||||
##0.16.4
|
||||
**Changes**
|
||||
+ [Update ws to 1.0.1](https://github.com/ripple/ripple-lib/pull/682)
|
||||
|
||||
##0.16.2
|
||||
**Changes**
|
||||
+ [Bump ripple-binary-codec dependency version to 0.1.1 to fix issue with computeLedgerHash for transactions with DeliverMin]
|
||||
|
||||
##0.16.1
|
||||
**Changes**
|
||||
+ [FIX: Use assert not assert-diff](https://github.com/ripple/ripple-lib/commit/f6ebe325193e7208c5ee8d8e84a7504714f0009e)
|
||||
|
||||
##0.16.0
|
||||
**Breaking Changes**
|
||||
+ [Fix types of XRP values in getServerInfo response](https://github.com/ripple/ripple-lib/commit/99d08065e4bda3dda6ae1f183adbd11abc70a9b7)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ripple-lib
|
||||
|
||||
A JavaScript API for interacting with Ripple in Node.js and the browser
|
||||
A JavaScript API for interacting with Ripple in Node.js
|
||||
|
||||
[](https://circleci.com/gh/ripple/ripple-lib/tree/develop) [](https://coveralls.io/r/ripple/ripple-lib?branch=develop)
|
||||
|
||||
@@ -8,7 +8,7 @@ A JavaScript API for interacting with Ripple in Node.js and the browser
|
||||
|
||||
###Features
|
||||
|
||||
+ Connect to a rippled server in JavaScript (Node.js or browser)
|
||||
+ Connect to a rippled server in Node.js
|
||||
+ Issue [rippled API](https://ripple.com/build/rippled-apis/) requests
|
||||
+ Listen to events on the Ripple network (transaction, ledger, etc.)
|
||||
+ Sign and submit transactions to the Ripple network
|
||||
|
||||
13
circle.yml
13
circle.yml
@@ -1,7 +1,20 @@
|
||||
machine:
|
||||
node:
|
||||
version: 0.12.0
|
||||
hosts:
|
||||
testripple.circleci.com: 127.0.0.1
|
||||
dependencies:
|
||||
pre:
|
||||
- npm -g install npm@latest-2
|
||||
- npm install flow-bin
|
||||
- wget https://s3-us-west-2.amazonaws.com/ripple-debs/rippled_0.30.1-b11-1.deb
|
||||
- sudo dpkg -i rippled_0.30.1-b11-1.deb
|
||||
test:
|
||||
pre:
|
||||
- rippled -a --start --conf "$HOME/$CIRCLE_PROJECT_REPONAME/test/integration/rippled.cfg":
|
||||
background: true
|
||||
override:
|
||||
- scripts/ci.sh "$CIRCLE_NODE_INDEX" "$CIRCLE_NODE_TOTAL":
|
||||
parallel: true
|
||||
post:
|
||||
- killall /usr/bin/rippled
|
||||
|
||||
159
docs/index.md
159
docs/index.md
@@ -54,12 +54,15 @@
|
||||
- [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
- [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
- [sign](#sign)
|
||||
- [combine](#combine)
|
||||
- [submit](#submit)
|
||||
- [generateAddress](#generateaddress)
|
||||
- [computeLedgerHash](#computeledgerhash)
|
||||
- [API Events](#api-events)
|
||||
- [ledger](#ledger)
|
||||
- [error](#error)
|
||||
- [connected](#connected)
|
||||
- [disconnected](#disconnected)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
@@ -89,6 +92,14 @@ const api = new RippleAPI({
|
||||
api.on('error', (errorCode, errorMessage) => {
|
||||
console.log(errorCode + ': ' + errorMessage);
|
||||
});
|
||||
api.on('connected', () => {
|
||||
console.log('connected');
|
||||
});
|
||||
api.on('disconnected', (code) => {
|
||||
// code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
|
||||
// will be 1000 if this was normal closure
|
||||
console.log('disconnected, code:', code);
|
||||
});
|
||||
api.connect().then(() => {
|
||||
/* insert code here */
|
||||
}).then(() => {
|
||||
@@ -137,7 +148,7 @@ If you omit the `server` parameter, RippleAPI operates [offline](#offline-functi
|
||||
|
||||
1. Install [NodeJS](https://nodejs.org) and the Node Package Manager (npm). Most Linux distros have a package for NodeJS, but make sure you have version `0.12.0` or higher.
|
||||
2. Use npm to install [Babel](https://babeljs.io/) globally:
|
||||
`npm install -g babel`
|
||||
`npm install -g babel-cli`
|
||||
3. Use npm to install RippleAPI:
|
||||
`npm install ripple-lib`
|
||||
|
||||
@@ -200,7 +211,7 @@ A *value* is a quantity of a currency represented as a decimal string. Be carefu
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
|
||||
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
@@ -269,7 +280,7 @@ Executing a transaction with `RippleAPI` requires the following four steps:
|
||||
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place.
|
||||
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place. For multisignature transactions, the `signedTransaction` fields returned by `sign` must be collected and passed to the [combine](#combine) method.
|
||||
3. [Submit](#submit) - Submit the transaction to the connected server.
|
||||
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
|
||||
|
||||
@@ -290,6 +301,7 @@ maxFee | [value](#value) | *Optional* The maximum fee to pay for the transaction
|
||||
maxLedgerVersion | integer,null | *Optional* The highest ledger version that the transaction can be included in. If this option and `maxLedgerVersionOffset` are both omitted, the `maxLedgerVersion` option will default to 3 greater than the current validated ledger version (equivalent to `maxLedgerVersionOffset=3`). Use `null` to not set a maximum ledger version.
|
||||
maxLedgerVersionOffset | integer | *Optional* Offset from current validated legder version to highest ledger version that the transaction can be included in.
|
||||
sequence | [sequence](#account-sequence-number) | *Optional* The initiating account's sequence number for this transaction.
|
||||
signersCount | integer | *Optional* Number of signers that will be signing this transaction.
|
||||
|
||||
We recommended that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the network ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare*" method.
|
||||
|
||||
@@ -418,6 +430,7 @@ expirationTime | date-time string | *Optional* Time after which the offer is no
|
||||
fillOrKill | boolean | *Optional* Treat the offer as a [Fill or Kill order](http://en.wikipedia.org/wiki/Fill_or_kill). Only attempt to match existing offers in the ledger, and only do so if the entire quantity can be exchanged.
|
||||
immediateOrCancel | boolean | *Optional* Treat the offer as an [Immediate or Cancel order](http://en.wikipedia.org/wiki/Immediate_or_cancel). If enabled, the offer will never become a ledger node: it only attempts to match existing offers in the ledger.
|
||||
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
|
||||
orderToReplace | [sequence](#account-sequence-number) | *Optional* The [account sequence number](#account-sequence-number) of an order to cancel before the new order is created, effectively replacing the old order.
|
||||
passive | boolean | *Optional* If enabled, the offer will not consume offers that exactly match it, and instead becomes an Offer node in the ledger. It will still consume offers that cross it.
|
||||
|
||||
### Example
|
||||
@@ -480,7 +493,13 @@ passwordSpent | boolean | *Optional* Indicates that the account has used its fre
|
||||
regularKey | [address](#ripple-address),null | *Optional* The public key of a new keypair, to use as the regular key to this account, as a base-58-encoded string in the same format as an account address. Use `null` to remove the regular key.
|
||||
requireAuthorization | boolean | *Optional* If set, this account must individually approve other users in order for those users to hold this account’s issuances.
|
||||
requireDestinationTag | boolean | *Optional* Requires incoming payments to specify a destination tag.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, represented as billionths of a unit. Use `null` to set no fee.
|
||||
signers | object | *Optional* Settings that determine what sets of accounts can be used to sign a transaction on behalf of this account using multisigning.
|
||||
*signers.* threshold | integer | *Optional* A target number for the signer weights. A multi-signature from this list is valid only if the sum weights of the signatures provided is equal or greater than this value. To delete the signers setting, use the value `0`.
|
||||
*signers.* weights | array | *Optional* Weights of signatures for each signer.
|
||||
*signers.* weights[] | object | An association of an address and a weight.
|
||||
*signers.weights[].* address | [address](#ripple-address) | A Ripple account address
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -803,7 +822,7 @@ Name | Type | Description
|
||||
id | [id](#transaction-id) | A hash of the transaction that can be used to identify it.
|
||||
address | [address](#ripple-address) | The address of the account that initiated the transaction.
|
||||
sequence | [sequence](#account-sequence-number) | The account sequence number of the transaction for the account that initiated it.
|
||||
type | [transactionType](#transaction-types) | The type of the tranasction.
|
||||
type | [transactionType](#transaction-types) | The type of the transaction.
|
||||
specification | object | A specification that would produce the same outcome as this transaction. The structure of the specification depends on the value of the `type` field (see [Transaction Types](#transaction-types) for details). *Note:* This is **not** necessarily the same as the original specification.
|
||||
outcome | object | The outcome of the transaction (what effects it had).
|
||||
*outcome.* result | string | Result code returned by rippled. See [Transaction Results](https://ripple.com/build/transactions/#full-transaction-response-list) for a complete list.
|
||||
@@ -820,6 +839,7 @@ outcome | object | The outcome of the transaction (what effects it had).
|
||||
*outcome.orderbookChanges.\*[].* makerExchangeRate | [value](#value) | *Optional* The exchange rate between the `quantity` currency and the `totalPrice` currency from the point of view of the maker.
|
||||
*outcome.* ledgerVersion | integer | The ledger version that the transaction was validated in.
|
||||
*outcome.* indexInLedger | integer | The ordering index of the transaction in the ledger.
|
||||
*outcome.* deliveredAmount | [amount](#amount) | *Optional* For payment transactions, it is impossible to reliably compute the actual delivered amount from the balanceChanges due to fixed precision. If the payment is not a partial payment and the transaction succeeded, the deliveredAmount should always be considered to be the amount specified in the transaction.
|
||||
*outcome.* timestamp | date-time string | *Optional* The timestamp when the transaction was validated. (May be missing when requesting transactions in binary mode.)
|
||||
|
||||
### Example
|
||||
@@ -859,6 +879,11 @@ return api.getTransaction(id).then(transaction => {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2013-03-12T23:56:50.000Z",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
@@ -993,6 +1018,11 @@ return api.getTransactions(address).then(transaction => {
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
@@ -1085,6 +1115,11 @@ return api.getTransactions(address).then(transaction => {
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
@@ -1477,7 +1512,7 @@ options | object | *Optional* Options to determine how the balances will be calc
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an array of objects with the following structure:
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
@@ -1599,18 +1634,18 @@ paths | string | The paths of trustlines and orders to use in executing the paym
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const pathfind = {
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"value": "100"
|
||||
}
|
||||
}
|
||||
const pathfind = {
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"value": "100"
|
||||
}
|
||||
}
|
||||
};
|
||||
return api.getPaths(pathfind)
|
||||
.then(paths => {/* ... */});
|
||||
@@ -2644,7 +2679,13 @@ passwordSpent | boolean | *Optional* Indicates that the account has used its fre
|
||||
regularKey | [address](#ripple-address),null | *Optional* The public key of a new keypair, to use as the regular key to this account, as a base-58-encoded string in the same format as an account address. Use `null` to remove the regular key.
|
||||
requireAuthorization | boolean | *Optional* If set, this account must individually approve other users in order for those users to hold this account’s issuances.
|
||||
requireDestinationTag | boolean | *Optional* Requires incoming payments to specify a destination tag.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, represented as billionths of a unit. Use `null` to set no fee.
|
||||
signers | object | *Optional* Settings that determine what sets of accounts can be used to sign a transaction on behalf of this account using multisigning.
|
||||
*signers.* threshold | integer | *Optional* A target number for the signer weights. A multi-signature from this list is valid only if the sum weights of the signatures provided is equal or greater than this value. To delete the signers setting, use the value `0`.
|
||||
*signers.* weights | array | *Optional* Weights of signatures for each signer.
|
||||
*signers.* weights[] | object | An association of an address and a weight.
|
||||
*signers.weights[].* address | [address](#ripple-address) | A Ripple account address
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -2894,7 +2935,7 @@ const trustline = {
|
||||
}
|
||||
]
|
||||
};
|
||||
return api.preparePayment(address, trustline).then(prepared =>
|
||||
return api.prepareTrustline(address, trustline).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
@@ -3011,7 +3052,7 @@ instructions | object | The instructions for how to execute the transaction afte
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const orderCancellation = {orderSequence: 123};
|
||||
return api.prepareOrderCancellation(address, sequence)
|
||||
return api.prepareOrderCancellation(address, orderCancellation)
|
||||
.then(prepared => {/* ... */});
|
||||
```
|
||||
|
||||
@@ -3282,7 +3323,7 @@ return api.prepareSuspendedPaymentExecution(address, suspendedPaymentExecution).
|
||||
|
||||
## sign
|
||||
|
||||
`sign(txJSON: string, secret: string): {signedTransaction: string, id: string}`
|
||||
`sign(txJSON: string, secret: string, options: Object): {signedTransaction: string, id: string}`
|
||||
|
||||
Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).
|
||||
|
||||
@@ -3292,6 +3333,8 @@ Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
txJSON | string | Transaction represented as a JSON string in rippled format.
|
||||
secret | secret string | The secret of the account that is initiating the transaction.
|
||||
options | object | *Optional* Options that control the type of signature that will be generated.
|
||||
*options.* signAs | [address](#ripple-address) | *Optional* The account that the signature should count for in multisigning.
|
||||
|
||||
### Return Value
|
||||
|
||||
@@ -3319,6 +3362,44 @@ return api.sign(txJSON, secret);
|
||||
```
|
||||
|
||||
|
||||
## combine
|
||||
|
||||
`combine(signedTransactions: Array<string>): {signedTransaction: string, id: string}`
|
||||
|
||||
Combines signed transactions from multiple accounts for a multisignature transaction. The signed transaction must subsequently be [submitted](#submit).
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
signedTransactions | array\<string\> | An array of signed transactions (from the output of [sign](#sign)) to combine.
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns an object with the following structure:
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
signedTransaction | string | The signed transaction represented as an uppercase hexadecimal string.
|
||||
id | [id](#transaction-id) | The [Transaction ID](#transaction-id) of the signed transaction.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const signedTransactions = [ "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
|
||||
"12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1F1" ];
|
||||
return api.combine(signedTransactions);
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"signedTransaction": "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
|
||||
"id": "8A3BFD2214B4C8271ED62648FCE9ADE4EE82EF01827CF7D1F7ED497549A368CC"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## submit
|
||||
|
||||
`submit(signedTransaction: string): Promise<Object>`
|
||||
@@ -3337,7 +3418,7 @@ This method returns an object with the following structure:
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
resultCode | string | The result code returned by rippled. [List of tranasction responses](http://pages.lightthenight.org/gba/SanFran15/ripple)
|
||||
resultCode | string | The result code returned by rippled. [List of transaction responses](https://ripple.com/build/transactions/#full-transaction-response-list)
|
||||
resultMessage | string | Human-readable explanation of the status of the transaction.
|
||||
|
||||
### Example
|
||||
@@ -3523,3 +3604,35 @@ api.on('error', (errorCode, errorMessage, data) => {
|
||||
tooBusy: The server is too busy to help you now.
|
||||
```
|
||||
|
||||
## connected
|
||||
|
||||
This event is emitted after connection successfully opened.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
api.on('connected', () => {
|
||||
console.log('Connection is open now.');
|
||||
});
|
||||
```
|
||||
|
||||
## disconnected
|
||||
|
||||
This event is emitted when connection is closed.
|
||||
|
||||
### Return Value
|
||||
|
||||
The only parameter is a number containing the [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) send by the server.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
api.on('disconnected', (code) => {
|
||||
if (code !== 1000) {
|
||||
console.log('Connection is closed due to error.');
|
||||
} else {
|
||||
console.log('Connection is closed normally.');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
38
docs/samples/cancelall.js
Normal file
38
docs/samples/cancelall.js
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
const RippleAPI = require('../../dist/npm').RippleAPI; // require('ripple-lib')
|
||||
|
||||
const address = 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K';
|
||||
const secret = '';
|
||||
|
||||
const api = new RippleAPI({server: 'wss://s1.ripple.com:443'});
|
||||
const instructions = {maxLedgerVersionOffset: 5};
|
||||
|
||||
function fail(message) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function cancelOrder(orderSequence) {
|
||||
console.log('Cancelling order: ' + orderSequence.toString());
|
||||
return api.prepareOrderCancellation(address, {orderSequence}, instructions)
|
||||
.then(prepared => {
|
||||
const signing = api.sign(prepared.txJSON, secret);
|
||||
return api.submit(signing.signedTransaction);
|
||||
});
|
||||
}
|
||||
|
||||
function cancelAllOrders(orderSequences) {
|
||||
if (orderSequences.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const orderSequence = orderSequences.pop();
|
||||
return cancelOrder(orderSequence).then(() => cancelAllOrders(orderSequences));
|
||||
}
|
||||
|
||||
api.connect().then(() => {
|
||||
console.log('Connected...');
|
||||
return api.getOrders(address).then(orders => {
|
||||
const orderSequences = orders.map(order => order.properties.sequence);
|
||||
return cancelAllOrders(orderSequences);
|
||||
}).then(() => process.exit(0));
|
||||
}).catch(fail);
|
||||
@@ -21,7 +21,7 @@ A *value* is a quantity of a currency represented as a decimal string. Be carefu
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
|
||||
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
|
||||
@@ -11,6 +11,14 @@ const api = new RippleAPI({
|
||||
api.on('error', (errorCode, errorMessage) => {
|
||||
console.log(errorCode + ': ' + errorMessage);
|
||||
});
|
||||
api.on('connected', () => {
|
||||
console.log('connected');
|
||||
});
|
||||
api.on('disconnected', (code) => {
|
||||
// code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
|
||||
// will be 1000 if this was normal closure
|
||||
console.log('disconnected, code:', code);
|
||||
});
|
||||
api.connect().then(() => {
|
||||
/* insert code here */
|
||||
}).then(() => {
|
||||
@@ -47,7 +55,7 @@ If you omit the `server` parameter, RippleAPI operates [offline](#offline-functi
|
||||
|
||||
1. Install [NodeJS](https://nodejs.org) and the Node Package Manager (npm). Most Linux distros have a package for NodeJS, but make sure you have version `0.12.0` or higher.
|
||||
2. Use npm to install [Babel](https://babeljs.io/) globally:
|
||||
`npm install -g babel`
|
||||
`npm install -g babel-cli`
|
||||
3. Use npm to install RippleAPI:
|
||||
`npm install ripple-lib`
|
||||
|
||||
|
||||
24
docs/src/combine.md.ejs
Normal file
24
docs/src/combine.md.ejs
Normal file
@@ -0,0 +1,24 @@
|
||||
## combine
|
||||
|
||||
`combine(signedTransactions: Array<string>): {signedTransaction: string, id: string}`
|
||||
|
||||
Combines signed transactions from multiple accounts for a multisignature transaction. The signed transaction must subsequently be [submitted](#submit).
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema("input/combine.json") %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns an object with the following structure:
|
||||
|
||||
<%- renderSchema("output/sign.json") %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const signedTransactions = <%- importFile('test/fixtures/requests/combine.json') %>;
|
||||
return api.combine(signedTransactions);
|
||||
```
|
||||
|
||||
<%- renderFixture("responses/combine.json") %>
|
||||
@@ -47,3 +47,35 @@ api.on('error', (errorCode, errorMessage, data) => {
|
||||
```
|
||||
tooBusy: The server is too busy to help you now.
|
||||
```
|
||||
|
||||
## connected
|
||||
|
||||
This event is emitted after connection successfully opened.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
api.on('connected', () => {
|
||||
console.log('Connection is open now.');
|
||||
});
|
||||
```
|
||||
|
||||
## disconnected
|
||||
|
||||
This event is emitted when connection is closed.
|
||||
|
||||
### Return Value
|
||||
|
||||
The only parameter is a number containing the [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) send by the server.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
api.on('disconnected', (code) => {
|
||||
if (code !== 1000) {
|
||||
console.log('Connection is closed due to error.');
|
||||
} else {
|
||||
console.log('Connection is closed normally.');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
@@ -10,7 +10,7 @@ Returns aggregate balances by currency plus a breakdown of assets and obligation
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an array of objects with the following structure:
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<%- renderSchema('output/get-balance-sheet.json') %>
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<% include prepareSuspendedPaymentCancellation.md.ejs %>
|
||||
<% include prepareSuspendedPaymentExecution.md.ejs %>
|
||||
<% include sign.md.ejs %>
|
||||
<% include combine.md.ejs %>
|
||||
<% include submit.md.ejs %>
|
||||
<% include generateAddress.md.ejs %>
|
||||
<% include computeLedgerHash.md.ejs %>
|
||||
|
||||
@@ -23,7 +23,7 @@ All "prepare*" methods have the same return type.
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const orderCancellation = {orderSequence: 123};
|
||||
return api.prepareOrderCancellation(address, sequence)
|
||||
return api.prepareOrderCancellation(address, orderCancellation)
|
||||
.then(prepared => {/* ... */});
|
||||
```
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ All "prepare*" methods have the same return type.
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const trustline = <%- importFile('test/fixtures/requests/prepare-trustline.json') %>;
|
||||
return api.preparePayment(address, trustline).then(prepared =>
|
||||
return api.prepareTrustline(address, trustline).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## sign
|
||||
|
||||
`sign(txJSON: string, secret: string): {signedTransaction: string, id: string}`
|
||||
`sign(txJSON: string, secret: string, options: Object): {signedTransaction: string, id: string}`
|
||||
|
||||
Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Executing a transaction with `RippleAPI` requires the following four steps:
|
||||
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place.
|
||||
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place. For multisignature transactions, the `signedTransaction` fields returned by `sign` must be collected and passed to the [combine](#combine) method.
|
||||
3. [Submit](#submit) - Submit the transaction to the connected server.
|
||||
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
|
||||
|
||||
|
||||
4304
npm-shrinkwrap.json
generated
4304
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.16.1",
|
||||
"version": "0.17.3",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -15,41 +15,50 @@
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^1.4.8",
|
||||
"babel-polyfill": "^6.2.0",
|
||||
"babel-runtime": "^5.5.4",
|
||||
"ajv": "^4.0.5",
|
||||
"ajv-i18n": "^1.2.0",
|
||||
"babel-polyfill": "^6.3.14",
|
||||
"babel-runtime": "^6.3.19",
|
||||
"bignumber.js": "^2.0.3",
|
||||
"https-proxy-agent": "^1.0.0",
|
||||
"jayson": "^1.2.2",
|
||||
"lodash": "^3.1.0",
|
||||
"ripple-address-codec": "^2.0.1",
|
||||
"ripple-binary-codec": "^0.1.0",
|
||||
"ripple-binary-codec": "^0.1.4",
|
||||
"ripple-hashes": "^0.1.0",
|
||||
"ripple-keypairs": "^0.10.0",
|
||||
"ripple-lib-transactionparser": "^0.6.0",
|
||||
"ws": "^0.7.1"
|
||||
"ws": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"assert-diff": "^1.0.1",
|
||||
"babel": "^5.8.21",
|
||||
"babel-core": "^5.8.22",
|
||||
"babel-eslint": "^4.1.3",
|
||||
"babel-loader": "^5.3.2",
|
||||
"coveralls": "^2.10.0",
|
||||
"babel-cli": "^6.4.0",
|
||||
"babel-core": "^6.4.0",
|
||||
"babel-eslint": "^6.0.4",
|
||||
"babel-loader": "^6.2.1",
|
||||
"babel-plugin-syntax-flow": "^6.3.13",
|
||||
"babel-plugin-transform-flow-strip-types": "^6.4.0",
|
||||
"babel-preset-es2015": "^6.3.13",
|
||||
"babel-preset-stage-1": "^6.3.13",
|
||||
"babel-register": "^6.3.13",
|
||||
"coveralls": "^2.11.9",
|
||||
"doctoc": "^0.15.0",
|
||||
"ejs": "^2.3.4",
|
||||
"eslint": "^1.3.0",
|
||||
"eslint-plugin-flowtype": "^1.0.0",
|
||||
"eslint": "^2.9.0",
|
||||
"eventemitter2": "^0.4.14",
|
||||
"flow-bin": "^0.14",
|
||||
"flow-bin": "^0.30.0",
|
||||
"gulp": "^3.8.10",
|
||||
"gulp-bump": "^0.1.13",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-uglify": "^1.1.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"http-server": "^0.8.5",
|
||||
"istanbul": "^1.1.0-alpha.1",
|
||||
"json-loader": "^0.5.2",
|
||||
"json-schema-to-markdown-table": "^0.4.0",
|
||||
"mocha": "^2.1.0",
|
||||
"mocha-in-sauce": "^0.0.1",
|
||||
"mocha-junit-reporter": "^1.9.1",
|
||||
"null-loader": "^0.1.1",
|
||||
"webpack": "^1.5.3",
|
||||
"yargs": "^1.3.1"
|
||||
},
|
||||
@@ -63,11 +72,12 @@
|
||||
"watch": "babel -w -D --optional runtime -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",
|
||||
"test": "istanbul test _mocha",
|
||||
"test": "babel-node ./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha",
|
||||
"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/",
|
||||
"perf": "./scripts/perf_test.sh",
|
||||
"start": "babel-node scripts/http.js"
|
||||
"start": "babel-node scripts/http.js",
|
||||
"sauce": "babel-node scripts/sauce-runner.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
18
scripts/checkeol.sh
Executable file
18
scripts/checkeol.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
function checkEOL {
|
||||
local changedFiles=$(git --no-pager diff --name-only -M100% --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD)
|
||||
local result=0
|
||||
for name in $changedFiles; do
|
||||
grep -c -U -q $'\r' $name
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "windows eol found in $name" >&2
|
||||
result=1
|
||||
fi
|
||||
done
|
||||
if [ $result -eq 1 ]; then
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
checkEOL
|
||||
@@ -3,6 +3,10 @@
|
||||
NODE_INDEX="$1"
|
||||
TOTAL_NODES="$2"
|
||||
|
||||
function checkEOL {
|
||||
./scripts/checkeol.sh
|
||||
}
|
||||
|
||||
typecheck() {
|
||||
npm install -g flow-bin
|
||||
flow --version
|
||||
@@ -11,7 +15,7 @@ typecheck() {
|
||||
|
||||
lint() {
|
||||
echo "eslint $(node_modules/.bin/eslint --version)"
|
||||
npm list babel-eslint | grep babel-eslint
|
||||
npm list babel-eslint
|
||||
REPO_URL="https://raw.githubusercontent.com/ripple/javascript-style-guide"
|
||||
curl "$REPO_URL/es6/eslintrc" > ./eslintrc
|
||||
echo "parser: babel-eslint" >> ./eslintrc
|
||||
@@ -20,6 +24,7 @@ lint() {
|
||||
|
||||
unittest() {
|
||||
# test "src"
|
||||
mocha test --reporter mocha-junit-reporter --reporter-options mochaFile=$CIRCLE_TEST_REPORTS/test-results.xml
|
||||
npm test --coverage
|
||||
npm run coveralls
|
||||
|
||||
@@ -29,12 +34,33 @@ unittest() {
|
||||
mkdir -p test-compiled/node_modules
|
||||
ln -nfs ../../dist/npm test-compiled/node_modules/ripple-api
|
||||
mocha --opts test-compiled/mocha.opts test-compiled
|
||||
|
||||
#compile tests for browser testing
|
||||
#gulp build-min build-tests
|
||||
#node --harmony test-compiled/mocked-server.js > /dev/null &
|
||||
|
||||
#echo "Running tests in PhantomJS"
|
||||
#mocha-phantomjs test/localrunner.html
|
||||
#echo "Running tests using minified version in PhantomJS"
|
||||
#mocha-phantomjs test/localrunnermin.html
|
||||
|
||||
#echo "Running tests in SauceLabs"
|
||||
#http-server &
|
||||
#npm run sauce
|
||||
|
||||
#pkill -f mocked-server.js
|
||||
#pkill -f http-server
|
||||
rm -rf test-compiled
|
||||
}
|
||||
|
||||
integrationtest() {
|
||||
mocha test/integration/integration-test.js
|
||||
mocha test/integration/http-integration-test.js
|
||||
|
||||
# run integration tests in PhantomJS
|
||||
#gulp build-tests build-min
|
||||
#echo "Running integragtion tests in PhantomJS"
|
||||
#mocha-phantomjs test/localintegrationrunner.html
|
||||
}
|
||||
|
||||
doctest() {
|
||||
@@ -47,6 +73,7 @@ doctest() {
|
||||
}
|
||||
|
||||
oneNode() {
|
||||
checkEOL
|
||||
doctest
|
||||
lint
|
||||
typecheck
|
||||
@@ -57,7 +84,7 @@ oneNode() {
|
||||
twoNodes() {
|
||||
case "$NODE_INDEX" in
|
||||
0) doctest; lint; integrationtest;;
|
||||
1) typecheck; unittest;;
|
||||
1) checkEOL; typecheck; unittest;;
|
||||
*) echo "ERROR: invalid usage"; exit 2;;
|
||||
esac
|
||||
}
|
||||
@@ -65,7 +92,7 @@ twoNodes() {
|
||||
threeNodes() {
|
||||
case "$NODE_INDEX" in
|
||||
0) doctest; lint; integrationtest;;
|
||||
1) typecheck;;
|
||||
1) checkEOL; typecheck;;
|
||||
2) unittest;;
|
||||
*) echo "ERROR: invalid usage"; exit 2;;
|
||||
esac
|
||||
|
||||
@@ -16,28 +16,3 @@ echo ""
|
||||
echo "publish to npm"
|
||||
npm publish
|
||||
exit_on_error
|
||||
|
||||
rm -rf dist/bower
|
||||
echo ""
|
||||
echo "publish to bower"
|
||||
|
||||
git clone git@github.com:ripple/bower-ripple.git dist/bower
|
||||
gulp bower
|
||||
exit_on_error
|
||||
|
||||
cd dist/bower
|
||||
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc([0-9])+)?')
|
||||
echo "version: $version"
|
||||
git add ripple.js ripple-debug.js ripple-min.js bower.json
|
||||
exit_on_error
|
||||
|
||||
git commit -m "[TASK] add v$version"
|
||||
exit_on_error
|
||||
|
||||
git tag "v$version"
|
||||
exit_on_error
|
||||
|
||||
git push origin master
|
||||
git push --tags origin master
|
||||
|
||||
cd ../..
|
||||
|
||||
@@ -16,28 +16,3 @@ echo ""
|
||||
echo "publish rc to npm"
|
||||
npm publish --tag beta
|
||||
exit_on_error
|
||||
|
||||
rm -rf dist/bower
|
||||
echo ""
|
||||
echo "publish to bower"
|
||||
|
||||
git clone git@github.com:ripple/bower-ripple.git dist/bower
|
||||
gulp bower
|
||||
exit_on_error
|
||||
|
||||
cd dist/bower
|
||||
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc([0-9])+)?')
|
||||
echo "version: $version"
|
||||
git add ripple.js ripple-debug.js ripple-min.js bower.json
|
||||
exit_on_error
|
||||
|
||||
git commit -m "[TASK] add v$version"
|
||||
exit_on_error
|
||||
|
||||
git tag "v$version"
|
||||
exit_on_error
|
||||
|
||||
git push origin master
|
||||
git push --tags origin master
|
||||
|
||||
cd ../..
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
rm -rf dist/bower
|
||||
git clone git@github.com:ripple/bower-ripple.git dist/bower
|
||||
gulp bower
|
||||
cd dist/bower
|
||||
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc[0-9])?')
|
||||
echo "version: $version"
|
||||
git add ripple.js ripple-debug.js ripple-min.js bower.json
|
||||
git commit -m "[TASK] add v$version"
|
||||
git tag "v$version"
|
||||
git push origin master
|
||||
git push --tags origin master
|
||||
cd ..
|
||||
100
scripts/sauce-runner.js
Normal file
100
scripts/sauce-runner.js
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
const MochaSauce = require('mocha-in-sauce');
|
||||
|
||||
const testUrl = 'http://testripple.circleci.com:8080/test/saucerunner.html';
|
||||
|
||||
|
||||
function main() {
|
||||
// uncomment for more debug info
|
||||
// process.env.DEBUG = '*';
|
||||
|
||||
// configure
|
||||
const config = {
|
||||
name: 'RippleAPI',
|
||||
host: 'localhost',
|
||||
port: 4445,
|
||||
maxDuration: 180000,
|
||||
// the current build name (optional)
|
||||
build: Date.now(),
|
||||
url: testUrl,
|
||||
runSauceConnect: true
|
||||
};
|
||||
|
||||
if (process.env.CIRCLE_BUILD_NUM) {
|
||||
config.build = process.env.CIRCLE_BUILD_NUM;
|
||||
config.tags = [process.env.CIRCLE_BRANCH, process.env.CIRCLE_SHA1];
|
||||
config.tunnelIdentifier = process.env.CIRCLE_BUILD_NUM;
|
||||
}
|
||||
|
||||
const sauce = new MochaSauce(config);
|
||||
|
||||
sauce.concurrency(5);
|
||||
|
||||
// setup what browsers to test with
|
||||
sauce.browser({browserName: 'firefox', platform: 'Linux',
|
||||
version: '43'});
|
||||
sauce.browser({browserName: 'firefox', platform: 'Windows 8.1',
|
||||
version: '43'});
|
||||
sauce.browser({browserName: 'firefox', platform: 'OS X 10.11',
|
||||
version: '43'});
|
||||
sauce.browser({browserName: 'safari', platform: 'OS X 10.11',
|
||||
version: '9'});
|
||||
sauce.browser({browserName: 'safari', platform: 'OS X 10.10',
|
||||
version: '8'});
|
||||
sauce.browser({browserName: 'safari', platform: 'OS X 10.9',
|
||||
version: '7'});
|
||||
sauce.browser({browserName: 'chrome', platform: 'OS X 10.11',
|
||||
version: '47'});
|
||||
sauce.browser({browserName: 'chrome', platform: 'Linux',
|
||||
version: '47'});
|
||||
sauce.browser({browserName: 'chrome', platform: 'Windows 8.1',
|
||||
version: '47'});
|
||||
sauce.browser({browserName: 'internet explorer', platform: 'Windows 10',
|
||||
version: '11'});
|
||||
sauce.browser({browserName: 'MicrosoftEdge', platform: 'Windows 10',
|
||||
version: '20'});
|
||||
|
||||
sauce.on('init', function(browser) {
|
||||
console.log(' init : %s %s', browser.browserName, browser.platform);
|
||||
});
|
||||
|
||||
sauce.on('start', function(browser) {
|
||||
console.log(' start : %s %s', browser.browserName, browser.platform);
|
||||
});
|
||||
|
||||
sauce.on('end', function(browser, res) {
|
||||
console.log(' end : %s %s : %d failures', browser.browserName,
|
||||
browser.platform, res && res.failures);
|
||||
});
|
||||
|
||||
sauce.on('connected', sauceConnectProcess => {
|
||||
sauceConnectProcess.on('exit', function(code, /* signal */) {
|
||||
if (code > 0) {
|
||||
console.log('something wrong - exiting');
|
||||
process.exit();
|
||||
} else {
|
||||
console.log('normal tunnel exit');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
sauce.start(function(err, res) {
|
||||
let failure = false;
|
||||
if (err) {
|
||||
console.log('Error starting Sauce');
|
||||
console.error(err);
|
||||
process.exitCode = 2;
|
||||
} else {
|
||||
console.log('-------------- done --------------');
|
||||
failure = _.some(res, 'failures');
|
||||
console.log('Tests are failed:', failure);
|
||||
if (failure) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
10
src/api.js
10
src/api.js
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
/* eslint-disable max-len */
|
||||
// Enable core-js polyfills. This allows use of ES6/7 extensions listed here:
|
||||
@@ -44,6 +44,7 @@ const prepareSuspendedPaymentCancellation =
|
||||
require('./transaction/suspended-payment-cancellation');
|
||||
const prepareSettings = require('./transaction/settings');
|
||||
const sign = require('./transaction/sign');
|
||||
const combine = require('./transaction/combine');
|
||||
const submit = require('./transaction/submit');
|
||||
const errors = require('./common').errors;
|
||||
const generateAddress =
|
||||
@@ -88,6 +89,12 @@ class RippleAPI extends EventEmitter {
|
||||
this.connection.on('error', (errorCode, errorMessage, data) => {
|
||||
this.emit('error', errorCode, errorMessage, data);
|
||||
});
|
||||
this.connection.on('connected', () => {
|
||||
this.emit('connected');
|
||||
});
|
||||
this.connection.on('disconnected', code => {
|
||||
this.emit('disconnected', code);
|
||||
});
|
||||
} else {
|
||||
// use null object pattern to provide better error message if user
|
||||
// tries to call a method that requires a connection
|
||||
@@ -125,6 +132,7 @@ _.assign(RippleAPI.prototype, {
|
||||
prepareSuspendedPaymentCancellation,
|
||||
prepareSettings,
|
||||
sign,
|
||||
combine,
|
||||
submit,
|
||||
|
||||
generateAddress,
|
||||
|
||||
@@ -11,6 +11,9 @@ class RippleAPIBroadcast extends RippleAPI {
|
||||
_.assign({}, options, {server})
|
||||
));
|
||||
|
||||
// exposed for testing
|
||||
this._apis = apis;
|
||||
|
||||
this.getMethodNames().forEach(name => {
|
||||
this[name] = function() { // eslint-disable-line no-loop-func
|
||||
return Promise.race(apis.map(api => api[name].apply(api, arguments)));
|
||||
|
||||
21
src/common/browser-hacks.js
Normal file
21
src/common/browser-hacks.js
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
function setPrototypeOf(object, prototype) {
|
||||
// Object.setPrototypeOf not supported on Internet Explorer 9
|
||||
/* eslint-disable */
|
||||
Object.setPrototypeOf ? Object.setPrototypeOf(object, prototype) :
|
||||
object.__proto__ = prototype;
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
function getConstructorName(object) {
|
||||
// hack for internet explorer
|
||||
return process.browser ?
|
||||
object.constructor.toString().match(/^function\s+([^(]*)/)[1] :
|
||||
object.constructor.name;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getConstructorName,
|
||||
setPrototypeOf
|
||||
};
|
||||
@@ -1,11 +1,13 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const _ = require('lodash');
|
||||
const {EventEmitter} = require('events');
|
||||
const WebSocket = require('ws');
|
||||
const parseURL = require('url').parse;
|
||||
const RangeSet = require('./rangeset').RangeSet;
|
||||
const {RippledError, DisconnectedError, NotConnectedError,
|
||||
TimeoutError, ResponseFormatError, ConnectionError} = require('./errors');
|
||||
TimeoutError, ResponseFormatError, ConnectionError,
|
||||
RippledNotInitializedError} = require('./errors');
|
||||
|
||||
function isStreamMessageType(type) {
|
||||
return type === 'ledgerClosed' ||
|
||||
@@ -36,6 +38,21 @@ class Connection extends EventEmitter {
|
||||
this._ledgerVersion = null;
|
||||
this._availableLedgerVersions = new RangeSet();
|
||||
this._nextRequestID = 1;
|
||||
this._retry = 0;
|
||||
this._retryTimer = null;
|
||||
this._onOpenErrorBound = null;
|
||||
this._onUnexpectedCloseBound = null;
|
||||
}
|
||||
|
||||
_updateLedgerVersions(data) {
|
||||
this._ledgerVersion = Number(data.ledger_index);
|
||||
if (data.validated_ledgers) {
|
||||
this._availableLedgerVersions.reset();
|
||||
this._availableLedgerVersions.parseAndAddRanges(
|
||||
data.validated_ledgers);
|
||||
} else {
|
||||
this._availableLedgerVersions.addValue(this._ledgerVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// return value is array of arguments to Connection.emit
|
||||
@@ -48,10 +65,7 @@ class Connection extends EventEmitter {
|
||||
return [data.id.toString(), data];
|
||||
} else if (isStreamMessageType(data.type)) {
|
||||
if (data.type === 'ledgerClosed') {
|
||||
this._ledgerVersion = Number(data.ledger_index);
|
||||
this._availableLedgerVersions.reset();
|
||||
this._availableLedgerVersions.parseAndAddRanges(
|
||||
data.validated_ledgers);
|
||||
this._updateLedgerVersions(data);
|
||||
}
|
||||
return [data.type, data];
|
||||
} else if (data.type === undefined && data.error) {
|
||||
@@ -73,7 +87,7 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
// we don't want this inside the try/catch or exceptions in listener
|
||||
// will be caught
|
||||
this.emit.apply(this, parameters);
|
||||
this.emit(...parameters);
|
||||
}
|
||||
|
||||
get _state() {
|
||||
@@ -88,26 +102,118 @@ class Connection extends EventEmitter {
|
||||
return this._state === WebSocket.OPEN && this._isReady;
|
||||
}
|
||||
|
||||
_onUnexpectedClose() {
|
||||
_onUnexpectedClose(beforeOpen, resolve, reject, code) {
|
||||
if (this._onOpenErrorBound) {
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
}
|
||||
// just in case
|
||||
this._ws.removeAllListeners('open');
|
||||
this._ws = null;
|
||||
this._isReady = false;
|
||||
this.connect().then();
|
||||
if (beforeOpen) {
|
||||
// connection was closed before it was properly opened, so we must return
|
||||
// error to connect's caller
|
||||
this.connect().then(resolve, reject);
|
||||
} else {
|
||||
// if first parameter ws lib sends close code,
|
||||
// but sometimes it forgots about it, so default to 1006 - CLOSE_ABNORMAL
|
||||
this.emit('disconnected', code || 1006);
|
||||
this._retryConnect();
|
||||
}
|
||||
}
|
||||
|
||||
_calculateTimeout(retriesCount) {
|
||||
return (retriesCount < 40)
|
||||
// First, for 2 seconds: 20 times per second
|
||||
? (1000 / 20)
|
||||
: (retriesCount < 40 + 60)
|
||||
// Then, for 1 minute: once per second
|
||||
? (1000)
|
||||
: (retriesCount < 40 + 60 + 60)
|
||||
// Then, for 10 minutes: once every 10 seconds
|
||||
? (10 * 1000)
|
||||
// Then: once every 30 seconds
|
||||
: (30 * 1000);
|
||||
}
|
||||
|
||||
_retryConnect() {
|
||||
this._retry += 1;
|
||||
const retryTimeout = this._calculateTimeout(this._retry);
|
||||
this._retryTimer = setTimeout(() => {
|
||||
this.emit('reconnecting', this._retry);
|
||||
this.connect().catch(this._retryConnect.bind(this));
|
||||
}, retryTimeout);
|
||||
}
|
||||
|
||||
_clearReconnectTimer() {
|
||||
clearTimeout(this._retryTimer);
|
||||
this._retryTimer = null;
|
||||
}
|
||||
|
||||
_onOpen() {
|
||||
if (!this._ws) {
|
||||
return Promise.reject(new DisconnectedError());
|
||||
}
|
||||
if (this._onOpenErrorBound) {
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
}
|
||||
|
||||
const request = {
|
||||
command: 'subscribe',
|
||||
streams: ['ledger']
|
||||
};
|
||||
return this.request(request).then(response => {
|
||||
this._ledgerVersion = Number(response.ledger_index);
|
||||
this._availableLedgerVersions.parseAndAddRanges(
|
||||
response.validated_ledgers);
|
||||
return this.request(request).then(data => {
|
||||
if (_.isEmpty(data) || !data.ledger_index) {
|
||||
// rippled instance doesn't have validated ledgers
|
||||
return this._disconnect(false).then(() => {
|
||||
throw new RippledNotInitializedError('Rippled not initialized');
|
||||
});
|
||||
}
|
||||
|
||||
this._updateLedgerVersions(data);
|
||||
this._rebindOnUnxpectedClose();
|
||||
|
||||
this._retry = 0;
|
||||
this._ws.on('error', error => {
|
||||
if (process.browser && error && error.type === 'error') {
|
||||
// we are in browser, ignore error - `close` event will be fired
|
||||
// after error
|
||||
return;
|
||||
}
|
||||
this.emit('error', 'websocket', error.message, error);
|
||||
});
|
||||
|
||||
this._isReady = true;
|
||||
this.emit('connected');
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
_rebindOnUnxpectedClose() {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
}
|
||||
this._onUnexpectedCloseBound =
|
||||
this._onUnexpectedClose.bind(this, false, null, null);
|
||||
this._ws.once('close', this._onUnexpectedCloseBound);
|
||||
}
|
||||
|
||||
_unbindOnUnxpectedClose() {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
}
|
||||
this._onUnexpectedCloseBound = null;
|
||||
}
|
||||
|
||||
_onOpenError(reject, error) {
|
||||
this._onOpenErrorBound = null;
|
||||
this._unbindOnUnxpectedClose();
|
||||
reject(new NotConnectedError(error && error.message));
|
||||
}
|
||||
|
||||
_createWebSocket() {
|
||||
const options = {};
|
||||
if (this._proxyURL !== undefined) {
|
||||
@@ -142,14 +248,17 @@ class Connection extends EventEmitter {
|
||||
cert: this._certificate
|
||||
}, _.isUndefined);
|
||||
const websocketOptions = _.assign({}, options, optionsOverrides);
|
||||
const websocket = new WebSocket(this._url, websocketOptions);
|
||||
const websocket = new WebSocket(this._url, null, websocketOptions);
|
||||
// we will have a listener for each outstanding request,
|
||||
// so we have to raise the limit (the default is 10)
|
||||
websocket.setMaxListeners(Infinity);
|
||||
if (typeof websocket.setMaxListeners === 'function') {
|
||||
websocket.setMaxListeners(Infinity);
|
||||
}
|
||||
return websocket;
|
||||
}
|
||||
|
||||
connect() {
|
||||
this._clearReconnectTimer();
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._url) {
|
||||
reject(new ConnectionError(
|
||||
@@ -165,10 +274,18 @@ class Connection extends EventEmitter {
|
||||
// should still be emitted; the "ws" documentation says: "The close
|
||||
// event is also emitted when then underlying net.Socket closes the
|
||||
// connection (end or close)."
|
||||
this._ws.on('error', error =>
|
||||
this.emit('error', 'websocket', error.messsage, error));
|
||||
// In case if there is connection error (say, server is not responding)
|
||||
// we must return this error to connection's caller. After successful
|
||||
// opening, we will forward all errors to main api object.
|
||||
this._onOpenErrorBound = this._onOpenError.bind(this, reject);
|
||||
this._ws.once('error', this._onOpenErrorBound);
|
||||
this._ws.on('message', this._onMessage.bind(this));
|
||||
this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(this);
|
||||
// in browser close event can came before open event, so we must
|
||||
// resolve connect's promise after reconnect in that case.
|
||||
// after open event we will rebound _onUnexpectedCloseBound
|
||||
// without resolve and reject functions
|
||||
this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(this, true,
|
||||
resolve, reject);
|
||||
this._ws.once('close', this._onUnexpectedCloseBound);
|
||||
this._ws.once('open', () => this._onOpen().then(resolve, reject));
|
||||
}
|
||||
@@ -176,16 +293,30 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
return this._disconnect(true);
|
||||
}
|
||||
|
||||
_disconnect(calledByUser) {
|
||||
if (calledByUser) {
|
||||
this._clearReconnectTimer();
|
||||
this._retry = 0;
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
if (this._state === WebSocket.CLOSED) {
|
||||
resolve();
|
||||
} else if (this._state === WebSocket.CLOSING) {
|
||||
this._ws.once('close', resolve);
|
||||
} else {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._ws.once('close', () => {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._onUnexpectedCloseBound = null;
|
||||
}
|
||||
this._ws.once('close', code => {
|
||||
this._ws = null;
|
||||
this._isReady = false;
|
||||
if (calledByUser) {
|
||||
this.emit('disconnected', code || 1000); // 1000 - CLOSE_NORMAL
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
this._ws.close();
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const util = require('util');
|
||||
const browserHacks = require('./browser-hacks');
|
||||
|
||||
class RippleError extends Error {
|
||||
// this is needed because extending builtins doesn't work in babel 6.x
|
||||
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) {
|
||||
constructor(message, data) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
|
||||
this.name = browserHacks.getConstructorName(this);
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
Error.captureStackTrace(this, this.constructor.name);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor.name);
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
@@ -39,6 +53,8 @@ class NotConnectedError extends ConnectionError {}
|
||||
|
||||
class DisconnectedError extends ConnectionError {}
|
||||
|
||||
class RippledNotInitializedError extends ConnectionError {}
|
||||
|
||||
class TimeoutError extends ConnectionError {}
|
||||
|
||||
class ResponseFormatError extends ConnectionError {}
|
||||
@@ -71,6 +87,7 @@ module.exports = {
|
||||
RippledError,
|
||||
NotConnectedError,
|
||||
DisconnectedError,
|
||||
RippledNotInitializedError,
|
||||
TimeoutError,
|
||||
ResponseFormatError,
|
||||
ValidationError,
|
||||
|
||||
@@ -94,7 +94,8 @@ function loadSchemas() {
|
||||
require('./schemas/input/compute-ledger-hash'),
|
||||
require('./schemas/input/sign.json'),
|
||||
require('./schemas/input/submit.json'),
|
||||
require('./schemas/input/generate-address.json')
|
||||
require('./schemas/input/generate-address.json'),
|
||||
require('./schemas/input/combine.json')
|
||||
];
|
||||
const titles = _.map(schemas, schema => schema.title);
|
||||
const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1));
|
||||
|
||||
19
src/common/schemas/input/combine.json
Normal file
19
src/common/schemas/input/combine.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "combineParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"signedTransactions": {
|
||||
"type": "array",
|
||||
"description": "An array of signed transactions (from the output of [sign](#sign)) to combine.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-F0-9]+$",
|
||||
"description": "A single-signed transaction represented as an uppercase hexadecimal string (from the output of [sign](#sign))"
|
||||
},
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["signedTransactions"]
|
||||
}
|
||||
@@ -11,6 +11,17 @@
|
||||
"type": "string",
|
||||
"format": "secret",
|
||||
"description": "The secret of the account that is initiating the transaction."
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"description": "Options that control the type of signature that will be generated.",
|
||||
"properties": {
|
||||
"signAs": {
|
||||
"$ref": "address",
|
||||
"description": "The account that the signature should count for in multisigning."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "amount",
|
||||
"link": "amount",
|
||||
"description": "An Amount on the Ripple Protocol, used also for XRP in the ripple-rest API",
|
||||
"description": "An Amount on the Ripple Protocol",
|
||||
"allOf": [
|
||||
{"$ref": "amountbase"},
|
||||
{"required": ["value"]}
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
"description": "Offset from current validated legder version to highest ledger version that the transaction can be included in.",
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"signersCount": {
|
||||
"description": "Number of signers that will be signing this transaction.",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
"description": " The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
|
||||
},
|
||||
"transferRate": {
|
||||
"description": " The fee to charge when users transfer this account’s issuances, represented as billionths of a unit. Use `null` to set no fee.",
|
||||
"description": " The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.",
|
||||
"oneOf": [
|
||||
{"type": "null"},
|
||||
{"type": "number", "minimum": 1, "maximum": 4.294967295}
|
||||
@@ -68,6 +68,35 @@
|
||||
],
|
||||
"description": "The public key of a new keypair, to use as the regular key to this account, as a base-58-encoded string in the same format as an account address. Use `null` to remove the regular key."
|
||||
},
|
||||
"signers": {
|
||||
"type": "object",
|
||||
"description": "Settings that determine what sets of accounts can be used to sign a transaction on behalf of this account using multisigning.",
|
||||
"properties": {
|
||||
"threshold": {
|
||||
"$ref": "uint32",
|
||||
"description": "A target number for the signer weights. A multi-signature from this list is valid only if the sum weights of the signatures provided is equal or greater than this value. To delete the signers setting, use the value `0`."
|
||||
},
|
||||
"weights": {
|
||||
"type": "array",
|
||||
"description": "Weights of signatures for each signer.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "An association of an address and a weight.",
|
||||
"properties": {
|
||||
"address": {"$ref": "address"},
|
||||
"weight": {
|
||||
"$ref": "uint32",
|
||||
"description": "The weight that the signature of this account counts as towards the threshold."
|
||||
}
|
||||
},
|
||||
"required": ["address", "weight"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 8
|
||||
}
|
||||
}
|
||||
},
|
||||
"memos": {"$ref": "memos"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "transactionType",
|
||||
"link": "transaction-types",
|
||||
"description": "The type of the tranasction.",
|
||||
"description": "The type of the transaction.",
|
||||
"type": "string",
|
||||
"enum": ["payment", "order", "orderCancellation", "trustline", "settings",
|
||||
"suspendedPaymentCreation", "suspendedPaymentCancellation",
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
"$ref": "value",
|
||||
"description": "The XRP fee that was charged for the transaction."
|
||||
},
|
||||
"deliveredAmount": {
|
||||
"$ref": "amount",
|
||||
"description": "For payment transactions, it is impossible to reliably compute the actual delivered amount from the balanceChanges due to fixed precision. If the payment is not a partial payment and the transaction succeeded, the deliveredAmount should always be considered to be the amount specified in the transaction."
|
||||
},
|
||||
"balanceChanges": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"properties": {
|
||||
"resultCode": {
|
||||
"type": "string",
|
||||
"description": "The result code returned by rippled. [List of tranasction responses](http://pages.lightthenight.org/gba/SanFran15/ripple)"
|
||||
"description": "The result code returned by rippled. [List of transaction responses](https://ripple.com/build/transactions/#full-transaction-response-list)"
|
||||
},
|
||||
"resultMessage": {
|
||||
"type": "string",
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
"format": "date-time",
|
||||
"description": "Time after which the offer is no longer active, as an [ISO 8601 date-time](https://en.wikipedia.org/wiki/ISO_8601)."
|
||||
},
|
||||
"orderToReplace": {
|
||||
"$ref": "sequence",
|
||||
"description": "The [account sequence number](#account-sequence-number) of an order to cancel before the new order is created, effectively replacing the old order."
|
||||
},
|
||||
"memos": {"$ref": "memos"}
|
||||
},
|
||||
"required": ["direction", "quantity", "totalPrice"],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const {convertKeysFromSnakeCaseToCamelCase} = require('./utils');
|
||||
import type {Connection} from './connection';
|
||||
@@ -43,18 +43,20 @@ function getServerInfo(connection: Connection): Promise<GetServerInfoResponse> {
|
||||
return connection.request({command: 'server_info'}).then(response => {
|
||||
const info = convertKeysFromSnakeCaseToCamelCase(response.info);
|
||||
renameKeys(info, {hostid: 'hostID'});
|
||||
renameKeys(info.validatedLedger, {
|
||||
baseFeeXrp: 'baseFeeXRP',
|
||||
reserveBaseXrp: 'reserveBaseXRP',
|
||||
reserveIncXrp: 'reserveIncrementXRP',
|
||||
seq: 'ledgerVersion'
|
||||
});
|
||||
info.validatedLedger.baseFeeXRP =
|
||||
info.validatedLedger.baseFeeXRP.toString();
|
||||
info.validatedLedger.reserveBaseXRP =
|
||||
info.validatedLedger.reserveBaseXRP.toString();
|
||||
info.validatedLedger.reserveIncrementXRP =
|
||||
info.validatedLedger.reserveIncrementXRP.toString();
|
||||
if (info.validatedLedger) {
|
||||
renameKeys(info.validatedLedger, {
|
||||
baseFeeXrp: 'baseFeeXRP',
|
||||
reserveBaseXrp: 'reserveBaseXRP',
|
||||
reserveIncXrp: 'reserveIncrementXRP',
|
||||
seq: 'ledgerVersion'
|
||||
});
|
||||
info.validatedLedger.baseFeeXRP =
|
||||
info.validatedLedger.baseFeeXRP.toString();
|
||||
info.validatedLedger.reserveBaseXRP =
|
||||
info.validatedLedger.reserveBaseXRP.toString();
|
||||
info.validatedLedger.reserveIncrementXRP =
|
||||
info.validatedLedger.reserveIncrementXRP.toString();
|
||||
}
|
||||
return info;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export type RippledAmountIOU = {
|
||||
currency: string,
|
||||
value: string,
|
||||
issuer?: string
|
||||
}
|
||||
|
||||
export type RippledAmount = string | RippledAmountIOU
|
||||
|
||||
|
||||
export type Amount = {
|
||||
value: string,
|
||||
currency: string,
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
|
||||
// Amount where counterparty and value are optional
|
||||
export type LaxLaxAmount = {
|
||||
currency: string,
|
||||
value?: string,
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
// A currency-counterparty pair, or just currency if it's XRP
|
||||
export type Issue = {
|
||||
currency: string,
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
export type Adjustment = {
|
||||
address: string,
|
||||
amount: Amount,
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type MaxAdjustment = {
|
||||
address: string,
|
||||
maxAmount: Amount,
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type MinAdjustment = {
|
||||
address: string,
|
||||
minAmount: Amount,
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type Memo = {
|
||||
type?: string,
|
||||
format?: string,
|
||||
data?: string
|
||||
}
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export type RippledAmountIOU = {
|
||||
currency: string,
|
||||
value: string,
|
||||
issuer?: string
|
||||
}
|
||||
|
||||
export type RippledAmount = string | RippledAmountIOU
|
||||
|
||||
|
||||
export type Amount = {
|
||||
value: string,
|
||||
currency: string,
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
|
||||
// Amount where counterparty and value are optional
|
||||
export type LaxLaxAmount = {
|
||||
currency: string,
|
||||
value?: string,
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
// A currency-counterparty pair, or just currency if it's XRP
|
||||
export type Issue = {
|
||||
currency: string,
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
export type Adjustment = {
|
||||
address: string,
|
||||
amount: Amount,
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type MaxAdjustment = {
|
||||
address: string,
|
||||
maxAmount: Amount,
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type MinAdjustment = {
|
||||
address: string,
|
||||
minAmount: Amount,
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type Memo = {
|
||||
type?: string,
|
||||
format?: string,
|
||||
data?: string
|
||||
}
|
||||
|
||||
@@ -35,12 +35,13 @@ function toRippledAmount(amount: Amount): RippledAmount {
|
||||
};
|
||||
}
|
||||
|
||||
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g;
|
||||
function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
|
||||
if (typeof obj === 'object') {
|
||||
let newKey;
|
||||
return _.reduce(obj, (result, value, key) => {
|
||||
newKey = key;
|
||||
// taking this out of function leads to error in PhantomJS
|
||||
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g;
|
||||
if (FINDSNAKE.test(key)) {
|
||||
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase());
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ module.exports = {
|
||||
prepareSuspendedPaymentExecution: _.partial(schemaValidate,
|
||||
'prepareSuspendedPaymentExecutionParameters'),
|
||||
sign: _.partial(schemaValidate, 'signParameters'),
|
||||
combine: _.partial(schemaValidate, 'combineParameters'),
|
||||
submit: _.partial(schemaValidate, 'submitParameters'),
|
||||
computeLedgerHash: _.partial(schemaValidate, 'computeLedgerHashParameters'),
|
||||
generateAddress: _.partial(schemaValidate, 'generateAddressParameters'),
|
||||
|
||||
59
src/common/wswrapper.js
Normal file
59
src/common/wswrapper.js
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
const {EventEmitter} = require('events');
|
||||
|
||||
function unsused() {}
|
||||
|
||||
/**
|
||||
* Provides `EventEmitter` interface for native browser `WebSocket`,
|
||||
* same, as `ws` package provides.
|
||||
*/
|
||||
class WSWrapper extends EventEmitter {
|
||||
constructor(url, protocols = null, websocketOptions = {}) {
|
||||
super();
|
||||
unsused(protocols);
|
||||
unsused(websocketOptions);
|
||||
this.setMaxListeners(Infinity);
|
||||
|
||||
this._ws = new WebSocket(url);
|
||||
|
||||
this._ws.onclose = () => {
|
||||
this.emit('close');
|
||||
};
|
||||
|
||||
this._ws.onopen = () => {
|
||||
this.emit('open');
|
||||
};
|
||||
|
||||
this._ws.onerror = error => {
|
||||
this.emit('error', error);
|
||||
};
|
||||
|
||||
this._ws.onmessage = message => {
|
||||
this.emit('message', message.data);
|
||||
};
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.readyState === 1) {
|
||||
this._ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
send(message) {
|
||||
this._ws.send(message);
|
||||
}
|
||||
|
||||
get readyState() {
|
||||
return this._ws.readyState;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WSWrapper.CONNECTING = 0;
|
||||
WSWrapper.OPEN = 1;
|
||||
WSWrapper.CLOSING = 2;
|
||||
WSWrapper.CLOSED = 3;
|
||||
|
||||
module.exports = WSWrapper;
|
||||
|
||||
@@ -8,6 +8,7 @@ const jayson = require('jayson');
|
||||
const RippleAPI = require('./api').RippleAPI;
|
||||
|
||||
|
||||
/* istanbul ignore next */
|
||||
function createHTTPServer(options, httpPort) {
|
||||
const rippleAPI = new RippleAPI(options);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const utils = require('./utils');
|
||||
const flags = require('./flags').orderFlags;
|
||||
const parseAmount = require('./amount');
|
||||
@@ -31,11 +31,14 @@ function parseAccountOrder(address: string, order: Object): Object {
|
||||
expirationTime: utils.parseTimestamp(order.expiration)
|
||||
});
|
||||
|
||||
const makerExchangeRate = order.quality ?
|
||||
utils.adjustQualityForXRP(order.quality.toString(),
|
||||
takerGetsAmount.currency, takerPaysAmount.currency) :
|
||||
computeQuality(takerGetsAmount, takerPaysAmount);
|
||||
const properties = {
|
||||
maker: address,
|
||||
sequence: order.seq,
|
||||
makerExchangeRate: order.quality ? order.quality.toString()
|
||||
: computeQuality(takerGetsAmount, takerPaysAmount)
|
||||
makerExchangeRate: makerExchangeRate
|
||||
};
|
||||
|
||||
return {specification, properties};
|
||||
|
||||
9
src/ledger/parse/amendment.js
Normal file
9
src/ledger/parse/amendment.js
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
|
||||
function parseAmendment(tx: Object) {
|
||||
return {
|
||||
amendment: tx.Amendment
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = parseAmendment;
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
const utils = require('../utils');
|
||||
import type {Amount, RippledAmount} from '../../common/types.js';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ function parseAmount(amount: RippledAmount): Amount {
|
||||
if (typeof amount === 'string') {
|
||||
return {
|
||||
currency: 'XRP',
|
||||
value: utils.dropsToXrp(amount)
|
||||
value: utils.common.dropsToXrp(amount)
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
||||
15
src/ledger/parse/fee-update.js
Normal file
15
src/ledger/parse/fee-update.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const BigNumber = require('bignumber.js');
|
||||
const {dropsToXrp} = require('./utils');
|
||||
|
||||
function parseFeeUpdate(tx: Object) {
|
||||
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString();
|
||||
return {
|
||||
baseFeeXRP: dropsToXrp(baseFeeDrops),
|
||||
referenceFeeUnits: tx.ReferenceFeeUnits,
|
||||
reserveBaseXRP: dropsToXrp(tx.ReserveBase),
|
||||
reserveIncrementXRP: dropsToXrp(tx.ReserveIncrement)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = parseFeeUpdate;
|
||||
@@ -1,5 +1,6 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const AccountFields = require('./utils').constants.AccountFields;
|
||||
|
||||
@@ -22,6 +23,26 @@ function parseFields(data: Object): Object {
|
||||
settings[info.name] = parseField(info, fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.RegularKey) {
|
||||
settings.regularKey = data.RegularKey;
|
||||
}
|
||||
|
||||
// TODO: this isn't implemented in rippled yet, may have to change this later
|
||||
if (data.SignerQuorum || data.SignerEntries) {
|
||||
settings.signers = {};
|
||||
if (data.SignerQuorum) {
|
||||
settings.signers.threshold = data.SignerQuorum;
|
||||
}
|
||||
if (data.SignerEntries) {
|
||||
settings.signers.weights = _.map(data.SignerEntries, entry => {
|
||||
return {
|
||||
address: entry.SignerEntry.Account,
|
||||
weight: entry.SignerEntry.SignerWeight
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const {removeUndefined, rippleTimeToISO8601} = require('./utils');
|
||||
const parseTransaction = require('./transaction');
|
||||
import type {GetLedger} from '../types.js';
|
||||
|
||||
function parseTransactionWrapper(ledgerVersion, tx) {
|
||||
const transaction = _.assign({}, _.omit(tx, 'metaData'),
|
||||
{meta: tx.metaData});
|
||||
const transaction = _.assign({}, _.omit(tx, 'metaData'), {
|
||||
meta: tx.metaData,
|
||||
ledger_index: ledgerVersion
|
||||
});
|
||||
const result = parseTransaction(transaction);
|
||||
if (!result.outcome.ledgerVersion) {
|
||||
result.outcome.ledgerVersion = ledgerVersion;
|
||||
|
||||
@@ -6,10 +6,6 @@ const utils = require('./utils');
|
||||
const parseAmount = require('./amount');
|
||||
const txFlags = utils.txFlags;
|
||||
|
||||
function isPartialPayment(tx) {
|
||||
return (tx.Flags & txFlags.Payment.PartialPayment) !== 0;
|
||||
}
|
||||
|
||||
function isNoDirectRipple(tx) {
|
||||
return (tx.Flags & txFlags.Payment.NoRippleDirect) !== 0;
|
||||
}
|
||||
@@ -45,7 +41,7 @@ function parsePayment(tx: Object): Object {
|
||||
memos: utils.parseMemos(tx),
|
||||
invoiceID: tx.InvoiceID,
|
||||
paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined,
|
||||
allowPartialPayment: isPartialPayment(tx) || undefined,
|
||||
allowPartialPayment: utils.isPartialPayment(tx) || undefined,
|
||||
noDirectRipple: isNoDirectRipple(tx) || undefined,
|
||||
limitQuality: isQualityLimited(tx) || undefined
|
||||
});
|
||||
|
||||
@@ -52,10 +52,10 @@ function parseFlags(tx: Object) {
|
||||
|
||||
function parseSettings(tx: Object) {
|
||||
const txType = tx.TransactionType;
|
||||
assert(txType === 'AccountSet' || txType === 'SetRegularKey');
|
||||
assert(txType === 'AccountSet' || txType === 'SetRegularKey' ||
|
||||
txType === 'SignerListSet');
|
||||
|
||||
const regularKey = tx.RegularKey ? {regularKey: tx.RegularKey} : {};
|
||||
return _.assign(regularKey, parseFlags(tx), parseFields(tx));
|
||||
return _.assign({}, parseFlags(tx), parseFields(tx));
|
||||
}
|
||||
|
||||
module.exports = parseSettings;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parsePayment = require('./payment');
|
||||
@@ -11,6 +11,8 @@ const parseSuspendedPaymentCreation = require('./suspended-payment-creation');
|
||||
const parseSuspendedPaymentExecution = require('./suspended-payment-execution');
|
||||
const parseSuspendedPaymentCancellation =
|
||||
require('./suspended-payment-cancellation');
|
||||
const parseFeeUpdate = require('./fee-update');
|
||||
const parseAmendment = require('./amendment');
|
||||
|
||||
function parseTransactionType(type) {
|
||||
const mapping = {
|
||||
@@ -22,7 +24,10 @@ function parseTransactionType(type) {
|
||||
SetRegularKey: 'settings',
|
||||
SuspendedPaymentCreate: 'suspendedPaymentCreation',
|
||||
SuspendedPaymentFinish: 'suspendedPaymentExecution',
|
||||
SuspendedPaymentCancel: 'suspendedPaymentCancellation'
|
||||
SuspendedPaymentCancel: 'suspendedPaymentCancellation',
|
||||
SignerListSet: 'settings',
|
||||
SetFee: 'feeUpdate', // pseudo-transaction
|
||||
EnableAmendment: 'amendment' // pseudo-transaction
|
||||
};
|
||||
return mapping[type] || null;
|
||||
}
|
||||
@@ -37,7 +42,9 @@ function parseTransaction(tx: Object): Object {
|
||||
'settings': parseSettings,
|
||||
'suspendedPaymentCreation': parseSuspendedPaymentCreation,
|
||||
'suspendedPaymentExecution': parseSuspendedPaymentExecution,
|
||||
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation
|
||||
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation,
|
||||
'feeUpdate': parseFeeUpdate,
|
||||
'amendment': parseAmendment
|
||||
};
|
||||
const parser = mapping[type];
|
||||
assert(parser !== undefined, 'Unrecognized transaction type');
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const transactionParser = require('ripple-lib-transactionparser');
|
||||
const utils = require('../utils');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const parseAmount = require('./amount');
|
||||
|
||||
import type {Amount} from '../common/types.js';
|
||||
|
||||
function adjustQualityForXRP(
|
||||
quality: string, takerGetsCurrency: string, takerPaysCurrency: string
|
||||
@@ -35,19 +38,63 @@ function removeEmptyCounterparty(amount) {
|
||||
}
|
||||
|
||||
function removeEmptyCounterpartyInBalanceChanges(balanceChanges) {
|
||||
_.forEach(balanceChanges, (changes) => {
|
||||
_.forEach(balanceChanges, changes => {
|
||||
_.forEach(changes, removeEmptyCounterparty);
|
||||
});
|
||||
}
|
||||
|
||||
function removeEmptyCounterpartyInOrderbookChanges(orderbookChanges) {
|
||||
_.forEach(orderbookChanges, (changes) => {
|
||||
_.forEach(changes, (change) => {
|
||||
_.forEach(orderbookChanges, changes => {
|
||||
_.forEach(changes, change => {
|
||||
_.forEach(change, removeEmptyCounterparty);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isPartialPayment(tx) {
|
||||
return (tx.Flags & utils.common.txFlags.Payment.PartialPayment) !== 0;
|
||||
}
|
||||
|
||||
function parseDeliveredAmount(tx: Object): Amount | void {
|
||||
|
||||
if (tx.TransactionType !== 'Payment' ||
|
||||
tx.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (tx.meta.delivered_amount &&
|
||||
tx.meta.delivered_amount === 'unavailable') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// parsable delivered_amount
|
||||
if (tx.meta.delivered_amount) {
|
||||
return parseAmount(tx.meta.delivered_amount);
|
||||
}
|
||||
|
||||
// DeliveredAmount only present on partial payments
|
||||
if (tx.meta.DeliveredAmount) {
|
||||
return parseAmount(tx.meta.DeliveredAmount);
|
||||
}
|
||||
|
||||
// no partial payment flag, use tx.Amount
|
||||
if (tx.Amount && !isPartialPayment(tx)) {
|
||||
return parseAmount(tx.Amount);
|
||||
}
|
||||
|
||||
// DeliveredAmount field was introduced at
|
||||
// ledger 4594095 - after that point its absence
|
||||
// on a tx flagged as partial payment indicates
|
||||
// the full amount was transferred. The amount
|
||||
// transferred with a partial payment before
|
||||
// that date must be derived from metadata.
|
||||
if (tx.Amount && tx.ledger_index > 4594094) {
|
||||
return parseAmount(tx.Amount);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseOutcome(tx: Object): ?Object {
|
||||
const metadata = tx.meta || tx.metaData;
|
||||
if (!metadata) {
|
||||
@@ -58,15 +105,16 @@ function parseOutcome(tx: Object): ?Object {
|
||||
removeEmptyCounterpartyInBalanceChanges(balanceChanges);
|
||||
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges);
|
||||
|
||||
return {
|
||||
return utils.common.removeUndefined({
|
||||
result: tx.meta.TransactionResult,
|
||||
timestamp: parseTimestamp(tx.date),
|
||||
fee: utils.common.dropsToXrp(tx.Fee),
|
||||
balanceChanges: balanceChanges,
|
||||
orderbookChanges: orderbookChanges,
|
||||
ledgerVersion: tx.ledger_index,
|
||||
indexInLedger: tx.meta.TransactionIndex
|
||||
};
|
||||
indexInLedger: tx.meta.TransactionIndex,
|
||||
deliveredAmount: parseDeliveredAmount(tx)
|
||||
});
|
||||
}
|
||||
|
||||
function hexToString(hex: string): ?string {
|
||||
@@ -77,7 +125,7 @@ function parseMemos(tx: Object): ?Array<Object> {
|
||||
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return tx.Memos.map((m) => {
|
||||
return tx.Memos.map(m => {
|
||||
return utils.common.removeUndefined({
|
||||
type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType),
|
||||
format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat),
|
||||
@@ -93,6 +141,7 @@ module.exports = {
|
||||
hexToString,
|
||||
parseTimestamp,
|
||||
adjustQualityForXRP,
|
||||
isPartialPayment,
|
||||
dropsToXrp: utils.common.dropsToXrp,
|
||||
constants: utils.common.constants,
|
||||
txFlags: utils.common.txFlags,
|
||||
|
||||
@@ -85,6 +85,20 @@ function conditionallyAddDirectXRPPath(connection: Connection, address: string,
|
||||
xrpBalance => addDirectXrpPath(paths, xrpBalance));
|
||||
}
|
||||
|
||||
function filterSourceFundsLowPaths(pathfind: PathFind,
|
||||
paths: RippledPathsResponse
|
||||
): RippledPathsResponse {
|
||||
if (pathfind.source.amount &&
|
||||
pathfind.destination.amount.value === undefined && paths.alternatives) {
|
||||
paths.alternatives = _.filter(paths.alternatives, alt => {
|
||||
return alt.source_amount &&
|
||||
pathfind.source.amount &&
|
||||
new BigNumber(alt.source_amount.value).eq(pathfind.source.amount.value);
|
||||
});
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
||||
if (paths.alternatives && paths.alternatives.length > 0) {
|
||||
return parsePathfind(paths);
|
||||
@@ -116,7 +130,9 @@ function getPaths(pathfind: PathFind): Promise<GetPaths> {
|
||||
const address = pathfind.source.address;
|
||||
return requestPathFind(this.connection, pathfind).then(paths =>
|
||||
conditionallyAddDirectXRPPath(this.connection, address, paths)
|
||||
).then(paths => formatResponse(pathfind, paths));
|
||||
)
|
||||
.then(paths => filterSourceFundsLowPaths(pathfind, paths))
|
||||
.then(paths => formatResponse(pathfind, paths));
|
||||
}
|
||||
|
||||
module.exports = getPaths;
|
||||
|
||||
@@ -1,135 +1,135 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import type {Amount, Memo} from '../common/types.js';
|
||||
|
||||
type Outcome = {
|
||||
result: string,
|
||||
ledgerVersion: number,
|
||||
indexInLedger: number,
|
||||
fee: string,
|
||||
balanceChanges: {
|
||||
[key: string]: [{
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
}]
|
||||
},
|
||||
orderbookChanges: Object,
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
type Adjustment = {
|
||||
address: string,
|
||||
amount: {
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
},
|
||||
tag?: number
|
||||
}
|
||||
|
||||
type Trustline = {
|
||||
currency: string,
|
||||
counterparty: string,
|
||||
limit: string,
|
||||
qualityIn?: number,
|
||||
qualityOut?: number,
|
||||
ripplingDisabled?: boolean,
|
||||
authorized?: boolean,
|
||||
frozen?: boolean
|
||||
}
|
||||
|
||||
type Settings = {
|
||||
passwordSpent?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
requireAuthorization?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
noFreeze?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
defaultRipple?: boolean,
|
||||
emailHash?: string,
|
||||
messageKey?: string,
|
||||
domain?: string,
|
||||
transferRate?: number,
|
||||
regularKey?: string
|
||||
}
|
||||
|
||||
type OrderCancellation = {
|
||||
orderSequence: number
|
||||
}
|
||||
|
||||
type Payment = {
|
||||
source: Adjustment,
|
||||
destination: Adjustment,
|
||||
paths?: string,
|
||||
memos?: Array<Memo>,
|
||||
invoiceID?: string,
|
||||
allowPartialPayment?: boolean,
|
||||
noDirectRipple?: boolean,
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
type PaymentTransaction = {
|
||||
type: string,
|
||||
specification: Payment,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
passive?: boolean
|
||||
}
|
||||
|
||||
type OrderTransaction = {
|
||||
type: string,
|
||||
specification: Order,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
type OrderCancellationTransaction = {
|
||||
type: string,
|
||||
specification: OrderCancellation,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
type TrustlineTransaction = {
|
||||
type: string,
|
||||
specification: Trustline,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
type SettingsTransaction = {
|
||||
type: string,
|
||||
specification: Settings,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type TransactionOptions = {
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
|
||||
export type TransactionType = PaymentTransaction | OrderTransaction |
|
||||
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import type {Amount, Memo} from '../common/types.js';
|
||||
|
||||
type Outcome = {
|
||||
result: string,
|
||||
ledgerVersion: number,
|
||||
indexInLedger: number,
|
||||
fee: string,
|
||||
balanceChanges: {
|
||||
[key: string]: [{
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
}]
|
||||
},
|
||||
orderbookChanges: Object,
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
type Adjustment = {
|
||||
address: string,
|
||||
amount: {
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
},
|
||||
tag?: number
|
||||
}
|
||||
|
||||
type Trustline = {
|
||||
currency: string,
|
||||
counterparty: string,
|
||||
limit: string,
|
||||
qualityIn?: number,
|
||||
qualityOut?: number,
|
||||
ripplingDisabled?: boolean,
|
||||
authorized?: boolean,
|
||||
frozen?: boolean
|
||||
}
|
||||
|
||||
type Settings = {
|
||||
passwordSpent?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
requireAuthorization?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
noFreeze?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
defaultRipple?: boolean,
|
||||
emailHash?: string,
|
||||
messageKey?: string,
|
||||
domain?: string,
|
||||
transferRate?: number,
|
||||
regularKey?: string
|
||||
}
|
||||
|
||||
type OrderCancellation = {
|
||||
orderSequence: number
|
||||
}
|
||||
|
||||
type Payment = {
|
||||
source: Adjustment,
|
||||
destination: Adjustment,
|
||||
paths?: string,
|
||||
memos?: Array<Memo>,
|
||||
invoiceID?: string,
|
||||
allowPartialPayment?: boolean,
|
||||
noDirectRipple?: boolean,
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
type PaymentTransaction = {
|
||||
type: string,
|
||||
specification: Payment,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
passive?: boolean
|
||||
}
|
||||
|
||||
type OrderTransaction = {
|
||||
type: string,
|
||||
specification: Order,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
type OrderCancellationTransaction = {
|
||||
type: string,
|
||||
specification: OrderCancellation,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
type TrustlineTransaction = {
|
||||
type: string,
|
||||
specification: Trustline,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
type SettingsTransaction = {
|
||||
type: string,
|
||||
specification: Settings,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type TransactionOptions = {
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
|
||||
export type TransactionType = PaymentTransaction | OrderTransaction |
|
||||
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const parseTransaction = require('./parse/transaction');
|
||||
@@ -13,15 +13,18 @@ function attachTransactionDate(connection: Connection, tx: Object
|
||||
return Promise.resolve(tx);
|
||||
}
|
||||
|
||||
if (!tx.ledger_index) {
|
||||
const ledgerVersion = tx.ledger_index || tx.LedgerSequence;
|
||||
|
||||
if (!ledgerVersion) {
|
||||
return new Promise(() => {
|
||||
throw new errors.NotFoundError('ledger_index not found in tx');
|
||||
throw new errors.NotFoundError(
|
||||
'ledger_index and LedgerSequence not found in tx');
|
||||
});
|
||||
}
|
||||
|
||||
const request = {
|
||||
command: 'ledger',
|
||||
ledger_index: tx.ledger_index
|
||||
ledger_index: ledgerVersion
|
||||
};
|
||||
|
||||
return connection.request(request).then(data => {
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export type TrustLineSpecification = {
|
||||
currency: string,
|
||||
counterparty: string,
|
||||
limit: string,
|
||||
qualityIn?: number,
|
||||
qualityOut?: number,
|
||||
ripplingDisabled?: boolean,
|
||||
authorized?: boolean,
|
||||
frozen?: boolean
|
||||
}
|
||||
|
||||
export type Trustline = {
|
||||
specification: TrustLineSpecification,
|
||||
counterparty: {
|
||||
limit: string,
|
||||
ripplingDisabled?: boolean,
|
||||
frozen?: boolean,
|
||||
authorized?: boolean
|
||||
},
|
||||
state: {
|
||||
balance: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TrustlinesOptions = {
|
||||
counterparty?: string,
|
||||
currency?: string,
|
||||
limit?: number,
|
||||
ledgerVersion?: number
|
||||
}
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export type TrustLineSpecification = {
|
||||
currency: string,
|
||||
counterparty: string,
|
||||
limit: string,
|
||||
qualityIn?: number,
|
||||
qualityOut?: number,
|
||||
ripplingDisabled?: boolean,
|
||||
authorized?: boolean,
|
||||
frozen?: boolean
|
||||
}
|
||||
|
||||
export type Trustline = {
|
||||
specification: TrustLineSpecification,
|
||||
counterparty: {
|
||||
limit: string,
|
||||
ripplingDisabled?: boolean,
|
||||
frozen?: boolean,
|
||||
authorized?: boolean
|
||||
},
|
||||
state: {
|
||||
balance: string
|
||||
}
|
||||
}
|
||||
|
||||
export type TrustlinesOptions = {
|
||||
counterparty?: string,
|
||||
currency?: string,
|
||||
limit?: number,
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import type {Amount} from '../common/types.js';
|
||||
|
||||
export type OrdersOptions = {
|
||||
limit?: number,
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type OrderSpecification = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
// If enabled, the offer will not consume offers that exactly match it, and
|
||||
// instead becomes an Offer node in the ledger. It will still consume offers
|
||||
// that cross it.
|
||||
passive?: boolean
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
specification: OrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
makerExchangeRate: string
|
||||
}
|
||||
}
|
||||
|
||||
export type GetLedger = {
|
||||
accepted: boolean,
|
||||
closed: boolean,
|
||||
stateHash: string,
|
||||
closeTime: number,
|
||||
closeTimeResolution: number,
|
||||
closeFlags: number,
|
||||
ledgerHash: string,
|
||||
ledgerVersion: number,
|
||||
parentLedgerHash: string,
|
||||
parentCloseTime: number,
|
||||
totalDrops: string,
|
||||
transactionHash: string,
|
||||
transactions?: Array<Object>,
|
||||
rawTransactions?: string,
|
||||
transactionHashes?: Array<string>,
|
||||
rawState?: string,
|
||||
stateHashes?: Array<string>
|
||||
}
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
import type {Amount} from '../common/types.js';
|
||||
|
||||
export type OrdersOptions = {
|
||||
limit?: number,
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type OrderSpecification = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
// If enabled, the offer will not consume offers that exactly match it, and
|
||||
// instead becomes an Offer node in the ledger. It will still consume offers
|
||||
// that cross it.
|
||||
passive?: boolean
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
specification: OrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
makerExchangeRate: string
|
||||
}
|
||||
}
|
||||
|
||||
export type GetLedger = {
|
||||
accepted: boolean,
|
||||
closed: boolean,
|
||||
stateHash: string,
|
||||
closeTime: number,
|
||||
closeTimeResolution: number,
|
||||
closeFlags: number,
|
||||
ledgerHash: string,
|
||||
ledgerVersion: number,
|
||||
parentLedgerHash: string,
|
||||
parentCloseTime: number,
|
||||
totalDrops: string,
|
||||
transactionHash: string,
|
||||
transactions?: Array<Object>,
|
||||
rawTransactions?: string,
|
||||
transactionHashes?: Array<string>,
|
||||
rawState?: string,
|
||||
stateHashes?: Array<string>
|
||||
}
|
||||
|
||||
39
src/transaction/combine.js
Normal file
39
src/transaction/combine.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const binary = require('ripple-binary-codec');
|
||||
const utils = require('./utils');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const {decodeAddress} = require('ripple-address-codec');
|
||||
const {validate} = utils.common;
|
||||
const {computeBinaryTransactionHash} = require('ripple-hashes');
|
||||
|
||||
function addressToBigNumber(address) {
|
||||
const hex = (new Buffer(decodeAddress(address))).toString('hex');
|
||||
return new BigNumber(hex, 16);
|
||||
}
|
||||
|
||||
function compareSigners(a, b) {
|
||||
return addressToBigNumber(a.Signer.Account)
|
||||
.comparedTo(addressToBigNumber(b.Signer.Account));
|
||||
}
|
||||
|
||||
function combine(signedTransactions: Array<string>): Object {
|
||||
validate.combine({signedTransactions});
|
||||
|
||||
const txs = _.map(signedTransactions, binary.decode);
|
||||
const tx = _.omit(txs[0], 'Signers');
|
||||
if (!_.every(txs, _tx => _.isEqual(tx, _.omit(_tx, 'Signers')))) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
'txJSON is not the same for all signedTransactions');
|
||||
}
|
||||
const unsortedSigners = _.reduce(txs, (accumulator, _tx) =>
|
||||
accumulator.concat(_tx.Signers || []), []);
|
||||
const signers = unsortedSigners.sort(compareSigners);
|
||||
const signedTx = _.assign({}, tx, {Signers: signers});
|
||||
const signedTransaction = binary.encode(signedTx);
|
||||
const id = computeBinaryTransactionHash(signedTransaction);
|
||||
return {signedTransaction, id};
|
||||
}
|
||||
|
||||
module.exports = combine;
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const offerFlags = utils.common.txFlags.OfferCreate;
|
||||
@@ -35,6 +35,9 @@ function createOrderTransaction(account: string, order: Order): Object {
|
||||
if (order.expirationTime !== undefined) {
|
||||
txJSON.Expiration = iso8601ToRippleTime(order.expirationTime);
|
||||
}
|
||||
if (order.orderToReplace !== undefined) {
|
||||
txJSON.OfferSequence = order.orderToReplace;
|
||||
}
|
||||
if (order.memos !== undefined) {
|
||||
txJSON.Memos = _.map(order.memos, utils.convertMemo);
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
type SettingPasswordSpent = {
|
||||
passwordSpent?: boolean,
|
||||
}
|
||||
type SettingRequireDestinationTag = {
|
||||
requireDestinationTag?: boolean,
|
||||
}
|
||||
type SettingRequireAuthorization = {
|
||||
requireAuthorization?: boolean,
|
||||
}
|
||||
type SettingDisallowIncomingXRP = {
|
||||
disallowIncomingXRP?: boolean,
|
||||
}
|
||||
type SettingDisableMasterKey = {
|
||||
disableMasterKey?: boolean,
|
||||
}
|
||||
type SettingEnableTransactionIDTracking = {
|
||||
enableTransactionIDTracking?: boolean,
|
||||
}
|
||||
type SettingNoFreeze = {
|
||||
noFreeze?: boolean,
|
||||
}
|
||||
type SettingGlobalFreeze = {
|
||||
globalFreeze?: boolean,
|
||||
}
|
||||
type SettingDefaultRipple = {
|
||||
defaultRipple?: boolean,
|
||||
}
|
||||
type SettingEmailHash = {
|
||||
emailHash?: ?string,
|
||||
}
|
||||
type SettingMessageKey = {
|
||||
messageKey?: string,
|
||||
}
|
||||
type SettingDomain = {
|
||||
domain?: string,
|
||||
}
|
||||
type SettingTransferRate = {
|
||||
transferRate?: ?number,
|
||||
}
|
||||
type SettingRegularKey = {
|
||||
regularKey?: string
|
||||
}
|
||||
|
||||
export type Settings = SettingRegularKey |
|
||||
SettingTransferRate | SettingDomain | SettingMessageKey |
|
||||
SettingEmailHash | SettingDefaultRipple |
|
||||
SettingGlobalFreeze | SettingNoFreeze | SettingEnableTransactionIDTracking |
|
||||
SettingDisableMasterKey | SettingDisallowIncomingXRP |
|
||||
SettingRequireAuthorization | SettingRequireDestinationTag |
|
||||
SettingPasswordSpent
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
type SettingPasswordSpent = {
|
||||
passwordSpent?: boolean,
|
||||
}
|
||||
type SettingRequireDestinationTag = {
|
||||
requireDestinationTag?: boolean,
|
||||
}
|
||||
type SettingRequireAuthorization = {
|
||||
requireAuthorization?: boolean,
|
||||
}
|
||||
type SettingDisallowIncomingXRP = {
|
||||
disallowIncomingXRP?: boolean,
|
||||
}
|
||||
type SettingDisableMasterKey = {
|
||||
disableMasterKey?: boolean,
|
||||
}
|
||||
type SettingEnableTransactionIDTracking = {
|
||||
enableTransactionIDTracking?: boolean,
|
||||
}
|
||||
type SettingNoFreeze = {
|
||||
noFreeze?: boolean,
|
||||
}
|
||||
type SettingGlobalFreeze = {
|
||||
globalFreeze?: boolean,
|
||||
}
|
||||
type SettingDefaultRipple = {
|
||||
defaultRipple?: boolean,
|
||||
}
|
||||
type SettingEmailHash = {
|
||||
emailHash?: ?string,
|
||||
}
|
||||
type SettingMessageKey = {
|
||||
messageKey?: string,
|
||||
}
|
||||
type SettingDomain = {
|
||||
domain?: string,
|
||||
}
|
||||
type SettingTransferRate = {
|
||||
transferRate?: ?number,
|
||||
}
|
||||
type SettingRegularKey = {
|
||||
regularKey?: string
|
||||
}
|
||||
|
||||
export type Settings = SettingRegularKey |
|
||||
SettingTransferRate | SettingDomain | SettingMessageKey |
|
||||
SettingEmailHash | SettingDefaultRipple |
|
||||
SettingGlobalFreeze | SettingNoFreeze | SettingEnableTransactionIDTracking |
|
||||
SettingDisableMasterKey | SettingDisallowIncomingXRP |
|
||||
SettingRequireAuthorization | SettingRequireDestinationTag |
|
||||
SettingPasswordSpent
|
||||
|
||||
@@ -70,7 +70,17 @@ function convertTransferRate(transferRate: number | string): number | string {
|
||||
return (new BigNumber(transferRate)).shift(9).toNumber();
|
||||
}
|
||||
|
||||
function createSettingsTransaction(account: string, settings: Settings
|
||||
function formatSignerEntry(signer: Object): Object {
|
||||
return {
|
||||
SignerEntry: {
|
||||
Account: signer.address,
|
||||
SignerWeight: signer.weight
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createSettingsTransactionWithoutMemos(
|
||||
account: string, settings: Settings
|
||||
): Object {
|
||||
if (settings.regularKey !== undefined) {
|
||||
const removeRegularKey = {
|
||||
@@ -83,15 +93,20 @@ function createSettingsTransaction(account: string, settings: Settings
|
||||
return _.assign({}, removeRegularKey, {RegularKey: settings.regularKey});
|
||||
}
|
||||
|
||||
if (settings.signers !== undefined) {
|
||||
return {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: account,
|
||||
SignerQuorum: settings.signers.threshold,
|
||||
SignerEntries: _.map(settings.signers.weights, formatSignerEntry)
|
||||
};
|
||||
}
|
||||
|
||||
const txJSON: Object = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: account
|
||||
};
|
||||
|
||||
if (settings.memos !== undefined) {
|
||||
txJSON.Memos = _.map(settings.memos, utils.convertMemo);
|
||||
}
|
||||
|
||||
setTransactionFlags(txJSON, _.omit(settings, 'memos'));
|
||||
setTransactionFields(txJSON, settings);
|
||||
|
||||
@@ -101,6 +116,15 @@ function createSettingsTransaction(account: string, settings: Settings
|
||||
return txJSON;
|
||||
}
|
||||
|
||||
function createSettingsTransaction(account: string, settings: Settings
|
||||
): Object {
|
||||
const txJSON = createSettingsTransactionWithoutMemos(account, settings);
|
||||
if (settings.memos !== undefined) {
|
||||
txJSON.Memos = _.map(settings.memos, utils.convertMemo);
|
||||
}
|
||||
return txJSON;
|
||||
}
|
||||
|
||||
function prepareSettings(address: string, settings: Settings,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
|
||||
@@ -6,23 +6,38 @@ const binary = require('ripple-binary-codec');
|
||||
const {computeBinaryTransactionHash} = require('ripple-hashes');
|
||||
const validate = utils.common.validate;
|
||||
|
||||
function computeSignature(txJSON, privateKey) {
|
||||
const signingData = binary.encodeForSigning(txJSON);
|
||||
function computeSignature(tx: Object, privateKey: string, signAs: ?string) {
|
||||
const signingData = signAs ?
|
||||
binary.encodeForMultisigning(tx, signAs) : binary.encodeForSigning(tx);
|
||||
return keypairs.sign(signingData, privateKey);
|
||||
}
|
||||
|
||||
function sign(txJSON: string, secret: string
|
||||
function sign(txJSON: string, secret: string, options: Object = {}
|
||||
): {signedTransaction: string; id: string} {
|
||||
validate.sign({txJSON, secret});
|
||||
// we can't validate that the secret matches the account because
|
||||
// the secret could correspond to the regular key
|
||||
|
||||
const tx = JSON.parse(txJSON);
|
||||
const keypair = keypairs.deriveKeypair(secret);
|
||||
if (tx.SigningPubKey === undefined) {
|
||||
tx.SigningPubKey = keypair.publicKey;
|
||||
if (tx.TxnSignature || tx.Signers) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
'txJSON must not contain "TxnSignature" or "Signers" properties');
|
||||
}
|
||||
tx.TxnSignature = computeSignature(tx, keypair.privateKey);
|
||||
|
||||
const keypair = keypairs.deriveKeypair(secret);
|
||||
tx.SigningPubKey = options.signAs ? '' : keypair.publicKey;
|
||||
|
||||
if (options.signAs) {
|
||||
const signer = {
|
||||
Account: options.signAs,
|
||||
SigningPubKey: keypair.publicKey,
|
||||
TxnSignature: computeSignature(tx, keypair.privateKey, options.signAs)
|
||||
};
|
||||
tx.Signers = [{Signer: signer}];
|
||||
} else {
|
||||
tx.TxnSignature = computeSignature(tx, keypair.privateKey);
|
||||
}
|
||||
|
||||
const serialized = binary.encode(tx);
|
||||
return {
|
||||
signedTransaction: serialized,
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
|
||||
type Submit = {
|
||||
success: boolean,
|
||||
engineResult: string,
|
||||
engineResultCode: number,
|
||||
engineResultMessage?: string,
|
||||
txBlob?: string,
|
||||
txJson?: Object
|
||||
}
|
||||
import type {Submit} from './types.js';
|
||||
|
||||
function isImmediateRejection(engineResult: string): boolean {
|
||||
// note: "tel" errors mean the local server refused to process the
|
||||
@@ -20,10 +12,10 @@ function isImmediateRejection(engineResult: string): boolean {
|
||||
// if the required fee changes (this does not occur at the time of
|
||||
// this writing, but it could change in the future)
|
||||
// all other error classes can potentially result in transcation validation
|
||||
return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej');
|
||||
return _.startsWith(engineResult, 'tem');
|
||||
}
|
||||
|
||||
function formatResponse(response) {
|
||||
function formatSubmitResponse(response) {
|
||||
const data = {
|
||||
resultCode: response.engine_result,
|
||||
resultMessage: response.engine_result_message
|
||||
@@ -36,11 +28,12 @@ function formatResponse(response) {
|
||||
|
||||
function submit(signedTransaction: string): Promise<Submit> {
|
||||
validate.submit({signedTransaction});
|
||||
|
||||
const request = {
|
||||
command: 'submit',
|
||||
tx_blob: signedTransaction
|
||||
};
|
||||
return this.connection.request(request).then(formatResponse);
|
||||
return this.connection.request(request).then(formatSubmitResponse);
|
||||
}
|
||||
|
||||
module.exports = submit;
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export type Instructions = {
|
||||
sequence?: number,
|
||||
fee?: string,
|
||||
maxFee?: string,
|
||||
maxLedgerVersion?: number,
|
||||
maxLedgerVersionOffset?: number
|
||||
}
|
||||
|
||||
export type Prepare = {
|
||||
txJSON: string,
|
||||
instructions: {
|
||||
fee: string,
|
||||
sequence: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
}
|
||||
/* @flow */
|
||||
'use strict';
|
||||
|
||||
export type Instructions = {
|
||||
sequence?: number,
|
||||
fee?: string,
|
||||
maxFee?: string,
|
||||
maxLedgerVersion?: number,
|
||||
maxLedgerVersionOffset?: number,
|
||||
signersCount?: number
|
||||
}
|
||||
|
||||
export type Prepare = {
|
||||
txJSON: string,
|
||||
instructions: {
|
||||
fee: string,
|
||||
sequence: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type Submit = {
|
||||
success: boolean,
|
||||
engineResult: string,
|
||||
engineResultCode: number,
|
||||
engineResultMessage?: string,
|
||||
txBlob?: string,
|
||||
txJson?: Object
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ function setCanonicalFlag(txJSON) {
|
||||
txJSON.Flags = txJSON.Flags >>> 0;
|
||||
}
|
||||
|
||||
function scaleValue(value, multiplier) {
|
||||
return (new BigNumber(value)).times(multiplier).toString();
|
||||
}
|
||||
|
||||
function prepareTransaction(txJSON: Object, api: Object,
|
||||
instructions: Instructions
|
||||
): Promise<Prepare> {
|
||||
@@ -51,8 +55,10 @@ function prepareTransaction(txJSON: Object, api: Object,
|
||||
}
|
||||
|
||||
function prepareFee(): Promise<Object> {
|
||||
const multiplier = instructions.signersCount === undefined ? 1 :
|
||||
instructions.signersCount + 1;
|
||||
if (instructions.fee !== undefined) {
|
||||
txJSON.Fee = common.xrpToDrops(instructions.fee);
|
||||
txJSON.Fee = scaleValue(common.xrpToDrops(instructions.fee), multiplier);
|
||||
return Promise.resolve(txJSON);
|
||||
}
|
||||
const cushion = api._feeCushion;
|
||||
@@ -60,9 +66,10 @@ function prepareTransaction(txJSON: Object, api: Object,
|
||||
const feeDrops = common.xrpToDrops(fee);
|
||||
if (instructions.maxFee !== undefined) {
|
||||
const maxFeeDrops = common.xrpToDrops(instructions.maxFee);
|
||||
txJSON.Fee = BigNumber.min(feeDrops, maxFeeDrops).toString();
|
||||
const normalFee = BigNumber.min(feeDrops, maxFeeDrops).toString();
|
||||
txJSON.Fee = scaleValue(normalFee, multiplier);
|
||||
} else {
|
||||
txJSON.Fee = feeDrops;
|
||||
txJSON.Fee = scaleValue(feeDrops, multiplier);
|
||||
}
|
||||
return txJSON;
|
||||
});
|
||||
|
||||
133
test/api-test.js
133
test/api-test.js
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert-diff');
|
||||
const setupAPI = require('./setup-api');
|
||||
@@ -14,8 +14,12 @@ const address = addresses.ACCOUNT;
|
||||
const utils = RippleAPI._PRIVATE.ledgerUtils;
|
||||
const ledgerClosed = require('./fixtures/rippled/ledger-close-newer');
|
||||
const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
|
||||
const binary = require('ripple-binary-codec');
|
||||
assert.options.strict = true;
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = process.browser ? 25000 : 10000;
|
||||
|
||||
function unused() {
|
||||
}
|
||||
|
||||
@@ -37,6 +41,7 @@ function checkResult(expected, schemaName, response) {
|
||||
|
||||
|
||||
describe('RippleAPI', function() {
|
||||
this.timeout(TIMEOUT);
|
||||
const instructions = {maxLedgerVersionOffset: 100};
|
||||
beforeEach(setupAPI.setup);
|
||||
afterEach(setupAPI.teardown);
|
||||
@@ -94,7 +99,7 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
|
||||
it('preparePayment with all options specified', function() {
|
||||
return this.api.getLedgerVersion().then((ver) => {
|
||||
return this.api.getLedgerVersion().then(ver => {
|
||||
const localInstructions = {
|
||||
maxLedgerVersion: ver + 100,
|
||||
fee: '0.000012'
|
||||
@@ -183,20 +188,20 @@ describe('RippleAPI', function() {
|
||||
|
||||
it('prepareSettings', function() {
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings, instructions).then(
|
||||
address, requests.prepareSettings.domain, instructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.flags, 'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - no maxLedgerVersion', function() {
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings, {maxLedgerVersion: null}).then(
|
||||
address, requests.prepareSettings.domain, {maxLedgerVersion: null}).then(
|
||||
_.partial(checkResult, responses.prepareSettings.noMaxLedgerVersion,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - no instructions', function() {
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings).then(
|
||||
address, requests.prepareSettings.domain).then(
|
||||
_.partial(
|
||||
checkResult,
|
||||
responses.prepareSettings.noInstructions,
|
||||
@@ -244,6 +249,23 @@ describe('RippleAPI', function() {
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - set signers', function() {
|
||||
const settings = requests.prepareSettings.signers;
|
||||
return this.api.prepareSettings(address, settings, instructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.signers,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - fee for multisign', function() {
|
||||
const localInstructions = _.defaults({
|
||||
signersCount: 4
|
||||
}, instructions);
|
||||
return this.api.prepareSettings(
|
||||
address, requests.prepareSettings.domain, localInstructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.flagsMultisign,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSuspendedPaymentCreation', function() {
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '0.000012'
|
||||
@@ -305,6 +327,15 @@ describe('RippleAPI', function() {
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - already signed', function() {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const result = this.api.sign(requests.sign.normal.txJSON, secret);
|
||||
assert.throws(() => {
|
||||
const tx = JSON.stringify(binary.decode(result.signedTransaction));
|
||||
this.api.sign(tx, secret);
|
||||
}, /txJSON must not contain "TxnSignature" or "Signers" properties/);
|
||||
});
|
||||
|
||||
it('sign - SuspendedPaymentExecution', function() {
|
||||
const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
const result = this.api.sign(requests.sign.suspended.txJSON, secret);
|
||||
@@ -312,6 +343,14 @@ describe('RippleAPI', function() {
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - signAs', function() {
|
||||
const txJSON = requests.sign.signAs;
|
||||
const secret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
const signature = this.api.sign(JSON.stringify(txJSON), secret,
|
||||
{signAs: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'});
|
||||
assert.deepEqual(signature, responses.sign.signAs);
|
||||
});
|
||||
|
||||
it('submit', function() {
|
||||
return this.api.submit(responses.sign.normal.signedTransaction).then(
|
||||
_.partial(checkResult, responses.submit, 'submit'));
|
||||
@@ -326,6 +365,21 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('combine', function() {
|
||||
const combined = this.api.combine(requests.combine.setDomain);
|
||||
checkResult(responses.combine.single, 'sign', combined);
|
||||
});
|
||||
|
||||
it('combine - different transactions', function() {
|
||||
const request = [requests.combine.setDomain[0]];
|
||||
const tx = binary.decode(requests.combine.setDomain[0]);
|
||||
tx.Flags = 0;
|
||||
request.push(binary.encode(tx));
|
||||
assert.throws(() => {
|
||||
this.api.combine(request);
|
||||
}, /txJSON is not the same for all signedTransactions/);
|
||||
});
|
||||
|
||||
describe('RippleAPI', function() {
|
||||
|
||||
it('getBalances', function() {
|
||||
@@ -654,6 +708,21 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransaction - amendment', function() {
|
||||
const hash =
|
||||
'A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F';
|
||||
return this.api.getTransaction(hash).then(result => {
|
||||
assert.deepEqual(result, responses.getTransaction.amendment);
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransaction - feeUpdate', function() {
|
||||
const hash =
|
||||
'C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF';
|
||||
return this.api.getTransaction(hash).then(result => {
|
||||
assert.deepEqual(result, responses.getTransaction.feeUpdate);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransactions', function() {
|
||||
@@ -914,7 +983,11 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
|
||||
it('getServerInfo - error', function() {
|
||||
this.mockRippled.returnErrorOnServerInfo = true;
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: {returnErrorOnServerInfo: true}
|
||||
}));
|
||||
|
||||
return this.api.getServerInfo().then(() => {
|
||||
assert(false, 'Should throw NetworkError');
|
||||
}).catch(error => {
|
||||
@@ -923,6 +996,19 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('getServerInfo - no validated ledger', function() {
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: {serverInfoWithoutValidated: true}
|
||||
}));
|
||||
|
||||
return this.api.getServerInfo().then(info => {
|
||||
assert.strictEqual(info.networkLedger, 'waiting');
|
||||
}).catch(error => {
|
||||
assert(false, 'Should not throw Error, got ' + String(error));
|
||||
});
|
||||
});
|
||||
|
||||
it('getFee', function() {
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '0.000012');
|
||||
@@ -1012,6 +1098,15 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('getPaths - no paths source amount', function() {
|
||||
return this.api.getPaths(requests.getPaths.NoPathsSource).then(() => {
|
||||
assert(false, 'Should throw NotFoundError');
|
||||
}).catch(error => {
|
||||
assert(error instanceof this.api.errors.NotFoundError);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('getPaths - no paths with source currencies', function() {
|
||||
const pathfind = requests.getPaths.NoPathsWithCurrencies;
|
||||
return this.api.getPaths(pathfind).then(() => {
|
||||
@@ -1035,7 +1130,7 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
|
||||
it('getLedgerVersion', function(done) {
|
||||
this.api.getLedgerVersion().then((ver) => {
|
||||
this.api.getLedgerVersion().then(ver => {
|
||||
assert.strictEqual(ver, 8819951);
|
||||
done();
|
||||
}, done);
|
||||
@@ -1076,6 +1171,28 @@ describe('RippleAPI', function() {
|
||||
_.partial(checkResult, responses.getLedger.withSettingsTx, 'getLedger'));
|
||||
});
|
||||
|
||||
it('getLedger - with partial payment', function() {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 100000
|
||||
};
|
||||
return this.api.getLedger(request).then(
|
||||
_.partial(checkResult, responses.getLedger.withPartial, 'getLedger'));
|
||||
});
|
||||
|
||||
it('getLedger - pre 2014 with partial payment', function() {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
includeAllData: true,
|
||||
ledgerVersion: 100001
|
||||
};
|
||||
return this.api.getLedger(request).then(
|
||||
_.partial(checkResult,
|
||||
responses.getLedger.pre2014withPartial,
|
||||
'getLedger'));
|
||||
});
|
||||
|
||||
it('getLedger - full, then computeLedgerHash', function() {
|
||||
const request = {
|
||||
includeTransactions: true,
|
||||
@@ -1255,7 +1372,7 @@ describe('RippleAPI - offline', function() {
|
||||
it('prepareSettings and sign', function() {
|
||||
const api = new RippleAPI();
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const settings = requests.prepareSettings;
|
||||
const settings = requests.prepareSettings.domain;
|
||||
const instructions = {
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051,
|
||||
|
||||
@@ -8,6 +8,8 @@ const ledgerClosed = require('./fixtures/rippled/ledger-close');
|
||||
const RippleAPI = require('ripple-api').RippleAPI;
|
||||
const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
|
||||
|
||||
const TIMEOUT = process.browser ? 25000 : 10000;
|
||||
|
||||
function checkResult(expected, schemaName, response) {
|
||||
if (expected.txJSON) {
|
||||
assert(response.txJSON);
|
||||
@@ -21,12 +23,15 @@ function checkResult(expected, schemaName, response) {
|
||||
}
|
||||
|
||||
describe('RippleAPIBroadcast', function() {
|
||||
this.timeout(TIMEOUT);
|
||||
beforeEach(setupAPI.setupBroadcast);
|
||||
afterEach(setupAPI.teardown);
|
||||
|
||||
it('base', function() {
|
||||
const expected = {request_server_info: 1};
|
||||
this.mocks.forEach(mock => mock.expect(_.assign({}, expected)));
|
||||
if (!process.browser) {
|
||||
this.mocks.forEach(mock => mock.expect(_.assign({}, expected)));
|
||||
}
|
||||
assert(this.api.isConnected());
|
||||
return this.api.getServerInfo().then(
|
||||
_.partial(checkResult, responses.getServerInfo, 'getServerInfo'));
|
||||
@@ -39,14 +44,16 @@ describe('RippleAPIBroadcast', function() {
|
||||
});
|
||||
const ledgerNext = _.assign({}, ledgerClosed);
|
||||
ledgerNext.ledger_index++;
|
||||
this.mocks.forEach(mock => mock.socket.send(JSON.stringify(ledgerNext)));
|
||||
|
||||
this.api._apis.forEach(api => api.connection._send(JSON.stringify({
|
||||
command: 'echo',
|
||||
data: ledgerNext
|
||||
})));
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('-- ledgerVersion', this.api.ledgerVersion);
|
||||
assert.strictEqual(gotLedger, 1);
|
||||
done();
|
||||
}, 50);
|
||||
|
||||
}, 1250);
|
||||
});
|
||||
|
||||
it('error propagation', function(done) {
|
||||
@@ -55,8 +62,10 @@ describe('RippleAPIBroadcast', function() {
|
||||
assert.strictEqual(info, 'info');
|
||||
done();
|
||||
});
|
||||
this.mocks[1].socket.send(
|
||||
JSON.stringify({error: 'type', error_message: 'info'}));
|
||||
this.api._apis[1].connection._send(JSON.stringify({
|
||||
command: 'echo',
|
||||
data: {error: 'type', error_message: 'info'}
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const net = require('net');
|
||||
@@ -7,8 +7,11 @@ const assert = require('assert-diff');
|
||||
const setupAPI = require('./setup-api');
|
||||
const RippleAPI = require('ripple-api').RippleAPI;
|
||||
const utils = RippleAPI._PRIVATE.ledgerUtils;
|
||||
const ledgerClose = require('./fixtures/rippled/ledger-close.json');
|
||||
|
||||
|
||||
const TIMEOUT = 200000; // how long before each test case times out
|
||||
|
||||
function unused() {
|
||||
}
|
||||
|
||||
@@ -26,6 +29,7 @@ function createServer() {
|
||||
}
|
||||
|
||||
describe('Connection', function() {
|
||||
this.timeout(TIMEOUT);
|
||||
beforeEach(setupAPI.setup);
|
||||
afterEach(setupAPI.teardown);
|
||||
|
||||
@@ -46,6 +50,9 @@ describe('Connection', function() {
|
||||
messages.push(message);
|
||||
}
|
||||
};
|
||||
connection._ws = {
|
||||
send: function() {}
|
||||
};
|
||||
connection._onMessage(message1);
|
||||
connection._send(message2);
|
||||
|
||||
@@ -53,11 +60,15 @@ describe('Connection', function() {
|
||||
});
|
||||
|
||||
it('with proxy', function(done) {
|
||||
createServer().then((server) => {
|
||||
if (process.browser) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
createServer().then(server => {
|
||||
const port = server.address().port;
|
||||
const expect = 'CONNECT localhost';
|
||||
server.on('connection', (socket) => {
|
||||
socket.on('data', (data) => {
|
||||
server.on('connection', socket => {
|
||||
socket.on('data', data => {
|
||||
const got = data.toString('ascii', 0, expect.length);
|
||||
assert.strictEqual(got, expect);
|
||||
server.close();
|
||||
@@ -95,10 +106,33 @@ describe('Connection', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw NotConnectedError if server not responding ', function(
|
||||
done
|
||||
) {
|
||||
if (process.browser) {
|
||||
const phantomTest = /PhantomJS/;
|
||||
if (phantomTest.test(navigator.userAgent)) {
|
||||
// inside PhantomJS this one just hangs, so skip as not very relevant
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Address where no one listens
|
||||
const connection =
|
||||
new utils.common.Connection('ws://testripple.circleci.com:129');
|
||||
connection.on('error', done);
|
||||
connection.connect().catch(error => {
|
||||
assert(error instanceof this.api.errors.NotConnectedError);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('DisconnectedError', function() {
|
||||
this.api.connection._send = function() {
|
||||
this._ws.close();
|
||||
};
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: {disconnectOnServerInfo: true}
|
||||
}));
|
||||
return this.api.getServerInfo().then(() => {
|
||||
assert(false, 'Should throw DisconnectedError');
|
||||
}).catch(error => {
|
||||
@@ -160,6 +194,114 @@ describe('Connection', function() {
|
||||
}, 1);
|
||||
});
|
||||
|
||||
describe('reconnection test', function() {
|
||||
beforeEach(function() {
|
||||
this.api.connection.__workingUrl = this.api.connection._url;
|
||||
this.api.connection.__doReturnBad = function() {
|
||||
this._url = this.__badUrl;
|
||||
const self = this;
|
||||
function onReconnect(num) {
|
||||
if (num >= 2) {
|
||||
self._url = self.__workingUrl;
|
||||
self.removeListener('reconnecting', onReconnect);
|
||||
}
|
||||
}
|
||||
this.on('reconnecting', onReconnect);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
|
||||
});
|
||||
|
||||
it('reconnect on several unexpected close', function(done) {
|
||||
if (process.browser) {
|
||||
const phantomTest = /PhantomJS/;
|
||||
if (phantomTest.test(navigator.userAgent)) {
|
||||
// inside PhantomJS this one just hangs, so skip as not very relevant
|
||||
done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.timeout(70001);
|
||||
const self = this;
|
||||
self.api.connection.__badUrl = 'ws://testripple.circleci.com:129';
|
||||
function breakConnection() {
|
||||
self.api.connection.__doReturnBad();
|
||||
self.api.connection._send(JSON.stringify({
|
||||
command: 'test_command',
|
||||
data: {disconnectIn: 10}
|
||||
}));
|
||||
}
|
||||
|
||||
let connectsCount = 0;
|
||||
let disconnectsCount = 0;
|
||||
let reconnectsCount = 0;
|
||||
let code = 0;
|
||||
this.api.connection.on('reconnecting', () => {
|
||||
reconnectsCount += 1;
|
||||
});
|
||||
this.api.connection.on('disconnected', _code => {
|
||||
code = _code;
|
||||
disconnectsCount += 1;
|
||||
});
|
||||
const num = 3;
|
||||
this.api.connection.on('connected', () => {
|
||||
connectsCount += 1;
|
||||
if (connectsCount < num) {
|
||||
breakConnection();
|
||||
}
|
||||
if (connectsCount === num) {
|
||||
if (disconnectsCount !== num) {
|
||||
done(new Error('disconnectsCount must be equal to ' + num +
|
||||
'(got ' + disconnectsCount + ' instead)'));
|
||||
} else if (reconnectsCount !== num * 2) {
|
||||
done(new Error('reconnectsCount must be equal to ' + num * 2 +
|
||||
' (got ' + reconnectsCount + ' instead)'));
|
||||
} else if (code !== 1006) {
|
||||
done(new Error('disconnect must send code 1006 (got ' + code +
|
||||
' instead)'));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
breakConnection();
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit disconnected event with code 1000 (CLOSE_NORMAL)',
|
||||
function(done
|
||||
) {
|
||||
this.api.once('disconnected', code => {
|
||||
assert.strictEqual(code, 1000);
|
||||
done();
|
||||
});
|
||||
this.api.disconnect();
|
||||
});
|
||||
|
||||
it('should emit disconnected event with code 1006 (CLOSE_ABNORMAL)',
|
||||
function(done
|
||||
) {
|
||||
this.api.once('error', error => {
|
||||
done(new Error('should not throw error, got ' + String(error)));
|
||||
});
|
||||
this.api.once('disconnected', code => {
|
||||
assert.strictEqual(code, 1006);
|
||||
done();
|
||||
});
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'test_command',
|
||||
data: {disconnectIn: 10}
|
||||
}));
|
||||
});
|
||||
|
||||
it('should emit connected event on after reconnect', function(done) {
|
||||
this.api.once('connected', done);
|
||||
this.api.connection._ws.close();
|
||||
});
|
||||
|
||||
it('Multiply connect calls', function() {
|
||||
return this.api.connect().then(() => {
|
||||
return this.api.connect();
|
||||
@@ -167,7 +309,7 @@ describe('Connection', function() {
|
||||
});
|
||||
|
||||
it('hasLedgerVersion', function() {
|
||||
return this.api.connection.hasLedgerVersion(8819951).then((result) => {
|
||||
return this.api.connection.hasLedgerVersion(8819951).then(result => {
|
||||
assert(result);
|
||||
});
|
||||
});
|
||||
@@ -261,4 +403,59 @@ describe('Connection', function() {
|
||||
|
||||
this.api.connection._onMessage(JSON.stringify({type: 'unknown'}));
|
||||
});
|
||||
|
||||
it('ledger close without validated_ledgers', function(done) {
|
||||
const message = _.omit(ledgerClose, 'validated_ledgers');
|
||||
this.api.on('ledger', function(ledger) {
|
||||
assert.strictEqual(ledger.ledgerVersion, 8819951);
|
||||
done();
|
||||
});
|
||||
this.api.connection._ws.emit('message', JSON.stringify(message));
|
||||
});
|
||||
|
||||
it('should throw RippledNotInitializedError if server does not have ' +
|
||||
'validated ledgers',
|
||||
function() {
|
||||
this.timeout(3000);
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'global_config',
|
||||
data: {returnEmptySubscribeRequest: 1}
|
||||
}));
|
||||
|
||||
const api = new RippleAPI({server: this.api.connection._url});
|
||||
return api.connect().then(() => {
|
||||
assert(false, 'Must have thrown!');
|
||||
}, error => {
|
||||
assert(error instanceof this.api.errors.RippledNotInitializedError,
|
||||
'Must throw RippledNotInitializedError, got instead ' + String(error));
|
||||
});
|
||||
});
|
||||
|
||||
it('should try to reconnect on empty subscribe response on reconnect',
|
||||
function(done) {
|
||||
this.timeout(23000);
|
||||
|
||||
this.api.on('error', error => {
|
||||
done(error || new Error('Should not emit error.'));
|
||||
});
|
||||
let disconncedCount = 0;
|
||||
this.api.on('connected', () => {
|
||||
done(disconncedCount !== 1 ?
|
||||
new Error('Wrong number of disconnects') : undefined);
|
||||
});
|
||||
this.api.on('disconnected', () => {
|
||||
disconncedCount++;
|
||||
});
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'global_config',
|
||||
data: {returnEmptySubscribeRequest: 3}
|
||||
}));
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'test_command',
|
||||
data: {disconnectIn: 10}
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
3
test/fixtures/addresses.js
vendored
3
test/fixtures/addresses.js
vendored
@@ -6,5 +6,6 @@ module.exports = {
|
||||
FOURTH_ACCOUNT: 'rJnZ4YHCUsHvQu7R6mZohevKJDHFzVD6Zr',
|
||||
ISSUER: 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM',
|
||||
NOTFOUND: 'rajTAg3hon5Lcu1RxQQPxTgHvqfhc1EaUS',
|
||||
SECRET: 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
|
||||
SECRET: 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV',
|
||||
SOURCE_LOW_FUNDS: 'rhVgDEfS1r1fLyRUZCpab4TdowZcAJwHy2'
|
||||
};
|
||||
|
||||
2
test/fixtures/requests/combine.json
vendored
Normal file
2
test/fixtures/requests/combine.json
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[ "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
|
||||
"12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1F1" ]
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"base": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw"
|
||||
},
|
||||
"counter": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
{
|
||||
"base": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw"
|
||||
},
|
||||
"counter": {
|
||||
"currency": "XRP"
|
||||
}
|
||||
}
|
||||
13
test/fixtures/requests/getpaths/no-paths-source-amount.json
vendored
Normal file
13
test/fixtures/requests/getpaths/no-paths-source-amount.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "rhVgDEfS1r1fLyRUZCpab4TdowZcAJwHy2",
|
||||
"amount": {
|
||||
"value": "1000002",
|
||||
"currency": "USD"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {"currency": "USD"}
|
||||
}
|
||||
}
|
||||
24
test/fixtures/requests/getpaths/normal.json
vendored
24
test/fixtures/requests/getpaths/normal.json
vendored
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"value": "100"
|
||||
}
|
||||
}
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"value": "100"
|
||||
}
|
||||
}
|
||||
}
|
||||
30
test/fixtures/requests/getpaths/send-all.json
vendored
30
test/fixtures/requests/getpaths/send-all.json
vendored
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "5"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"amount": {
|
||||
"currency": "USD"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "5.00"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
|
||||
"amount": {
|
||||
"currency": "USD"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
test/fixtures/requests/getpaths/usd2usd.json
vendored
38
test/fixtures/requests/getpaths/usd2usd.json
vendored
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"currencies": [
|
||||
{
|
||||
"currency": "LTC"
|
||||
},
|
||||
{
|
||||
"currency": "USD"
|
||||
}
|
||||
]
|
||||
},
|
||||
"destination": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "0.000001"
|
||||
}
|
||||
}
|
||||
{
|
||||
"source": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"currencies": [
|
||||
{
|
||||
"currency": "LTC"
|
||||
},
|
||||
{
|
||||
"currency": "USD"
|
||||
}
|
||||
]
|
||||
},
|
||||
"destination": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "0.000001"
|
||||
}
|
||||
}
|
||||
}
|
||||
24
test/fixtures/requests/getpaths/xrp2xrp.json
vendored
24
test/fixtures/requests/getpaths/xrp2xrp.json
vendored
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J"
|
||||
},
|
||||
"destination": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"value": "0.000002",
|
||||
"currency": "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"source": {
|
||||
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J"
|
||||
},
|
||||
"destination": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"value": "0.000002",
|
||||
"currency": "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
test/fixtures/requests/index.js
vendored
12
test/fixtures/requests/index.js
vendored
@@ -20,7 +20,10 @@ module.exports = {
|
||||
allOptions: require('./prepare-payment-all-options'),
|
||||
noCounterparty: require('./prepare-payment-no-counterparty')
|
||||
},
|
||||
prepareSettings: require('./prepare-settings'),
|
||||
prepareSettings: {
|
||||
domain: require('./prepare-settings'),
|
||||
signers: require('./prepare-settings-signers')
|
||||
},
|
||||
prepareSuspendedPaymentCreation: {
|
||||
normal: require('./prepare-suspended-payment-creation'),
|
||||
full: require('./prepare-suspended-payment-creation-full')
|
||||
@@ -40,7 +43,8 @@ module.exports = {
|
||||
},
|
||||
sign: {
|
||||
normal: require('./sign'),
|
||||
suspended: require('./sign-suspended.json')
|
||||
suspended: require('./sign-suspended.json'),
|
||||
signAs: require('./sign-as')
|
||||
},
|
||||
getPaths: {
|
||||
normal: require('./getpaths/normal'),
|
||||
@@ -49,6 +53,7 @@ module.exports = {
|
||||
XrpToXrpNotEnough: require('./getpaths/xrp2xrp-not-enough'),
|
||||
NotAcceptCurrency: require('./getpaths/not-accept-currency'),
|
||||
NoPaths: require('./getpaths/no-paths'),
|
||||
NoPathsSource: require('./getpaths/no-paths-source-amount'),
|
||||
NoPathsWithCurrencies: require('./getpaths/no-paths-with-currencies'),
|
||||
sendAll: require('./getpaths/send-all'),
|
||||
invalid: require('./getpaths/invalid'),
|
||||
@@ -61,5 +66,8 @@ module.exports = {
|
||||
computeLedgerHash: {
|
||||
header: require('./compute-ledger-hash'),
|
||||
transactions: require('./compute-ledger-hash-transactions')
|
||||
},
|
||||
combine: {
|
||||
setDomain: require('./combine.json')
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"value": "2"
|
||||
},
|
||||
"immediateOrCancel": true,
|
||||
"orderToReplace": 12345,
|
||||
"memos": [
|
||||
{
|
||||
"type": "test",
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"minAmount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"source": {
|
||||
"address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"minAmount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"minAmount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"allowPartialPayment": true
|
||||
}
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"minAmount": {
|
||||
"value": "0.01",
|
||||
"currency": "XRP"
|
||||
}
|
||||
},
|
||||
"allowPartialPayment": true
|
||||
}
|
||||
|
||||
19
test/fixtures/requests/prepare-settings-signers.json
vendored
Normal file
19
test/fixtures/requests/prepare-settings-signers.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"signers": {
|
||||
"threshold": 2,
|
||||
"weights": [
|
||||
{
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"weight": 1
|
||||
},
|
||||
{
|
||||
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
||||
"weight": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
8
test/fixtures/requests/sign-as.json
vendored
Normal file
8
test/fixtures/requests/sign-as.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||
"Amount": "1000000000",
|
||||
"Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"Fee": "50",
|
||||
"Sequence": 2,
|
||||
"TransactionType": "Payment"
|
||||
}
|
||||
4
test/fixtures/responses/combine.json
vendored
Normal file
4
test/fixtures/responses/combine.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"signedTransaction": "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
|
||||
"id": "8A3BFD2214B4C8271ED62648FCE9ADE4EE82EF01827CF7D1F7ED497549A368CC"
|
||||
}
|
||||
4
test/fixtures/responses/get-ledger-full.json
vendored
4
test/fixtures/responses/get-ledger-full.json
vendored
@@ -34,6 +34,10 @@
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "XRP",
|
||||
"value": "10000"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rLQBHVhFnaC5gLEkgr6HgBJJ3bgeZHg9cj": [
|
||||
{
|
||||
|
||||
79
test/fixtures/responses/get-ledger-pre2014-with-partial.json
vendored
Normal file
79
test/fixtures/responses/get-ledger-pre2014-with-partial.json
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"stateHash": "334EE5F2209538C3099E133D25725E5BFEB40A198EA7028E6317F13E95D533DF",
|
||||
"closeTime": "2016-07-07T16:53:51.000Z",
|
||||
"closeTimeResolution": 10,
|
||||
"closeFlags": 0,
|
||||
"ledgerHash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
|
||||
"ledgerVersion": 12345,
|
||||
"parentLedgerHash": "4F636662B714CD9CCE965E9C23BB2E1058A2DF496F5A2416299317AE03F1CD35",
|
||||
"parentCloseTime": "2016-07-07T16:53:50.000Z",
|
||||
"totalDrops": "99997302532397566",
|
||||
"transactionHash": "C72A2BDCB471F3AEEB917ABC6019407CAE6DA4B858903A8AB2335A0EB077125D",
|
||||
"transactions": [
|
||||
{
|
||||
"type": "payment",
|
||||
"address": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"sequence": 23295,
|
||||
"id": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
|
||||
"specification": {
|
||||
"source": {
|
||||
"address": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"maxAmount": {
|
||||
"currency": "USD",
|
||||
"value": "10",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
|
||||
"amount": {
|
||||
"currency": "USD",
|
||||
"value": "10",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"allowPartialPayment": true
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.01",
|
||||
"balanceChanges": {
|
||||
"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX": [
|
||||
{
|
||||
"currency": "XRP",
|
||||
"value": "-0.01"
|
||||
},
|
||||
{
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"currency": "USD",
|
||||
"value": "-10"
|
||||
}
|
||||
],
|
||||
"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B": [
|
||||
{
|
||||
"counterparty": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
|
||||
"currency": "USD",
|
||||
"value": "-9.980039920159681"
|
||||
},
|
||||
{
|
||||
"counterparty": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
|
||||
"currency": "USD",
|
||||
"value": "10"
|
||||
}
|
||||
],
|
||||
"rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4": [
|
||||
{
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"currency": "USD",
|
||||
"value": "9.980039920159681"
|
||||
}
|
||||
]
|
||||
},
|
||||
"orderbookChanges": {},
|
||||
"ledgerVersion": 12345,
|
||||
"indexInLedger": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"rawTransactions": "[{\"Account\":\"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX\",\"Amount\":{\"currency\":\"USD\",\"issuer\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\",\"value\":\"10\"},\"Destination\":\"rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4\",\"Fee\":\"10000\",\"Flags\":131072,\"Sequence\":23295,\"SigningPubKey\":\"02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53\",\"TransactionType\":\"Payment\",\"TxnSignature\":\"3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D\",\"hash\":\"A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A\",\"metaData\":{\"AffectedNodes\":[{\"ModifiedNode\":{\"FinalFields\":{\"Account\":\"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX\",\"Balance\":\"1930599790\",\"Flags\":0,\"OwnerCount\":2,\"Sequence\":23296},\"LedgerEntryType\":\"AccountRoot\",\"LedgerIndex\":\"267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD\",\"PreviousFields\":{\"Balance\":\"1930609790\",\"Sequence\":23295},\"PreviousTxnID\":\"0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD\",\"PreviousTxnLgrSeq\":22419806}},{\"ModifiedNode\":{\"FinalFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-9.980959751659681\"},\"Flags\":2228224,\"HighLimit\":{\"currency\":\"USD\",\"issuer\":\"rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4\",\"value\":\"1000000\"},\"HighNode\":\"0000000000000000\",\"LowLimit\":{\"currency\":\"USD\",\"issuer\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\",\"value\":\"0\"},\"LowNode\":\"0000000000000423\"},\"LedgerEntryType\":\"RippleState\",\"LedgerIndex\":\"C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5\",\"PreviousFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-0.0009198315\"}},\"PreviousTxnID\":\"2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869\",\"PreviousTxnLgrSeq\":22420532}},{\"ModifiedNode\":{\"FinalFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-276666.975959\"},\"Flags\":131072,\"HighLimit\":{\"currency\":\"USD\",\"issuer\":\"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX\",\"value\":\"1000000\"},\"HighNode\":\"0000000000000000\",\"LowLimit\":{\"currency\":\"USD\",\"issuer\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\",\"value\":\"0\"},\"LowNode\":\"00000000000002D7\"},\"LedgerEntryType\":\"RippleState\",\"LedgerIndex\":\"FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615\",\"PreviousFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-276676.975959\"}},\"PreviousTxnID\":\"BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B\",\"PreviousTxnLgrSeq\":22419307}}],\"TransactionIndex\":1,\"TransactionResult\":\"tesSUCCESS\"}}]"
|
||||
}
|
||||
354
test/fixtures/responses/get-ledger-with-partial-payment.json
vendored
Normal file
354
test/fixtures/responses/get-ledger-with-partial-payment.json
vendored
Normal file
File diff suppressed because one or more lines are too long
17
test/fixtures/responses/get-transaction-amendment.json
vendored
Normal file
17
test/fixtures/responses/get-transaction-amendment.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"type": "amendment",
|
||||
"address": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||
"sequence": 0,
|
||||
"id": "A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F",
|
||||
"specification": {
|
||||
"amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE"
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2016-05-05T16:33:30.000Z",
|
||||
"fee": "0",
|
||||
"balanceChanges": {},
|
||||
"orderbookChanges": {},
|
||||
"indexInLedger": 0
|
||||
}
|
||||
}
|
||||
21
test/fixtures/responses/get-transaction-fee-update.json
vendored
Normal file
21
test/fixtures/responses/get-transaction-fee-update.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"type": "feeUpdate",
|
||||
"address": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
|
||||
"sequence": 0,
|
||||
"id": "C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF",
|
||||
"specification": {
|
||||
"baseFeeXRP": "0.00001",
|
||||
"referenceFeeUnits": 10,
|
||||
"reserveBaseXRP": "50",
|
||||
"reserveIncrementXRP": "12.5"
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2014-08-08T16:57:50.000Z",
|
||||
"fee": "0",
|
||||
"balanceChanges": {},
|
||||
"orderbookChanges": {},
|
||||
"ledgerVersion": 3717633,
|
||||
"indexInLedger": 3
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,11 @@
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2013-03-12T23:56:50.000Z",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
|
||||
@@ -31,4 +31,4 @@
|
||||
"ledgerVersion": 14,
|
||||
"indexInLedger": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,4 @@
|
||||
"ledgerVersion": 14,
|
||||
"indexInLedger": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
test/fixtures/responses/get-transactions.json
vendored
10
test/fixtures/responses/get-transactions.json
vendored
@@ -30,6 +30,11 @@
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
@@ -122,6 +127,11 @@
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
"value": "0.001",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
},
|
||||
"balanceChanges": {
|
||||
"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo": [
|
||||
{
|
||||
|
||||
@@ -331,4 +331,4 @@
|
||||
"balance": "0"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
20
test/fixtures/responses/index.js
vendored
20
test/fixtures/responses/index.js
vendored
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict'; // eslint-disable-line strict
|
||||
|
||||
module.exports = {
|
||||
generateAddress: require('./generate-address.json'),
|
||||
@@ -43,7 +43,9 @@ module.exports = {
|
||||
suspendedPaymentExecution:
|
||||
require('./get-transaction-suspended-payment-execution.json'),
|
||||
suspendedPaymentExecutionSimple:
|
||||
require('./get-transaction-suspended-payment-execution-simple.json')
|
||||
require('./get-transaction-suspended-payment-execution-simple.json'),
|
||||
amendment: require('./get-transaction-amendment.json'),
|
||||
feeUpdate: require('./get-transaction-fee-update.json')
|
||||
},
|
||||
getTransactions: {
|
||||
normal: require('./get-transactions.json'),
|
||||
@@ -57,7 +59,9 @@ module.exports = {
|
||||
header: require('./get-ledger'),
|
||||
full: require('./get-ledger-full'),
|
||||
withSettingsTx: require('./get-ledger-with-settings-tx'),
|
||||
withStateAsHashes: require('./get-ledger-with-state-as-hashes')
|
||||
withStateAsHashes: require('./get-ledger-with-state-as-hashes'),
|
||||
withPartial: require('./get-ledger-with-partial-payment'),
|
||||
pre2014withPartial: require('./get-ledger-pre2014-with-partial')
|
||||
},
|
||||
prepareOrder: {
|
||||
buy: require('./prepare-order.json'),
|
||||
@@ -81,13 +85,15 @@ module.exports = {
|
||||
regularKey: require('./prepare-settings-regular-key.json'),
|
||||
removeRegularKey: require('./prepare-settings-remove-regular-key.json'),
|
||||
flags: require('./prepare-settings.json'),
|
||||
flagsMultisign: require('./prepare-settings-multisign.json'),
|
||||
flagSet: require('./prepare-settings-flag-set.json'),
|
||||
flagClear: require('./prepare-settings-flag-clear.json'),
|
||||
setTransferRate: require('./prepare-settings-set-transfer-rate.json'),
|
||||
fieldClear: require('./prepare-settings-field-clear.json'),
|
||||
noInstructions: require('./prepare-settings-no-instructions.json'),
|
||||
signed: require('./prepare-settings-signed.json'),
|
||||
noMaxLedgerVersion: require('./prepare-settings-no-maxledgerversion.json')
|
||||
noMaxLedgerVersion: require('./prepare-settings-no-maxledgerversion.json'),
|
||||
signers: require('./prepare-settings-signers.json')
|
||||
},
|
||||
prepareSuspendedPaymentCreation: {
|
||||
normal: require('./prepare-suspended-payment-creation'),
|
||||
@@ -108,7 +114,11 @@ module.exports = {
|
||||
},
|
||||
sign: {
|
||||
normal: require('./sign.json'),
|
||||
suspended: require('./sign-suspended.json')
|
||||
suspended: require('./sign-suspended.json'),
|
||||
signAs: require('./sign-as')
|
||||
},
|
||||
combine: {
|
||||
single: require('./combine.json')
|
||||
},
|
||||
submit: require('./submit.json'),
|
||||
ledgerEvent: require('./ledger-event.json')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"txJSON": "{\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10.1\"},\"TakerPays\":\"2000000\",\"Flags\":2148139008,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10.1\"},\"TakerPays\":\"2000000\",\"Flags\":2148139008,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23,\"OfferSequence\":12345}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user