mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-13 09:05:49 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebb64ba177 | ||
|
|
1a685e2b68 | ||
|
|
9c561885a1 | ||
|
|
612e98b198 | ||
|
|
0a41d5ccf1 | ||
|
|
ba8fe1f32c | ||
|
|
0f840876a5 | ||
|
|
ac3900b6f4 | ||
|
|
5e138b9937 | ||
|
|
82d50cd903 | ||
|
|
c5b1d4daac | ||
|
|
b4a30d49d8 | ||
|
|
229360d1b9 | ||
|
|
d627d362af | ||
|
|
7ca7a07942 | ||
|
|
09f81fa3cd | ||
|
|
b03bf9c7f1 | ||
|
|
4d696369fe | ||
|
|
bcb80ea5f5 | ||
|
|
1be2ee5875 |
@@ -36,6 +36,10 @@ Warning: Use at your own risk.
|
||||
|
||||
List of XRPL validators, nodes, and testnet validators.
|
||||
|
||||
- **[XRP Scan - XRP Ledger explorer](https://http://xrpscan.com)**
|
||||
|
||||
XRP Ledger explorer, metrics and analytics.
|
||||
|
||||
## Send and request payments
|
||||
|
||||
- **[XRP Tip Bot](https://www.xrptipbot.com/)**
|
||||
|
||||
146
Gulpfile.js
146
Gulpfile.js
@@ -6,15 +6,12 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
const gulp = require('gulp');
|
||||
const rename = require('gulp-rename');
|
||||
const webpack = require('webpack');
|
||||
const bump = require('gulp-bump');
|
||||
const argv = require('yargs').argv;
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
|
||||
var pkg = require('./package.json');
|
||||
const pkg = require('./package.json');
|
||||
|
||||
var uglifyOptions = {
|
||||
const uglifyOptions = {
|
||||
mangle: {
|
||||
reserved: ['_', 'RippleError', 'RippledError', 'UnexpectedError',
|
||||
'LedgerVersionError', 'ConnectionError', 'NotConnectedError',
|
||||
@@ -36,7 +33,7 @@ function getWebpackConfig(extension, overrides) {
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: path.join(__dirname, 'build/'),
|
||||
filename: ['ripple-', extension].join(pkg.version)
|
||||
filename: `ripple-${pkg.version}${extension}`
|
||||
},
|
||||
plugins: [
|
||||
new webpack.NormalModuleReplacementPlugin(/^ws$/, './wswrapper'),
|
||||
@@ -69,7 +66,7 @@ function getWebpackConfig(extension, overrides) {
|
||||
return _.assign({}, defaults, overrides);
|
||||
}
|
||||
|
||||
function webpackConfigForWebTest(testFileName, path) {
|
||||
function webpackConfigForWebTest(testFileName) {
|
||||
var match = testFileName.match(/\/?([^\/]*)-test.js$/);
|
||||
if (!match) {
|
||||
assert(false, 'wrong filename:' + testFileName);
|
||||
@@ -83,28 +80,13 @@ function webpackConfigForWebTest(testFileName, path) {
|
||||
entry: testFileName,
|
||||
output: {
|
||||
library: match[1].replace(/-/g, '_'),
|
||||
path: './test-compiled-for-web/' + (path ? path : ''),
|
||||
path: path.join(__dirname, 'test-compiled-for-web/'),
|
||||
filename: match[1] + '-test.js'
|
||||
}
|
||||
};
|
||||
return getWebpackConfig('.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);
|
||||
@@ -120,11 +102,22 @@ function createBuildLink(callback) {
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('build', function(callback) {
|
||||
webpack(getWebpackConfig('.js'), createBuildLink(callback));
|
||||
});
|
||||
function watch(callback) {
|
||||
gulp.watch('src/*', gulp.series(buildDebug));
|
||||
callback();
|
||||
}
|
||||
|
||||
gulp.task('build-min', function(callback) {
|
||||
function build(callback) {
|
||||
webpack(getWebpackConfig('.js'), createBuildLink(callback));
|
||||
}
|
||||
|
||||
function buildDebug(callback) {
|
||||
const webpackConfig = getWebpackConfig('-debug.js', {devtool: 'eval'});
|
||||
webpackConfig.plugins.unshift(new webpack.LoaderOptionsPlugin({debug: true}));
|
||||
webpack(webpackConfig, callback);
|
||||
}
|
||||
|
||||
function buildMin(callback) {
|
||||
const webpackConfig = getWebpackConfig('-min.js');
|
||||
webpackConfig.plugins.push(new UglifyJsPlugin({uglifyOptions}));
|
||||
webpack(webpackConfig, function() {
|
||||
@@ -132,86 +125,27 @@ gulp.task('build-min', function(callback) {
|
||||
'./build/ripple-latest-min.js');
|
||||
callback();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('build-debug', function(callback) {
|
||||
const webpackConfig = getWebpackConfig('-debug.js', {devtool: 'eval'});
|
||||
webpackConfig.plugins.unshift(new webpack.LoaderOptionsPlugin({debug: true}));
|
||||
webpack(webpackConfig, callback);
|
||||
});
|
||||
|
||||
/**
|
||||
* Generate a WebPack external for a given unavailable module which replaces
|
||||
* that module's constructor with an error-thrower
|
||||
*/
|
||||
function buildUseError(cons) {
|
||||
return ('var {<CONS>:function(){throw new Error('
|
||||
+ '"Class is unavailable in this build: <CONS>")}}')
|
||||
.replace(new RegExp('<CONS>', 'g'), cons);
|
||||
}
|
||||
|
||||
gulp.task('build-core', function(callback) {
|
||||
var configOverrides = {
|
||||
cache: false,
|
||||
entry: './src/remote.ts',
|
||||
externals: [{
|
||||
'./transaction': buildUseError('Transaction'),
|
||||
'./orderbook': buildUseError('OrderBook'),
|
||||
'./account': buildUseError('Account'),
|
||||
'./serializedobject': buildUseError('SerializedObject')
|
||||
}],
|
||||
plugins: [
|
||||
new UglifyJsPlugin()
|
||||
]
|
||||
};
|
||||
webpack(getWebpackConfig('-core.js', configOverrides), callback);
|
||||
});
|
||||
|
||||
gulp.task('bower-build', ['build'], function() {
|
||||
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
||||
.pipe(rename('ripple.js'))
|
||||
.pipe(gulp.dest('./dist/bower'));
|
||||
});
|
||||
|
||||
gulp.task('bower-build-min', ['build-min'], function() {
|
||||
return gulp.src(['./build/ripple-', '-min.js'].join(pkg.version))
|
||||
.pipe(rename('ripple-min.js'))
|
||||
.pipe(gulp.dest('./dist/bower'));
|
||||
});
|
||||
|
||||
gulp.task('bower-build-debug', ['build-debug'], function() {
|
||||
return gulp.src(['./build/ripple-', '-debug.js'].join(pkg.version))
|
||||
.pipe(rename('ripple-debug.js'))
|
||||
.pipe(gulp.dest('./dist/bower'));
|
||||
});
|
||||
|
||||
gulp.task('bower-version', function() {
|
||||
gulp.src('./dist/bower/bower.json')
|
||||
.pipe(bump({version: pkg.version}))
|
||||
.pipe(gulp.dest('./dist/bower'));
|
||||
});
|
||||
|
||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug',
|
||||
'bower-version']);
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('src/*', ['build-debug']);
|
||||
});
|
||||
|
||||
gulp.task('version-bump', function() {
|
||||
if (!argv.type) {
|
||||
throw new Error('No type found, pass it in using the --type argument');
|
||||
function buildTests(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);
|
||||
}
|
||||
|
||||
gulp.src('./package.json')
|
||||
.pipe(bump({type: argv.type}))
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
exports.watch = watch;
|
||||
exports.build = build;
|
||||
exports.buildDebug = buildDebug;
|
||||
exports.buildMin = buildMin;
|
||||
exports.buildTests = buildTests;
|
||||
|
||||
gulp.task('version-beta', function() {
|
||||
gulp.src('./package.json')
|
||||
.pipe(bump({version: pkg.version + '-beta'}))
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
gulp.task('default', ['build', 'build-debug', 'build-min']);
|
||||
exports.default = gulp.parallel(build, buildDebug, buildMin);
|
||||
|
||||
98
HISTORY.md
98
HISTORY.md
@@ -1,5 +1,103 @@
|
||||
# ripple-lib Release History
|
||||
|
||||
## 1.3.2 (2019-09-03)
|
||||
|
||||
* Export and document `rippleTimeToISO8601()` method
|
||||
* Add type for isValidAddress (fixes error TS7016, #1032)
|
||||
* Docs: update recommended Node.js version (#1031)
|
||||
|
||||
When using this release with [rippled](https://github.com/ripple/rippled), we recommend using [rippled version 1.3.1](https://github.com/ripple/rippled/releases/tag/1.3.1) or later.
|
||||
|
||||
## 1.3.1 (2019-08-26)
|
||||
|
||||
* Upgrade to gulp 4 (#1030)
|
||||
* Remove http server (unused)
|
||||
* Update dependencies
|
||||
|
||||
There are no changes in the browser version with this release. The npm package for Node.js should be slightly smaller.
|
||||
|
||||
When using this release with [rippled](https://github.com/ripple/rippled), we recommend using [rippled version 1.3.1](https://github.com/ripple/rippled/releases/tag/1.3.1).
|
||||
|
||||
## 1.3.0 (2019-08-16)
|
||||
|
||||
### Bug fixes:
|
||||
|
||||
* Breaking change: Fix `getServerInfo` (#1012)
|
||||
|
||||
Before:
|
||||
```
|
||||
{
|
||||
// ...
|
||||
"load": {
|
||||
"jobTypes": {
|
||||
"0": {"jobType": "untrustedValidation", "perSecond": 10},
|
||||
"1": {"jobType": "ledgerData", "peakTime": 2, "perSecond": 2},
|
||||
"2": {"inProgress": 1, "jobType": "clientCommand", "perSecond": 1},
|
||||
"3": {"jobType": "transaction", "perSecond": 1},
|
||||
// ...
|
||||
},
|
||||
"threads": 6
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
```
|
||||
{
|
||||
// ...
|
||||
"load": {
|
||||
"jobTypes": [
|
||||
{
|
||||
"jobType": "untrustedValidation",
|
||||
"perSecond": 8
|
||||
},
|
||||
{
|
||||
"avgTime": 2,
|
||||
"jobType": "ledgerData",
|
||||
"peakTime": 72,
|
||||
"perSecond": 2
|
||||
},
|
||||
{
|
||||
"inProgress": 1,
|
||||
"jobType": "clientCommand",
|
||||
"perSecond": 1
|
||||
},
|
||||
{
|
||||
"jobType": "transaction",
|
||||
"perSecond": 1
|
||||
},
|
||||
// ...
|
||||
],
|
||||
"threads": 6
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
* Sign method - verify accurate encoding (#1026)
|
||||
* In previous versions, the following could be encoded incorrectly:
|
||||
* Amounts of XRP with more than 6 decimal places
|
||||
* Amounts of XRP drops with any decimal places
|
||||
* In versions 1.2.5 and 1.3.0, amounts that are invalid in this way will throw an error
|
||||
* Expand `APIOptions` by extending `ConnectionOptions` (#1018, fixes #1017)
|
||||
* Fix docs for destination.address (#1011)
|
||||
|
||||
### New features:
|
||||
|
||||
* Support removing a signer list (#1021)
|
||||
* Export `setCanonicalFlag` method from `src/transaction/utils`
|
||||
|
||||
### Improvements:
|
||||
|
||||
* Clean up phrasing in schema descriptions (#1023)
|
||||
* Improve docs
|
||||
* Update dependencies
|
||||
|
||||
Since this release fixes a bug that could cause transactions to be serialized incorrectly during the signing process, it has also been simultaneously released as version 1.2.5 (patch release).
|
||||
|
||||
When using this release with [rippled](https://github.com/ripple/rippled), we recommend using [rippled version 1.3.1](https://github.com/ripple/rippled/releases/tag/1.3.1).
|
||||
|
||||
## 1.2.4 (2019-06-06)
|
||||
|
||||
* Update README.md
|
||||
|
||||
@@ -14,7 +14,7 @@ A JavaScript API for interacting with the XRP Ledger
|
||||
|
||||
## Getting Started
|
||||
|
||||
See also: [RippleAPI Beginners Guide](https://ripple.com/build/rippleapi-beginners-guide/)
|
||||
See also: [RippleAPI Beginners Guide](https://xrpl.org/get-started-with-rippleapi-for-javascript.html)
|
||||
|
||||
### Requirements
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
- [xrpToDrops](#xrptodrops)
|
||||
- [dropsToXrp](#dropstoxrp)
|
||||
- [iso8601ToRippleTime](#iso8601torippletime)
|
||||
- [rippleTimeToISO8601](#rippletimetoiso8601)
|
||||
- [txFlags](#txflags)
|
||||
- [schemaValidator](#schemavalidator)
|
||||
- [schemaValidate](#schemavalidate)
|
||||
@@ -141,7 +142,7 @@ api.connect().then(() => {
|
||||
}).catch(console.error);
|
||||
```
|
||||
|
||||
RippleAPI is designed to work in [Node.js](https://nodejs.org) version **6.11.3**. RippleAPI may work on older Node.js versions if you use [Babel](https://babeljs.io/) for [ECMAScript 6](https://babeljs.io/docs/learn-es2015/) support.
|
||||
RippleAPI is designed to work in [Node.js](https://nodejs.org) version 6 or higher. Ripple recommends Node.js v10 LTS.
|
||||
|
||||
The code samples in this documentation are written with ECMAScript 6 (ES6) features, but `RippleAPI` also works with ECMAScript 5 (ES5). Regardless of whether you use ES5 or ES6, the methods that return Promises return [ES6-style promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
|
||||
@@ -273,7 +274,7 @@ A *balance* is an amount than can have a negative value.
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
currency | [currency](#currency) | The three-character code or hexadecimal string used to denote currencies, or "drops" for the smallest unit of XRP.
|
||||
counterparty | [address](#address) | *Optional* The Ripple address of the account that owes or is owed the funds (omitted if `currency` is "XRP" or "drops")
|
||||
counterparty | [address](#address) | *Optional* The XRP Ledger address of the account that owes or is owed the funds (omitted if `currency` is "XRP" or "drops")
|
||||
value | [value](#value) | *Optional* The quantity of the currency, denoted as a string to retain floating point precision
|
||||
|
||||
# Transaction Overview
|
||||
@@ -375,15 +376,14 @@ Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
source | object | The source of the funds to be sent.
|
||||
*source.* address | [address](#address) | The address to send from.
|
||||
*source.* amount | [laxAmount](#amount) | An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field is exclusive with source.maxAmount)
|
||||
*source.* amount | [laxAmount](#amount) | An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field cannot be used with source.maxAmount)
|
||||
*source.* tag | integer | *Optional* An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.
|
||||
*source.* maxAmount | [laxAmount](#amount) | The maximum amount to send. (This field is exclusive with source.amount)
|
||||
*source.* maxAmount | [laxAmount](#amount) | The maximum amount to send. (This field cannot be used with source.amount)
|
||||
destination | object | The destination of the funds to be sent.
|
||||
*destination.* address | [address](#address) | The address to receive at.
|
||||
*destination.* address | [address](#address) | An address representing the destination of the transaction.
|
||||
*destination.* amount | [laxAmount](#amount) | An exact amount to deliver to the recipient. If the counterparty is not specified, amounts with any counterparty may be used. (This field cannot be used with `destination.minAmount`.)
|
||||
*destination.* tag | integer | *Optional* An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.
|
||||
*destination.* address | [address](#address) | The address to send to.
|
||||
*destination.* minAmount | [laxAmount](#amount) | The minimum amount to be delivered. (This field is exclusive with destination.amount)
|
||||
*destination.* minAmount | [laxAmount](#amount) | The minimum amount to be delivered. (This field cannot be used with destination.amount)
|
||||
allowPartialPayment | boolean | *Optional* If true, this payment should proceed even if the whole amount cannot be delivered due to a lack of liquidity or a lack of funds in the source account.
|
||||
invoiceID | string | *Optional* A 256-bit hash that can be used to identify a particular payment.
|
||||
limitQuality | boolean | *Optional* Only take paths where all the conversions have an input:output ratio that is equal or better than the ratio of destination.amount:source.maxAmount.
|
||||
@@ -536,7 +536,7 @@ requireAuthorization | boolean | *Optional* If set, this account must individual
|
||||
requireDestinationTag | boolean | *Optional* Requires incoming payments to specify a destination tag.
|
||||
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 | 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 | Weights of signatures for each signer.
|
||||
*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](#address) | A Ripple account address
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
@@ -1639,8 +1639,8 @@ options | object | *Optional* Options to filter the resulting transactions.
|
||||
*options.* limit | integer | *Optional* If specified, return at most this many transactions.
|
||||
*options.* maxLedgerVersion | integer | *Optional* Return only transactions in this ledger version or lower.
|
||||
*options.* maxLedgerVersion | string | *Optional* Return only transactions in this ledger version or lower.
|
||||
*options.* minLedgerVersion | integer | *Optional* Return only transactions in this ledger verion or higher.
|
||||
*options.* minLedgerVersion | string | *Optional* Return only transactions in this ledger verion or higher.
|
||||
*options.* minLedgerVersion | integer | *Optional* Return only transactions in this ledger version or higher.
|
||||
*options.* minLedgerVersion | string | *Optional* Return only transactions in this ledger version or higher.
|
||||
*options.* start | string | *Optional* If specified, this transaction will be the first transaction in the result. You cannot use `start` with `minLedgerVersion` or `maxLedgerVersion`. When `start` is specified, these ledger versions will be determined internally.
|
||||
*options.* types | array\<[transactionType](#transaction-types)\> | *Optional* Only return transactions of the specified [Transaction Types](#transaction-types).
|
||||
|
||||
@@ -2021,7 +2021,7 @@ Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
currency | [currency](#currency) | The three-character code or hexadecimal string used to denote currencies
|
||||
value | [signedValue](#value) | The balance on the trustline
|
||||
counterparty | [address](#address) | *Optional* The Ripple address of the account that owes or is owed the funds.
|
||||
counterparty | [address](#address) | *Optional* The XRP Ledger address of the account that owes or is owed the funds.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -2172,7 +2172,7 @@ Returns aggregate balances by currency plus a breakdown of assets and obligation
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#address) | The Ripple address of the account to get the balance sheet of.
|
||||
address | [address](#address) | The XRP Ledger address of the account to get the balance sheet of.
|
||||
options | object | *Optional* Options to determine how the balances will be calculated.
|
||||
*options.* excludeAddresses | array\<[address](#address)\> | *Optional* Addresses to exclude from the balance totals.
|
||||
*options.* ledgerVersion | integer | *Optional* Get the balance sheet as of this historical ledger version.
|
||||
@@ -2270,14 +2270,14 @@ Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
pathfind | object | Specification of a pathfind request.
|
||||
*pathfind.* source | object | Properties of the source of funds.
|
||||
*pathfind.source.* address | [address](#address) | The Ripple address of the account where funds will come from.
|
||||
*pathfind.source.* address | [address](#address) | The XRP Ledger address of the account where funds will come from.
|
||||
*pathfind.source.* amount | [laxAmount](#amount) | *Optional* The amount of funds to send.
|
||||
*pathfind.source.* currencies | array | *Optional* An array of currencies (with optional counterparty) that may be used in the payment paths.
|
||||
*pathfind.source.* currencies[] | object | A currency with optional counterparty.
|
||||
*pathfind.source.currencies[].* currency | [currency](#currency) | The three-character code or hexadecimal string used to denote currencies
|
||||
*pathfind.source.currencies[].* counterparty | [address](#address) | *Optional* The counterparty for the currency; if omitted any counterparty may be used.
|
||||
*pathfind.* destination | object | Properties of the destination of funds.
|
||||
*pathfind.destination.* address | [address](#address) | The address to send to.
|
||||
*pathfind.destination.* address | [address](#address) | An address representing the destination of the transaction.
|
||||
*pathfind.destination.* amount | [laxLaxAmount](#amount) | The amount to be received by the receiver (`value` may be ommitted if a source amount is specified).
|
||||
|
||||
### Return Value
|
||||
@@ -2288,15 +2288,14 @@ Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
source | object | Properties of the source of the payment.
|
||||
*source.* address | [address](#address) | The address to send from.
|
||||
*source.* amount | [laxAmount](#amount) | An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field is exclusive with source.maxAmount)
|
||||
*source.* amount | [laxAmount](#amount) | An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field cannot be used with source.maxAmount)
|
||||
*source.* tag | integer | *Optional* An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.
|
||||
*source.* maxAmount | [laxAmount](#amount) | The maximum amount to send. (This field is exclusive with source.amount)
|
||||
*source.* maxAmount | [laxAmount](#amount) | The maximum amount to send. (This field cannot be used with source.amount)
|
||||
destination | object | Properties of the destination of the payment.
|
||||
*destination.* address | [address](#address) | The address to receive at.
|
||||
*destination.* address | [address](#address) | An address representing the destination of the transaction.
|
||||
*destination.* amount | [laxAmount](#amount) | An exact amount to deliver to the recipient. If the counterparty is not specified, amounts with any counterparty may be used. (This field cannot be used with `destination.minAmount`.)
|
||||
*destination.* tag | integer | *Optional* An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.
|
||||
*destination.* address | [address](#address) | The address to send to.
|
||||
*destination.* minAmount | [laxAmount](#amount) | The minimum amount to be delivered. (This field is exclusive with destination.amount)
|
||||
*destination.* minAmount | [laxAmount](#amount) | The minimum amount to be delivered. (This field cannot be used with destination.amount)
|
||||
paths | string | The paths of trustlines and orders to use in executing the payment.
|
||||
|
||||
### Example
|
||||
@@ -2390,7 +2389,7 @@ Returns open orders for the specified account. Open orders are orders that have
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#address) | The Ripple address of the account to get open orders for.
|
||||
address | [address](#address) | The XRP Ledger address of the account to get open orders for.
|
||||
options | object | *Optional* Options that determine what orders will be returned.
|
||||
*options.* ledgerVersion | integer | *Optional* Return orders as of this historical ledger version.
|
||||
*options.* ledgerVersion | string | *Optional* Return orders as of this historical ledger version.
|
||||
@@ -3905,7 +3904,7 @@ requireAuthorization | boolean | *Optional* If set, this account must individual
|
||||
requireDestinationTag | boolean | *Optional* Requires incoming payments to specify a destination tag.
|
||||
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 | 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 | Weights of signatures for each signer.
|
||||
*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](#address) | A Ripple account address
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
@@ -5397,12 +5396,12 @@ This method can sign any of [the transaction types supported by ripple-binary-co
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
txJSON | string | Transaction represented as a JSON string in rippled format.
|
||||
keypair | object | *Optional* The private and public key of the account that is initiating the transaction. (This field is exclusive with secret).
|
||||
keypair | object | *Optional* The private and public key of the account that is initiating the transaction. (This field cannot be used with secret).
|
||||
*keypair.* privateKey | privateKey | The uppercase hexadecimal representation of the secp256k1 or Ed25519 private key.
|
||||
*keypair.* publicKey | publicKey | The uppercase hexadecimal representation of the secp256k1 or Ed25519 public key.
|
||||
options | object | *Optional* Options that control the type of signature that will be generated.
|
||||
*options.* signAs | [address](#address) | *Optional* The account that the signature should count for in multisigning.
|
||||
secret | secret string | *Optional* The secret of the account that is initiating the transaction. (This field is exclusive with keypair).
|
||||
secret | secret string | *Optional* The secret of the account that is initiating the transaction. (This field cannot be used with keypair).
|
||||
|
||||
### Return Value
|
||||
|
||||
@@ -5862,6 +5861,34 @@ api.iso8601ToRippleTime('2017-02-17T15:04:57Z');
|
||||
540659097
|
||||
```
|
||||
|
||||
## rippleTimeToISO8601
|
||||
|
||||
`rippleTimeToISO8601(rippleTime: number): string`
|
||||
|
||||
This method takes the number of seconds since the "Ripple Epoch" of January 1, 2000 (00:00 UTC) and returns a string representation of a date.
|
||||
|
||||
The Ripple Epoch is 946684800 seconds after the Unix Epoch.
|
||||
|
||||
This method is useful for interpreting timestamps returned by the rippled APIs. The rippled APIs represent time as an unsigned integer of the number of seconds since the Ripple Epoch.
|
||||
|
||||
### Parameters
|
||||
|
||||
`rippleTime`: A number of seconds since the Ripple Epoch.
|
||||
|
||||
### Return Value
|
||||
|
||||
A string representing a date and time, created by calling a `Date` object's `toISOString()` method.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
api.rippleTimeToISO8601(540659097);
|
||||
```
|
||||
|
||||
```json
|
||||
'2017-02-17T15:04:57.000Z'
|
||||
```
|
||||
|
||||
## txFlags
|
||||
|
||||
`txFlags.TRANSACTION_TYPE.FLAG`
|
||||
|
||||
@@ -26,7 +26,7 @@ api.connect().then(() => {
|
||||
}).catch(console.error);
|
||||
```
|
||||
|
||||
RippleAPI is designed to work in [Node.js](https://nodejs.org) version **6.11.3**. RippleAPI may work on older Node.js versions if you use [Babel](https://babeljs.io/) for [ECMAScript 6](https://babeljs.io/docs/learn-es2015/) support.
|
||||
RippleAPI is designed to work in [Node.js](https://nodejs.org) version 6 or higher. Ripple recommends Node.js v10 LTS.
|
||||
|
||||
The code samples in this documentation are written with ECMAScript 6 (ES6) features, but `RippleAPI` also works with ECMAScript 5 (ES5). Regardless of whether you use ES5 or ES6, the methods that return Promises return [ES6-style promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<% include computeLedgerHash.md.ejs %>
|
||||
<% include xrpToDropsAndDropsToXrp.md.ejs %>
|
||||
<% include iso8601ToRippleTime.md.ejs %>
|
||||
<% include rippleTimeToISO8601.md.ejs %>
|
||||
<% include txFlags.md.ejs %>
|
||||
<% include schemaValidator.md.ejs %>
|
||||
<% include events.md.ejs %>
|
||||
|
||||
21
package.json
21
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "1.2.4",
|
||||
"version": "1.3.2",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -17,14 +17,14 @@
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.14.85",
|
||||
"@types/lodash": "^4.14.136",
|
||||
"@types/ws": "^3.2.0",
|
||||
"bignumber.js": "^4.1.0",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"jsonschema": "1.2.2",
|
||||
"lodash": "^4.17.4",
|
||||
"ripple-address-codec": "^2.0.1",
|
||||
"ripple-binary-codec": "0.2.1",
|
||||
"ripple-address-codec": "^3.0.4",
|
||||
"ripple-binary-codec": "0.2.2",
|
||||
"ripple-hashes": "0.3.2",
|
||||
"ripple-keypairs": "^0.10.1",
|
||||
"ripple-lib-transactionparser": "0.7.1",
|
||||
@@ -36,10 +36,7 @@
|
||||
"doctoc": "^0.15.0",
|
||||
"ejs": "^2.3.4",
|
||||
"eventemitter2": "^0.4.14",
|
||||
"gulp": "^3.8.10",
|
||||
"gulp-bump": "^0.1.13",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"jayson": "^1.2.2",
|
||||
"gulp": "^4.0.2",
|
||||
"json-loader": "^0.5.2",
|
||||
"json-schema-to-markdown-table": "^0.4.0",
|
||||
"mocha": "6.1.3",
|
||||
@@ -53,22 +50,20 @@
|
||||
"tslint-eslint-rules": "^4.1.1",
|
||||
"typescript": "3.4.2",
|
||||
"uglifyjs-webpack-plugin": "^1.1.4",
|
||||
"webpack": "3.12.0",
|
||||
"yargs": "13.2.2"
|
||||
"webpack": "3.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp",
|
||||
"doctoc": "doctoc docs/index.md --title '# RippleAPI Reference' --github --maxlevel 2",
|
||||
"docgen": "node --harmony scripts/build_docs.js",
|
||||
"clean": "rm -rf dist/npm",
|
||||
"compile": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/ && tsc --build",
|
||||
"compile": "mkdir -p dist/npm/common/js && cp -r src/common/js/ dist/npm/common/js/ && mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/ && tsc --build",
|
||||
"watch": "tsc -w",
|
||||
"prepublish": "npm run clean && npm run compile && npm run build",
|
||||
"test": "TS_NODE_PROJECT=src/tsconfig.json nyc mocha --exit",
|
||||
"lint": "tslint -p ./",
|
||||
"perf": "./scripts/perf_test.sh",
|
||||
"start": "node scripts/http.js",
|
||||
"sauce": "node scripts/sauce-runner.js"
|
||||
"start": "node scripts/http.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -45,7 +45,6 @@ unittest() {
|
||||
|
||||
integrationtest() {
|
||||
mocha test/integration/integration-test.js
|
||||
mocha test/integration/http-integration-test.js
|
||||
|
||||
# run integration tests in PhantomJS
|
||||
#gulp build-tests build-min
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const createHTTPServer = require('../dist/npm/http').createHTTPServer;
|
||||
const port = 5990;
|
||||
const serverUrl = 'wss://s1.ripple.com';
|
||||
|
||||
|
||||
function main() {
|
||||
const server = createHTTPServer({server: serverUrl}, port);
|
||||
server.start().then(() => {
|
||||
console.log('Server started on port ' + String(port));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
main();
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
validate,
|
||||
xrpToDrops,
|
||||
dropsToXrp,
|
||||
rippleTimeToISO8601,
|
||||
iso8601ToRippleTime,
|
||||
txFlags
|
||||
} from './common'
|
||||
@@ -72,8 +73,9 @@ import * as schemaValidator from './common/schema-validator'
|
||||
import {getServerInfo, getFee} from './common/serverinfo'
|
||||
import {clamp, renameCounterpartyToIssuer} from './ledger/utils'
|
||||
import {TransactionJSON, Instructions, Prepare} from './transaction/types'
|
||||
import {ConnectionOptions} from './common/connection'
|
||||
|
||||
export type APIOptions = {
|
||||
export interface APIOptions extends ConnectionOptions {
|
||||
server?: string,
|
||||
feeCushion?: number,
|
||||
maxFeeXRP?: string,
|
||||
@@ -336,6 +338,7 @@ class RippleAPI extends EventEmitter {
|
||||
|
||||
xrpToDrops = xrpToDrops
|
||||
dropsToXrp = dropsToXrp
|
||||
rippleTimeToISO8601 = rippleTimeToISO8601
|
||||
iso8601ToRippleTime = iso8601ToRippleTime
|
||||
txFlags = txFlags
|
||||
|
||||
|
||||
1649
src/common/js/lodash.isequal.js
Normal file
1649
src/common/js/lodash.isequal.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ class RangeSet {
|
||||
}
|
||||
|
||||
addRange(start: number, end: number) {
|
||||
assert(start <= end, 'invalid range')
|
||||
assert(start <= end, `invalid range ${start} <= ${end}`)
|
||||
this.ranges = mergeIntervals(this.ranges.concat([[start, end]]))
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The Ripple address of the account to get the balance sheet of."
|
||||
"description": "The XRP Ledger address of the account to get the balance sheet of."
|
||||
},
|
||||
"options": {
|
||||
"properties": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The Ripple address of the account to get open orders for."
|
||||
"description": "The XRP Ledger address of the account to get open orders for."
|
||||
},
|
||||
"options": {
|
||||
"description": "Options that determine what orders will be returned.",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The Ripple address of the account where funds will come from."
|
||||
"description": "The XRP Ledger address of the account where funds will come from."
|
||||
},
|
||||
"amount": {
|
||||
"$ref": "laxAmount",
|
||||
@@ -49,7 +49,7 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address to send to."
|
||||
"description": "An address representing the destination of the transaction."
|
||||
},
|
||||
"amount": {
|
||||
"$ref": "laxLaxAmount",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"minLedgerVersion": {
|
||||
"$ref": "ledgerVersion",
|
||||
"description": "Return only transactions in this ledger verion or higher."
|
||||
"description": "Return only transactions in this ledger version or higher."
|
||||
},
|
||||
"maxLedgerVersion": {
|
||||
"$ref": "ledgerVersion",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"format": "secret",
|
||||
"description": "The secret of the account that is initiating the transaction. (This field is exclusive with keypair)."
|
||||
"description": "The secret of the account that is initiating the transaction. (This field cannot be used with keypair)."
|
||||
},
|
||||
"keypair": {
|
||||
"type": "object",
|
||||
@@ -24,7 +24,7 @@
|
||||
"description": "The uppercase hexadecimal representation of the secp256k1 or Ed25519 public key."
|
||||
}
|
||||
},
|
||||
"description": "The private and public key of the account that is initiating the transaction. (This field is exclusive with secret).",
|
||||
"description": "The private and public key of the account that is initiating the transaction. (This field cannot be used with secret).",
|
||||
"required": ["privateKey", "publicKey"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"$ref": "currency"
|
||||
},
|
||||
"counterparty": {
|
||||
"description": "The Ripple address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\" or \"drops\")",
|
||||
"description": "The XRP Ledger address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\" or \"drops\")",
|
||||
"$ref": "address"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"$ref": "currency"
|
||||
},
|
||||
"counterparty": {
|
||||
"description": "The Ripple address of the account that owes or is owed the funds.",
|
||||
"description": "The XRP Ledger address of the account that owes or is owed the funds.",
|
||||
"$ref": "address"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address to receive at."
|
||||
"description": "An address representing the destination of the transaction."
|
||||
},
|
||||
"tag": {"$ref": "tag"}
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address to receive at."
|
||||
"description": "An address representing the destination of the transaction."
|
||||
},
|
||||
"amount": {
|
||||
"$ref": "laxAmount",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"maxAmount": {
|
||||
"$ref": "laxAmount",
|
||||
"description": "The maximum amount to send. (This field is exclusive with source.amount)"
|
||||
"description": "The maximum amount to send. (This field cannot be used with source.amount)"
|
||||
},
|
||||
"tag": {"$ref": "tag"}
|
||||
},
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address to send to."
|
||||
"description": "An address representing the destination of the transaction."
|
||||
},
|
||||
"minAmount": {
|
||||
"$ref": "laxAmount",
|
||||
"description": "The minimum amount to be delivered. (This field is exclusive with destination.amount)"
|
||||
"description": "The minimum amount to be delivered. (This field cannot be used with destination.amount)"
|
||||
},
|
||||
"tag": {"$ref": "tag"}
|
||||
},
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
"maxItems": 8
|
||||
}
|
||||
},
|
||||
"required": ["threshold", "weights"],
|
||||
"required": ["threshold"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"transferRate": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"amount": {
|
||||
"$ref": "laxAmount",
|
||||
"description": "An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field is exclusive with source.maxAmount)"
|
||||
"description": "An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field cannot be used with source.maxAmount)"
|
||||
},
|
||||
"tag": {"$ref": "tag"}
|
||||
},
|
||||
|
||||
@@ -103,6 +103,7 @@ function toRippledAmount(amount: Amount): RippledAmount {
|
||||
|
||||
function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
|
||||
if (typeof obj === 'object') {
|
||||
const accumulator = Array.isArray(obj) ? [] : {}
|
||||
let newKey
|
||||
return _.reduce(obj, (result, value, key) => {
|
||||
newKey = key
|
||||
@@ -113,7 +114,7 @@ function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
|
||||
}
|
||||
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value)
|
||||
return result
|
||||
}, {})
|
||||
}, accumulator)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
84
src/http.ts
84
src/http.ts
@@ -1,84 +0,0 @@
|
||||
/* eslint-disable new-cap */
|
||||
|
||||
import * as assert from 'assert'
|
||||
import * as _ from 'lodash'
|
||||
import * as jayson from 'jayson'
|
||||
import {RippleAPI} from './api'
|
||||
|
||||
|
||||
/* istanbul ignore next */
|
||||
function createHTTPServer(options, httpPort) {
|
||||
const rippleAPI = new RippleAPI(options)
|
||||
|
||||
const methodNames = _.filter(_.keys(RippleAPI.prototype), k => {
|
||||
return typeof RippleAPI.prototype[k] === 'function'
|
||||
&& k !== 'connect'
|
||||
&& k !== 'disconnect'
|
||||
&& k !== 'constructor'
|
||||
&& k !== 'RippleAPI'
|
||||
})
|
||||
|
||||
function applyPromiseWithCallback(fnName, callback, args_) {
|
||||
try {
|
||||
let args = args_
|
||||
if (!_.isArray(args_)) {
|
||||
const fnParameters = jayson.Utils.getParameterNames(rippleAPI[fnName])
|
||||
args = fnParameters.map(name => args_[name])
|
||||
const defaultArgs = _.omit(args_, fnParameters)
|
||||
assert(_.size(defaultArgs) <= 1,
|
||||
'Function must have no more than one default argument')
|
||||
if (_.size(defaultArgs) > 0) {
|
||||
args.push(defaultArgs[_.keys(defaultArgs)[0]])
|
||||
}
|
||||
}
|
||||
Promise.resolve(rippleAPI[fnName](...args))
|
||||
.then(res => callback(null, res))
|
||||
.catch(err => {
|
||||
callback({code: 99, message: err.message, data: {name: err.name}})
|
||||
})
|
||||
} catch (err) {
|
||||
callback({code: 99, message: err.message, data: {name: err.name}})
|
||||
}
|
||||
}
|
||||
|
||||
const methods = {}
|
||||
_.forEach(methodNames, fn => {
|
||||
methods[fn] = jayson.Method((args, cb) => {
|
||||
applyPromiseWithCallback(fn, cb, args)
|
||||
}, {collect: true})
|
||||
})
|
||||
|
||||
const server = jayson.server(methods)
|
||||
let httpServer = null
|
||||
|
||||
return {
|
||||
server: server,
|
||||
start: function() {
|
||||
if (httpServer !== null) {
|
||||
return Promise.reject('Already started')
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
rippleAPI.connect().then(() => {
|
||||
httpServer = server.http()
|
||||
httpServer.listen(httpPort, resolve)
|
||||
})
|
||||
})
|
||||
},
|
||||
stop: function() {
|
||||
if (httpServer === null) {
|
||||
return Promise.reject('Not started')
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
rippleAPI.disconnect()
|
||||
httpServer.close(() => {
|
||||
httpServer = null
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
createHTTPServer
|
||||
}
|
||||
@@ -89,12 +89,17 @@ function createSettingsTransactionWithoutMemos(
|
||||
}
|
||||
|
||||
if (settings.signers !== undefined) {
|
||||
return {
|
||||
const setSignerList = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: account,
|
||||
SignerQuorum: settings.signers.threshold,
|
||||
SignerEntries: settings.signers.weights.map(formatSignerEntry)
|
||||
SignerEntries: [],
|
||||
SignerQuorum: settings.signers.threshold
|
||||
};
|
||||
|
||||
if (settings.signers.weights !== undefined) {
|
||||
setSignerList.SignerEntries = settings.signers.weights.map(formatSignerEntry);
|
||||
}
|
||||
return setSignerList;
|
||||
}
|
||||
|
||||
const txJSON: SettingsTransaction = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as isEqual from '../common/js/lodash.isequal'
|
||||
import * as utils from './utils'
|
||||
import keypairs = require('ripple-keypairs')
|
||||
import binary = require('ripple-binary-codec')
|
||||
import binaryCodec = require('ripple-binary-codec')
|
||||
import {computeBinaryTransactionHash} from 'ripple-hashes'
|
||||
import {SignOptions, KeyPair} from './types'
|
||||
import {BigNumber} from 'bignumber.js'
|
||||
@@ -10,8 +11,8 @@ const validate = utils.common.validate
|
||||
|
||||
function computeSignature(tx: object, privateKey: string, signAs?: string) {
|
||||
const signingData = signAs
|
||||
? binary.encodeForMultisigning(tx, signAs)
|
||||
: binary.encodeForSigning(tx)
|
||||
? binaryCodec.encodeForMultisigning(tx, signAs)
|
||||
: binaryCodec.encodeForSigning(tx)
|
||||
return keypairs.sign(signingData, privateKey)
|
||||
}
|
||||
|
||||
@@ -32,7 +33,88 @@ function signWithKeypair(
|
||||
)
|
||||
}
|
||||
|
||||
const fee = new BigNumber(tx.Fee)
|
||||
checkFee(api, tx.Fee)
|
||||
|
||||
const txToSignAndEncode = Object.assign({}, tx)
|
||||
|
||||
txToSignAndEncode.SigningPubKey = options.signAs ? '' : keypair.publicKey
|
||||
|
||||
if (options.signAs) {
|
||||
const signer = {
|
||||
Account: options.signAs,
|
||||
SigningPubKey: keypair.publicKey,
|
||||
TxnSignature: computeSignature(txToSignAndEncode, keypair.privateKey, options.signAs)
|
||||
}
|
||||
txToSignAndEncode.Signers = [{Signer: signer}]
|
||||
} else {
|
||||
txToSignAndEncode.TxnSignature = computeSignature(txToSignAndEncode, keypair.privateKey)
|
||||
}
|
||||
|
||||
const serialized = binaryCodec.encode(txToSignAndEncode)
|
||||
|
||||
checkTxSerialization(serialized, tx)
|
||||
|
||||
return {
|
||||
signedTransaction: serialized,
|
||||
id: computeBinaryTransactionHash(serialized)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a serialized transaction, remove the fields that are added during the signing process,
|
||||
* and verify that it matches the transaction prior to signing.
|
||||
*
|
||||
* @param {string} serialized A signed and serialized transaction.
|
||||
* @param {utils.TransactionJSON} tx The transaction prior to signing.
|
||||
*
|
||||
* @returns {void} This method does not return a value, but throws an error if the check fails.
|
||||
*/
|
||||
function checkTxSerialization(serialized: string, tx: utils.TransactionJSON): void {
|
||||
// Decode the serialized transaction:
|
||||
const decoded = binaryCodec.decode(serialized)
|
||||
|
||||
// ...And ensure it is equal to the original tx, except:
|
||||
// - It must have a TxnSignature or Signers (multisign).
|
||||
if (!decoded.TxnSignature && !decoded.Signers) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
'Serialized transaction must have a TxnSignature or Signers property'
|
||||
)
|
||||
}
|
||||
// - We know that the original tx did not have TxnSignature, so we should delete it:
|
||||
delete decoded.TxnSignature
|
||||
// - We know that the original tx did not have Signers, so if it exists, we should delete it:
|
||||
delete decoded.Signers
|
||||
|
||||
// - If SigningPubKey was not in the original tx, then we should delete it.
|
||||
// But if it was in the original tx, then we should ensure that it has not been changed.
|
||||
if (!tx.SigningPubKey) {
|
||||
delete decoded.SigningPubKey
|
||||
}
|
||||
|
||||
if (!isEqual(decoded, tx)) {
|
||||
const error = new utils.common.errors.ValidationError(
|
||||
'Serialized transaction does not match original txJSON'
|
||||
)
|
||||
error.data = {
|
||||
decoded,
|
||||
tx
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a given transaction fee does not exceed maxFeeXRP (in drops).
|
||||
*
|
||||
* See https://xrpl.org/rippleapi-reference.html#parameters
|
||||
*
|
||||
* @param {RippleAPI} api A RippleAPI instance.
|
||||
* @param {string} txFee The transaction fee in drops, encoded as a string.
|
||||
*
|
||||
* @returns {void} This method does not return a value, but throws an error if the check fails.
|
||||
*/
|
||||
function checkFee(api: RippleAPI, txFee: string): void {
|
||||
const fee = new BigNumber(txFee)
|
||||
const maxFeeDrops = xrpToDrops(api._maxFeeXRP)
|
||||
if (fee.greaterThan(maxFeeDrops)) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
@@ -40,25 +122,6 @@ function signWithKeypair(
|
||||
'To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor.'
|
||||
)
|
||||
}
|
||||
|
||||
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,
|
||||
id: computeBinaryTransactionHash(serialized)
|
||||
}
|
||||
}
|
||||
|
||||
function sign(
|
||||
|
||||
@@ -34,7 +34,17 @@ function formatPrepareResponse(txJSON: any): Prepare {
|
||||
}
|
||||
}
|
||||
|
||||
function setCanonicalFlag(txJSON) {
|
||||
/**
|
||||
* Set the `tfFullyCanonicalSig` flag on a transaction.
|
||||
*
|
||||
* See https://xrpl.org/transaction-malleability.html
|
||||
*
|
||||
* @param {TransactionJSON} txJSON The transaction object to modify.
|
||||
* This method will modify object's `Flags` property, or add it if it does not exist.
|
||||
*
|
||||
* @returns {void} This method mutates the original txJSON and does not return a value.
|
||||
*/
|
||||
function setCanonicalFlag(txJSON: TransactionJSON): void {
|
||||
txJSON.Flags |= txFlags.Universal.FullyCanonicalSig
|
||||
|
||||
// JavaScript converts operands to 32-bit signed ints before doing bitwise
|
||||
@@ -58,6 +68,11 @@ function prepareTransaction(txJSON: TransactionJSON, api: RippleAPI,
|
||||
'" exists in instance when not allowed'))
|
||||
}
|
||||
|
||||
// To remove the signer list, SignerEntries field should be omitted.
|
||||
if (txJSON['SignerQuorum'] === 0) {
|
||||
delete txJSON.SignerEntries;
|
||||
}
|
||||
|
||||
const account = txJSON.Account
|
||||
setCanonicalFlag(txJSON)
|
||||
|
||||
@@ -187,5 +202,6 @@ export {
|
||||
convertStringToHex,
|
||||
convertMemo,
|
||||
prepareTransaction,
|
||||
common
|
||||
common,
|
||||
setCanonicalFlag
|
||||
}
|
||||
|
||||
140
test/api-test.js
140
test/api-test.js
@@ -1767,19 +1767,15 @@ describe('RippleAPI', function () {
|
||||
};
|
||||
});
|
||||
|
||||
it('prepareSettings - signers no weights', function (done) {
|
||||
it('prepareSettings - signers no weights', function () {
|
||||
const settings = requests.prepareSettings.signers.noWeights;
|
||||
try {
|
||||
this.api.prepareSettings(address, settings, instructionsWithMaxLedgerVersionOffset).then(prepared => {
|
||||
done(new Error('Expected method to reject. Prepared transaction: ' + JSON.stringify(prepared)));
|
||||
}).catch(err => {
|
||||
assert.strictEqual(err.name, 'ValidationError');
|
||||
assert.strictEqual(err.message, 'instance.settings.signers requires property "weights"');
|
||||
done();
|
||||
}).catch(done); // Finish test with assertion failure immediately instead of waiting for timeout.
|
||||
} catch (err) {
|
||||
done(new Error('Expected method to reject, but method threw. Thrown: ' + err));
|
||||
};
|
||||
const localInstructions = _.defaults({
|
||||
signersCount: 1
|
||||
}, instructionsWithMaxLedgerVersionOffset);
|
||||
return this.api.prepareSettings(
|
||||
address, settings, localInstructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.noWeights,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - fee for multisign', function () {
|
||||
@@ -1792,6 +1788,17 @@ describe('RippleAPI', function () {
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - no signer list', function () {
|
||||
const settings = requests.prepareSettings.noSignerEntries;
|
||||
const localInstructions = _.defaults({
|
||||
signersCount: 1
|
||||
}, instructionsWithMaxLedgerVersionOffset);
|
||||
return this.api.prepareSettings(
|
||||
address, settings, localInstructions).then(
|
||||
_.partial(checkResult, responses.prepareSettings.noSignerList,
|
||||
'prepare'));
|
||||
});
|
||||
|
||||
it('prepareSettings - invalid', function (done) {
|
||||
// domain must be a string
|
||||
const settings = Object.assign({},
|
||||
@@ -2601,6 +2608,115 @@ describe('RippleAPI', function () {
|
||||
assert.deepEqual(signature, responses.sign.signAs);
|
||||
});
|
||||
|
||||
it('sign - succeeds - prepared payment', async function () {
|
||||
const payment = await this.api.preparePayment('r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: {
|
||||
value: '1',
|
||||
currency: 'drops'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
amount: {
|
||||
value: '1',
|
||||
currency: 'drops'
|
||||
}
|
||||
}
|
||||
});
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const result = this.api.sign(payment.txJSON, secret);
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'12000022800000002400000017201B008694F261400000000000000168400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100A9C91D4CFAE45686146EE0B56D4C53A2E7C2D672FB834D43E0BE2D2E9106519A022075DDA2F92DE552B0C45D83D4E6D35889B3FBF51BFBBD9B25EBF70DE3C96D0D6681145E7B112523F68D2F5E879DB4EAC51C6698A693048314FDB08D07AAA0EB711793A3027304D688E10C3648',
|
||||
id:
|
||||
'88D6B913C66279EA31ADC25C5806C48B2D4E5680261666790A736E1961217700'
|
||||
};
|
||||
assert.deepEqual(result, expectedResult);
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - succeeds - no flags', async function () {
|
||||
const txJSON = '{"TransactionType":"Payment","Account":"r45Rev1EXGxy2hAUmJPCne97KUE7qyrD3j","Destination":"rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r","Amount":"20000000","Sequence":1,"Fee":"12"}';
|
||||
const secret = 'shotKgaEotpcYsshSE39vmSnBDRim';
|
||||
const result = this.api.sign(txJSON, secret);
|
||||
const expectedResult = {
|
||||
signedTransaction:
|
||||
'1200002400000001614000000001312D0068400000000000000C7321022B05847086686F9D0499B13136B94AD4323EE1B67D4C429ECC987AB35ACFA34574473045022100C104B7B97C31FACA4597E7D6FCF13BD85BD11375963A62A0AC45B0061236E39802207784F157F6A98DFC85B051CDDF61CC3084C4F5750B82674801C8E9950280D1998114EE3046A5DDF8422C40DDB93F1D522BB4FE6419158314FDB08D07AAA0EB711793A3027304D688E10C3648',
|
||||
id:
|
||||
'0596925967F541BF332FF6756645B2576A9858414B5B363DC3D34915BE8A70D6'
|
||||
};
|
||||
const decoded = binary.decode(result.signedTransaction);
|
||||
assert(decoded.Flags === undefined, `Flags = ${decoded.Flags}, should be undefined`);
|
||||
assert.deepEqual(result, expectedResult);
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - throws when encoded tx does not match decoded tx - prepared payment', async function () {
|
||||
const payment = await this.api.preparePayment('r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59', {
|
||||
source: {
|
||||
address: 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
|
||||
maxAmount: {
|
||||
value: '1.1234567',
|
||||
currency: 'drops'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: 'rQ3PTWGLCbPz8ZCicV5tCX3xuymojTng5r',
|
||||
amount: {
|
||||
value: '1.1234567',
|
||||
currency: 'drops'
|
||||
}
|
||||
}
|
||||
});
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
assert.throws(
|
||||
() => {
|
||||
this.api.sign(payment.txJSON, secret);
|
||||
},
|
||||
/^Error: 1\.1234567 is an illegal amount/
|
||||
);
|
||||
});
|
||||
|
||||
it('sign - throws when encoded tx does not match decoded tx - AccountSet', function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"1.2\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "0.0000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
this.api.sign(request.txJSON, secret);
|
||||
},
|
||||
/Error: 1\.2 is an illegal amount/
|
||||
);
|
||||
});
|
||||
|
||||
it('sign - throws when encoded tx does not match decoded tx - higher fee', function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"1123456.7\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "1.1234567",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
this.api.sign(request.txJSON, secret);
|
||||
},
|
||||
/Error: 1123456\.7 is an illegal amount/
|
||||
);
|
||||
});
|
||||
|
||||
it('sign - throws when Fee exceeds maxFeeXRP (in drops)', function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
|
||||
1
test/fixtures/requests/index.js
vendored
1
test/fixtures/requests/index.js
vendored
@@ -22,6 +22,7 @@ module.exports = {
|
||||
},
|
||||
prepareSettings: {
|
||||
domain: require('./prepare-settings'),
|
||||
noSignerEntries: require('./prepare-settings-no-signer-entries'),
|
||||
signers: {
|
||||
normal: require('./prepare-settings-signers'),
|
||||
noThreshold: require('./prepare-settings-signers-no-threshold'),
|
||||
|
||||
5
test/fixtures/requests/prepare-settings-no-signer-entries.json
vendored
Normal file
5
test/fixtures/requests/prepare-settings-no-signer-entries.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"signers": {
|
||||
"threshold": 0
|
||||
}
|
||||
}
|
||||
4
test/fixtures/responses/index.js
vendored
4
test/fixtures/responses/index.js
vendored
@@ -122,7 +122,9 @@ module.exports = {
|
||||
noInstructions: require('./prepare-settings-no-instructions.json'),
|
||||
signed: require('./prepare-settings-signed.json'),
|
||||
noMaxLedgerVersion: require('./prepare-settings-no-maxledgerversion.json'),
|
||||
signers: require('./prepare-settings-signers.json')
|
||||
signers: require('./prepare-settings-signers.json'),
|
||||
noSignerList: require('./prepare-settings-no-signer-list.json'),
|
||||
noWeights: require('./prepare-settings-no-weight.json')
|
||||
},
|
||||
prepareCheckCreate: {
|
||||
normal: require('./prepare-check-create'),
|
||||
|
||||
8
test/fixtures/responses/prepare-settings-no-signer-list.json
vendored
Normal file
8
test/fixtures/responses/prepare-settings-no-signer-list.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"TransactionType\":\"SignerListSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SignerQuorum\":0,\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"24\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000024",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
8
test/fixtures/responses/prepare-settings-no-weight.json
vendored
Normal file
8
test/fixtures/responses/prepare-settings-no-weight.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"TransactionType\":\"SignerListSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SignerQuorum\":2,\"SignerEntries\":[],\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"24\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000024",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
'use strict';
|
||||
const assert = require('assert-diff');
|
||||
const _ = require('lodash');
|
||||
const jayson = require('jayson');
|
||||
|
||||
const RippleAPI = require('../../src').RippleAPI;
|
||||
const createHTTPServer = require('../../src/http').createHTTPServer;
|
||||
const {payTo, ledgerAccept} = require('./utils');
|
||||
|
||||
const apiFixtures = require('../fixtures');
|
||||
const apiRequests = apiFixtures.requests;
|
||||
const apiResponses = apiFixtures.responses;
|
||||
|
||||
const TIMEOUT = 20000; // how long before each test case times out
|
||||
|
||||
const serverUri = 'ws://127.0.0.1:6006';
|
||||
const apiOptions = {
|
||||
server: serverUri
|
||||
};
|
||||
|
||||
const httpPort = 3000;
|
||||
|
||||
function createClient() {
|
||||
return jayson.client.http({port: httpPort, hostname: 'localhost'});
|
||||
}
|
||||
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
|
||||
function makePositionalParams(params) {
|
||||
return params.map(value => value[_.keys(value)[0]]);
|
||||
}
|
||||
|
||||
function makeNamedParams(params) {
|
||||
return _.reduce(params, _.assign, {});
|
||||
}
|
||||
|
||||
function random() {
|
||||
return _.fill(Array(16), 0);
|
||||
}
|
||||
|
||||
|
||||
describe('http server integration tests', function() {
|
||||
this.timeout(TIMEOUT);
|
||||
|
||||
let server = null;
|
||||
let client = null;
|
||||
let paymentId = null;
|
||||
let newWallet = null;
|
||||
|
||||
function createTestInternal(testName, methodName, params, testFunc, id) {
|
||||
it(testName, function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.request(methodName, params, id,
|
||||
(err, result) => err ? reject(err) : resolve(testFunc(result)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createTest(name, params, testFunc, id) {
|
||||
createTestInternal(name + ' - positional params', name,
|
||||
makePositionalParams(params), testFunc, id);
|
||||
createTestInternal(name + ' - named params', name,
|
||||
makeNamedParams(params), testFunc, id);
|
||||
}
|
||||
|
||||
before(() => {
|
||||
this.api = new RippleAPI({server: serverUri});
|
||||
console.log('CONNECTING...');
|
||||
return this.api.connect().then(() => {
|
||||
console.log('CONNECTED...');
|
||||
})
|
||||
.then(() => ledgerAccept(this.api))
|
||||
.then(() => newWallet = this.api.generateAddress())
|
||||
.then(() => ledgerAccept(this.api))
|
||||
.then(() => payTo(this.api, newWallet.address))
|
||||
.then(paymentId_ => {
|
||||
paymentId = paymentId_;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
server = createHTTPServer(apiOptions, httpPort);
|
||||
return server.start().then(() => {
|
||||
this.client = createClient();
|
||||
client = this.client;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
return server.stop();
|
||||
});
|
||||
|
||||
|
||||
createTest(
|
||||
'getLedgerVersion',
|
||||
[],
|
||||
result => assert(_.isNumber(result.result))
|
||||
);
|
||||
|
||||
createTest(
|
||||
'getServerInfo',
|
||||
[],
|
||||
result => assert(_.isNumber(result.result.validatedLedger.ledgerVersion))
|
||||
);
|
||||
|
||||
it('getTransaction', function() {
|
||||
const params = [{id: paymentId}];
|
||||
return new Promise((resolve, reject) => {
|
||||
client.request('getTransaction', makePositionalParams(params),
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
assert.strictEqual(result.result.id, paymentId);
|
||||
const outcome = result.result.outcome;
|
||||
assert.strictEqual(outcome.result, 'tesSUCCESS');
|
||||
assert.strictEqual(outcome.balanceChanges
|
||||
.rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh[0].value, '-4003218.000012');
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('getTransactions', function() {
|
||||
const params = [{address: newWallet.address}, {
|
||||
options: {
|
||||
binary: true,
|
||||
limit: 1
|
||||
}
|
||||
}];
|
||||
return new Promise((resolve, reject) => {
|
||||
client.request('getTransactions', makeNamedParams(params),
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
assert.strictEqual(result.result.length, 1);
|
||||
assert.strictEqual(result.result[0].id, paymentId);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
createTest(
|
||||
'prepareSettings',
|
||||
[
|
||||
{address},
|
||||
{settings: apiRequests.prepareSettings.domain},
|
||||
{instructions: {
|
||||
maxFee: '0.000012',
|
||||
sequence: 23,
|
||||
maxLedgerVersion: 8820051
|
||||
}}
|
||||
],
|
||||
result => {
|
||||
const got = JSON.parse(result.result.txJSON);
|
||||
const expected = JSON.parse(apiResponses.prepareSettings.flags.txJSON);
|
||||
assert.deepEqual(got, expected);
|
||||
}
|
||||
);
|
||||
|
||||
createTest(
|
||||
'sign',
|
||||
[{txJSON: apiRequests.sign.normal.txJSON},
|
||||
{secret: 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'}],
|
||||
result => assert.deepEqual(result.result, apiResponses.sign.normal)
|
||||
);
|
||||
|
||||
createTest(
|
||||
'sign',
|
||||
[{txJSON: apiRequests.sign.normal.txJSON},
|
||||
{keypair: {
|
||||
privateKey: '00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A',
|
||||
publicKey: '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8' }}],
|
||||
result => assert.deepEqual(result.result, apiResponses.sign.normal)
|
||||
);
|
||||
|
||||
createTest(
|
||||
'generateAddress',
|
||||
[{options: {entropy: random()}}],
|
||||
result => assert.deepEqual(result.result, apiResponses.generateAddress)
|
||||
);
|
||||
|
||||
createTest(
|
||||
'computeLedgerHash',
|
||||
[{ledger: _.assign({}, apiResponses.getLedger.full,
|
||||
{parentCloseTime: apiResponses.getLedger.full.closeTime})
|
||||
}],
|
||||
result => {
|
||||
assert.strictEqual(result.result,
|
||||
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E');
|
||||
}
|
||||
);
|
||||
|
||||
createTest(
|
||||
'isConnected',
|
||||
[],
|
||||
result => assert(result.result)
|
||||
);
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user