mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
59
Gulpfile.js
59
Gulpfile.js
@@ -8,6 +8,7 @@ var rename = require('gulp-rename');
|
||||
var webpack = require('webpack');
|
||||
var bump = require('gulp-bump');
|
||||
var argv = require('yargs').argv;
|
||||
var assert = require('assert');
|
||||
|
||||
var pkg = require('./package.json');
|
||||
|
||||
@@ -21,10 +22,19 @@ function webpackConfig(extension, overrides) {
|
||||
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/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader?optional=runtime'
|
||||
}, {
|
||||
test: /\.json/,
|
||||
@@ -35,6 +45,53 @@ 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: [{
|
||||
'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-for-web-tests', function(callback) {
|
||||
var configOverrides = {
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: './test-compiled-for-web/',
|
||||
filename: 'ripple-for-web-tests.js'
|
||||
}
|
||||
};
|
||||
var config = webpackConfig('-debug.js', configOverrides);
|
||||
webpack(config, callback);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
gulp.task('build', function(callback) {
|
||||
webpack(webpackConfig('.js'), 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
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
machine:
|
||||
node:
|
||||
version: 0.12.0
|
||||
dependencies:
|
||||
pre:
|
||||
- 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
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
- [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
- [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
- [sign](#sign)
|
||||
- [combine](#combine)
|
||||
- [submit](#submit)
|
||||
- [generateAddress](#generateaddress)
|
||||
- [computeLedgerHash](#computeledgerhash)
|
||||
@@ -269,7 +270,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 +291,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.
|
||||
|
||||
@@ -480,6 +482,12 @@ 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.
|
||||
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, represented as billionths of a unit. Use `null` to set no fee.
|
||||
|
||||
### Example
|
||||
@@ -1599,18 +1607,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,6 +2652,12 @@ 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.
|
||||
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, represented as billionths of a unit. Use `null` to set no fee.
|
||||
|
||||
### Example
|
||||
@@ -3282,7 +3296,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 +3306,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 +3335,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>`
|
||||
|
||||
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);
|
||||
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") %>
|
||||
@@ -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 %>
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
55
npm-shrinkwrap.json
generated
55
npm-shrinkwrap.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.16.1",
|
||||
"version": "0.16.5",
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "1.4.8",
|
||||
"from": "https://registry.npmjs.org/ajv/-/ajv-1.4.8.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-1.4.8.tgz",
|
||||
"version": "1.4.10",
|
||||
"from": "https://registry.npmjs.org/ajv/-/ajv-1.4.10.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-1.4.10.tgz",
|
||||
"dependencies": {
|
||||
"json-stable-stringify": {
|
||||
"version": "1.0.0",
|
||||
@@ -21,10 +21,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv-i18n": {
|
||||
"version": "0.1.1",
|
||||
"from": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-0.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-0.1.1.tgz"
|
||||
},
|
||||
"babel-polyfill": {
|
||||
"version": "6.2.0",
|
||||
"from": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.2.0.tgz",
|
||||
"version": "6.3.14",
|
||||
"from": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.3.14.tgz",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.3.14.tgz",
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "1.2.6",
|
||||
@@ -32,28 +37,28 @@
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz"
|
||||
},
|
||||
"babel-regenerator-runtime": {
|
||||
"version": "6.2.0",
|
||||
"from": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.2.0.tgz"
|
||||
"version": "6.3.13",
|
||||
"from": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.3.13.tgz",
|
||||
"resolved": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.3.13.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-runtime": {
|
||||
"version": "5.8.29",
|
||||
"from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.29.tgz",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.29.tgz",
|
||||
"version": "5.8.34",
|
||||
"from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.34.tgz",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.34.tgz",
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "1.2.3",
|
||||
"from": "https://registry.npmjs.org/core-js/-/core-js-1.2.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.3.tgz"
|
||||
"version": "1.2.6",
|
||||
"from": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"bignumber.js": {
|
||||
"version": "2.1.0",
|
||||
"from": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.0.tgz"
|
||||
"version": "2.1.2",
|
||||
"from": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.2.tgz"
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "1.0.0",
|
||||
@@ -174,9 +179,9 @@
|
||||
}
|
||||
},
|
||||
"ripple-binary-codec": {
|
||||
"version": "0.1.0",
|
||||
"from": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.0.tgz",
|
||||
"version": "0.1.1",
|
||||
"from": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.1.tgz",
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "3.3.0",
|
||||
@@ -298,9 +303,9 @@
|
||||
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.6.0.tgz"
|
||||
},
|
||||
"ws": {
|
||||
"version": "0.7.2",
|
||||
"from": "https://registry.npmjs.org/ws/-/ws-0.7.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-0.7.2.tgz",
|
||||
"version": "1.0.1",
|
||||
"from": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz",
|
||||
"dependencies": {
|
||||
"options": {
|
||||
"version": "0.0.6",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.16.1",
|
||||
"version": "0.16.5",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -23,11 +23,11 @@
|
||||
"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.1",
|
||||
"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",
|
||||
@@ -50,6 +50,9 @@
|
||||
"json-loader": "^0.5.2",
|
||||
"json-schema-to-markdown-table": "^0.4.0",
|
||||
"mocha": "^2.1.0",
|
||||
"mocha-junit-reporter": "^1.9.1",
|
||||
"mocha-phantomjs": "^4.0.1",
|
||||
"null-loader": "^0.1.1",
|
||||
"webpack": "^1.5.3",
|
||||
"yargs": "^1.3.1"
|
||||
},
|
||||
|
||||
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
|
||||
@@ -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,26 @@ 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-tests build-for-web-tests
|
||||
node --harmony test-compiled/mocked-server.js > /dev/null &
|
||||
|
||||
echo "Running tests in PhantomJS"
|
||||
mocha-phantomjs test/localrunner.html
|
||||
|
||||
pkill -f mocked-server.js
|
||||
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-for-web-tests
|
||||
echo "Running integragtion tests in PhantomJS"
|
||||
mocha-phantomjs test/localintegrationrunner.html
|
||||
}
|
||||
|
||||
doctest() {
|
||||
@@ -47,6 +66,7 @@ doctest() {
|
||||
}
|
||||
|
||||
oneNode() {
|
||||
checkEOL
|
||||
doctest
|
||||
lint
|
||||
typecheck
|
||||
@@ -57,7 +77,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 +85,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 ..
|
||||
@@ -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 =
|
||||
@@ -125,6 +126,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)));
|
||||
|
||||
@@ -38,6 +38,17 @@ class Connection extends EventEmitter {
|
||||
this._nextRequestID = 1;
|
||||
}
|
||||
|
||||
_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
|
||||
_parseMessage(message) {
|
||||
const data = JSON.parse(message);
|
||||
@@ -48,10 +59,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) {
|
||||
@@ -99,10 +107,8 @@ class Connection extends EventEmitter {
|
||||
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 => {
|
||||
this._updateLedgerVersions(data);
|
||||
this._isReady = true;
|
||||
this.emit('connected');
|
||||
});
|
||||
@@ -142,10 +148,12 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ class RippleError extends Error {
|
||||
this.name = this.constructor.name;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
Error.captureStackTrace(this, this.constructor.name);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor.name);
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'),
|
||||
|
||||
62
src/common/wswrapper.js
Normal file
62
src/common/wswrapper.js
Normal file
@@ -0,0 +1,62 @@
|
||||
'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) => {
|
||||
if (this.listenerCount('error') > 0) {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -22,7 +22,8 @@ function parseTransactionType(type) {
|
||||
SetRegularKey: 'settings',
|
||||
SuspendedPaymentCreate: 'suspendedPaymentCreation',
|
||||
SuspendedPaymentFinish: 'suspendedPaymentExecution',
|
||||
SuspendedPaymentCancel: 'suspendedPaymentCancellation'
|
||||
SuspendedPaymentCancel: 'suspendedPaymentCancellation',
|
||||
SignerListSet: 'settings'
|
||||
};
|
||||
return mapping[type] || null;
|
||||
}
|
||||
|
||||
@@ -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 &&
|
||||
alt.source_amount.value === 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,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,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,
|
||||
|
||||
@@ -3,15 +3,7 @@
|
||||
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
|
||||
@@ -23,7 +15,7 @@ function isImmediateRejection(engineResult: string): boolean {
|
||||
return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej');
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
@@ -16,6 +16,8 @@ const ledgerClosed = require('./fixtures/rippled/ledger-close-newer');
|
||||
const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
|
||||
assert.options.strict = true;
|
||||
|
||||
const TIMEOUT = 10000; // how long before each test case times out
|
||||
|
||||
function unused() {
|
||||
}
|
||||
|
||||
@@ -37,6 +39,7 @@ function checkResult(expected, schemaName, response) {
|
||||
|
||||
|
||||
describe('RippleAPI', function() {
|
||||
this.timeout(TIMEOUT);
|
||||
const instructions = {maxLedgerVersionOffset: 100};
|
||||
beforeEach(setupAPI.setup);
|
||||
afterEach(setupAPI.teardown);
|
||||
@@ -183,20 +186,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 +247,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'
|
||||
@@ -312,6 +332,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 +354,11 @@ describe('RippleAPI', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('combine', function() {
|
||||
const combined = this.api.combine(requests.combine.setDomain);
|
||||
checkResult(responses.combine.single, 'sign', combined);
|
||||
});
|
||||
|
||||
describe('RippleAPI', function() {
|
||||
|
||||
it('getBalances', function() {
|
||||
@@ -914,7 +947,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 => {
|
||||
@@ -1012,6 +1049,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(() => {
|
||||
@@ -1255,7 +1301,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,
|
||||
|
||||
@@ -26,7 +26,9 @@ describe('RippleAPIBroadcast', function() {
|
||||
|
||||
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 +41,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);
|
||||
|
||||
}, 250);
|
||||
});
|
||||
|
||||
it('error propagation', function(done) {
|
||||
@@ -55,8 +59,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'}
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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 = 10000; // 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,6 +60,10 @@ describe('Connection', function() {
|
||||
});
|
||||
|
||||
it('with proxy', function(done) {
|
||||
if (process.browser) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
createServer().then((server) => {
|
||||
const port = server.address().port;
|
||||
const expect = 'CONNECT localhost';
|
||||
@@ -96,9 +107,10 @@ describe('Connection', function() {
|
||||
});
|
||||
|
||||
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 => {
|
||||
@@ -261,4 +273,13 @@ 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));
|
||||
});
|
||||
});
|
||||
|
||||
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"
|
||||
}
|
||||
},
|
||||
"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')
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -31,4 +31,4 @@
|
||||
"ledgerVersion": 14,
|
||||
"indexInLedger": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,4 @@
|
||||
"ledgerVersion": 14,
|
||||
"indexInLedger": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,4 +331,4 @@
|
||||
"balance": "0"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
10
test/fixtures/responses/index.js
vendored
10
test/fixtures/responses/index.js
vendored
@@ -81,13 +81,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 +110,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,8 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147942400,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"LTC\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\"},\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"Paths\":[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147942400,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"LTC\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\"},\"InvoiceID\":\"A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A\",\"SourceTag\":14,\"DestinationTag\":58,\"Memos\":[{\"Memo\":{\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\",\"MemoData\":\"7465787465642064617461\"}}],\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\"},\"Paths\":[[{\"account\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"issuer\":\"rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q\",\"currency\":\"USD\"},{\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"},{\"account\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"issuer\":\"rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX\",\"currency\":\"LTC\"}]],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"WalletLocator\":\"0\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"WalletLocator\":\"0\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
8
test/fixtures/responses/prepare-settings-multisign.json
vendored
Normal file
8
test/fixtures/responses/prepare-settings-multisign.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"Domain\":\"726970706C652E636F6D\",\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"60\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.00006",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransferRate\":1000000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransferRate\":1000000000,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"signedTransaction": "12000322800000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402202FBF6A6F74DFDA17C7341D532B66141206BC71A147C08DBDA6A950AA9A1741DC022055859A39F2486A46487F8DA261E3D80B4FDD26178A716A929F26377D1BEC7E43770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304F9EA7C04746573747D0B74657874656420646174617E0A706C61696E2F74657874E1F1",
|
||||
"id": "4755D26FAC39E3E477870D4E03CC6783DDDF967FFBE240606755D3D03702FC16"
|
||||
}
|
||||
}
|
||||
|
||||
8
test/fixtures/responses/prepare-settings-signers.json
vendored
Normal file
8
test/fixtures/responses/prepare-settings-signers.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"txJSON": "{\"TransactionType\":\"SignerListSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SignerQuorum\":2,\"SignerEntries\":[{\"SignerEntry\":{\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"SignerWeight\":1}},{\"SignerEntry\":{\"Account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"SignerWeight\":1}},{\"SignerEntry\":{\"Account\":\"rwBYyfufTzk77zUSKEu4MvixfarC35av1J\",\"SignerWeight\":1}}],\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
4
test/fixtures/responses/sign-as.json
vendored
Normal file
4
test/fixtures/responses/sign-as.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"signedTransaction": "120000240000000261400000003B9ACA00684000000000000032730081142E244E6F20104E57C0C60BD823CB312BF10928C78314B5F762798A53D543A014CAF8B297CFF8F2F937E8F3E01073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100BB6FC77F26BC88587204CAA79B2230C420D7EC937B8AC3A0CF9B0BE988BAB0D002203BF86893BA3B764375FFFAD9D54A4AAEDABD07C4D72ADB9C1B20C10B4DD712898114B5F762798A53D543A014CAF8B297CFF8F2F937E8E1F1",
|
||||
"id": "AB7632D7C07E591658635CED6A5DDE832B22CA066907CB131DEFAAA925B98185"
|
||||
}
|
||||
@@ -29,4 +29,4 @@
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
}
|
||||
|
||||
3
test/fixtures/rippled/index.js
vendored
3
test/fixtures/rippled/index.js
vendored
@@ -38,7 +38,8 @@ module.exports = {
|
||||
sendUSD: require('./path-find-send-usd'),
|
||||
sendAll: require('./path-find-send-all'),
|
||||
XrpToXrp: require('./path-find-xrp-to-xrp'),
|
||||
srcActNotFound: require('./path-find-srcActNotFound')
|
||||
srcActNotFound: require('./path-find-srcActNotFound'),
|
||||
sourceAmountLow: require('./path-find-srcAmtLow')
|
||||
},
|
||||
tx: {
|
||||
Payment: require('./tx/payment.json'),
|
||||
|
||||
22
test/fixtures/rippled/ledger-close-newer.json
vendored
22
test/fixtures/rippled/ledger-close-newer.json
vendored
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"fee_base": 10,
|
||||
"fee_ref": 10,
|
||||
"ledger_hash": "9141FA171F2C0CE63E609466AF728FF66C12F7ACD4B4B50B0947A7F3409D593A",
|
||||
"ledger_index": 14804627,
|
||||
"ledger_time": 490945840,
|
||||
"reserve_base": 20000000,
|
||||
"reserve_inc": 5000000,
|
||||
"txn_count": 19,
|
||||
"type": "ledgerClosed",
|
||||
"validated_ledgers": "13983423-14804627"
|
||||
{
|
||||
"fee_base": 10,
|
||||
"fee_ref": 10,
|
||||
"ledger_hash": "9141FA171F2C0CE63E609466AF728FF66C12F7ACD4B4B50B0947A7F3409D593A",
|
||||
"ledger_index": 14804627,
|
||||
"ledger_time": 490945840,
|
||||
"reserve_base": 20000000,
|
||||
"reserve_inc": 5000000,
|
||||
"txn_count": 19,
|
||||
"type": "ledgerClosed",
|
||||
"validated_ledgers": "13983423-14804627"
|
||||
}
|
||||
24
test/fixtures/rippled/ledger-not-found.json
vendored
24
test/fixtures/rippled/ledger-not-found.json
vendored
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "error",
|
||||
"type": "response",
|
||||
"error": "lgrNotFound",
|
||||
"error_code": 20,
|
||||
"error_message": "ledgerNotFound",
|
||||
"request": {
|
||||
"command": "ledger",
|
||||
"id": 3,
|
||||
"ledger_index": 34
|
||||
}
|
||||
{
|
||||
"id": 0,
|
||||
"status": "error",
|
||||
"type": "response",
|
||||
"error": "lgrNotFound",
|
||||
"error_code": 20,
|
||||
"error_message": "ledgerNotFound",
|
||||
"request": {
|
||||
"command": "ledger",
|
||||
"id": 3,
|
||||
"ledger_index": 34
|
||||
}
|
||||
}
|
||||
97
test/fixtures/rippled/path-find-srcAmtLow.json
vendored
Normal file
97
test/fixtures/rippled/path-find-srcAmtLow.json
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"id": 0,
|
||||
"result": {
|
||||
"full_reply": true,
|
||||
"alternatives": [
|
||||
{
|
||||
"paths_canonical": [],
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rLMJ4db4uwHcd6NHg6jvTaYb8sH5Gy4tg5",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rLMJ4db4uwHcd6NHg6jvTaYb8sH5Gy4tg5",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"value": "0.000001002"
|
||||
}
|
||||
}
|
||||
],
|
||||
"source_account": "rhVgDEfS1r1fLyRUZCpab4TdowZcAJwHy2",
|
||||
"destination_amount": {
|
||||
"currency": "USD",
|
||||
"value": "-1",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||
},
|
||||
"destination_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"destination_currencies": [
|
||||
"JOE",
|
||||
"BTC",
|
||||
"DYM",
|
||||
"CNY",
|
||||
"EUR",
|
||||
"015841551A748AD2C1F76FF6ECB0CCCD00000000",
|
||||
"MXN",
|
||||
"USD",
|
||||
"XRP"
|
||||
]
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
190
test/fixtures/rippled/tx/offer-cancel.json
vendored
190
test/fixtures/rippled/tx/offer-cancel.json
vendored
@@ -1,95 +1,95 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"TransactionType": "OfferCancel",
|
||||
"Flags": 0,
|
||||
"Sequence": 466,
|
||||
"OfferSequence": 465,
|
||||
"LastLedgerSequence": 14661888,
|
||||
"Fee": "12000",
|
||||
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
|
||||
"TxnSignature": "3045022100E4148E9809C5CE13BC5583E8CA665614D9FF02D6589D13BA7FBB67CF45EAC0BF02201B84DC18A921260BCEE685908260888BC20D4375DB4A8702F25B346CAD7F3387",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
|
||||
"hash": "809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E",
|
||||
"ledger_index": 14661789,
|
||||
"inLedger": 14661789,
|
||||
"meta": {
|
||||
"TransactionIndex": 4,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 14661788,
|
||||
"PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
|
||||
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
|
||||
"PreviousFields": {
|
||||
"Sequence": 466,
|
||||
"OwnerCount": 4,
|
||||
"Balance": "71827095"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 467,
|
||||
"OwnerCount": 3,
|
||||
"Balance": "71815095",
|
||||
"Domain": "726970706C652E636F6D",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"ExchangeRate": "550435C0500F1000",
|
||||
"RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 465,
|
||||
"PreviousTxnLgrSeq": 14661788,
|
||||
"BookNode": "0000000000000000",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
|
||||
"BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPays": {
|
||||
"value": "237",
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||
},
|
||||
"TakerGets": "200",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"TransactionType": "OfferCancel",
|
||||
"Flags": 0,
|
||||
"Sequence": 466,
|
||||
"OfferSequence": 465,
|
||||
"LastLedgerSequence": 14661888,
|
||||
"Fee": "12000",
|
||||
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
|
||||
"TxnSignature": "3045022100E4148E9809C5CE13BC5583E8CA665614D9FF02D6589D13BA7FBB67CF45EAC0BF02201B84DC18A921260BCEE685908260888BC20D4375DB4A8702F25B346CAD7F3387",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
|
||||
"hash": "809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E",
|
||||
"ledger_index": 14661789,
|
||||
"inLedger": 14661789,
|
||||
"meta": {
|
||||
"TransactionIndex": 4,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 14661788,
|
||||
"PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
|
||||
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
|
||||
"PreviousFields": {
|
||||
"Sequence": 466,
|
||||
"OwnerCount": 4,
|
||||
"Balance": "71827095"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 467,
|
||||
"OwnerCount": 3,
|
||||
"Balance": "71815095",
|
||||
"Domain": "726970706C652E636F6D",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"ExchangeRate": "550435C0500F1000",
|
||||
"RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 465,
|
||||
"PreviousTxnLgrSeq": 14661788,
|
||||
"BookNode": "0000000000000000",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
|
||||
"BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPays": {
|
||||
"value": "237",
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||
},
|
||||
"TakerGets": "200",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,4 +48,4 @@
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
}
|
||||
|
||||
184
test/fixtures/rippled/tx/offer-create.json
vendored
184
test/fixtures/rippled/tx/offer-create.json
vendored
@@ -1,92 +1,92 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"TransactionType": "OfferCreate",
|
||||
"Flags": 0,
|
||||
"Sequence": 465,
|
||||
"LastLedgerSequence": 14661886,
|
||||
"TakerPays": {
|
||||
"value": "237",
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||
},
|
||||
"TakerGets": "200",
|
||||
"Fee": "12000",
|
||||
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
|
||||
"TxnSignature": "3045022100FA4CBD0A54A38906F8D4C18FBA4DBCE45B98F9C5A33BC9102CB5911E9E20E88F022032C47AC74E60042FF1517C866680A41B396D61146FBA9E60B4CF74E373CA7AD2",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
|
||||
"hash": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
|
||||
"ledger_index": 14661788,
|
||||
"inLedger": 14661788,
|
||||
"meta": {
|
||||
"TransactionIndex": 2,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 14660978,
|
||||
"PreviousTxnID": "566D4DE22972C5BAD2506CFFA928B21D2BD33FA52FE16712D17D727681FAA4B1",
|
||||
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
|
||||
"PreviousFields": {
|
||||
"Sequence": 465,
|
||||
"OwnerCount": 3,
|
||||
"Balance": "71839095"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 466,
|
||||
"OwnerCount": 4,
|
||||
"Balance": "71827095",
|
||||
"Domain": "726970706C652E636F6D",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"NewFields": {
|
||||
"ExchangeRate": "550435C0500F1000",
|
||||
"RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C",
|
||||
"NewFields": {
|
||||
"Sequence": 465,
|
||||
"BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPays": {
|
||||
"value": "237",
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||
},
|
||||
"TakerGets": "200",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"TransactionType": "OfferCreate",
|
||||
"Flags": 0,
|
||||
"Sequence": 465,
|
||||
"LastLedgerSequence": 14661886,
|
||||
"TakerPays": {
|
||||
"value": "237",
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||
},
|
||||
"TakerGets": "200",
|
||||
"Fee": "12000",
|
||||
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
|
||||
"TxnSignature": "3045022100FA4CBD0A54A38906F8D4C18FBA4DBCE45B98F9C5A33BC9102CB5911E9E20E88F022032C47AC74E60042FF1517C866680A41B396D61146FBA9E60B4CF74E373CA7AD2",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
|
||||
"hash": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
|
||||
"ledger_index": 14661788,
|
||||
"inLedger": 14661788,
|
||||
"meta": {
|
||||
"TransactionIndex": 2,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 14660978,
|
||||
"PreviousTxnID": "566D4DE22972C5BAD2506CFFA928B21D2BD33FA52FE16712D17D727681FAA4B1",
|
||||
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
|
||||
"PreviousFields": {
|
||||
"Sequence": 465,
|
||||
"OwnerCount": 3,
|
||||
"Balance": "71839095"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 466,
|
||||
"OwnerCount": 4,
|
||||
"Balance": "71827095",
|
||||
"Domain": "726970706C652E636F6D",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
|
||||
"Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"NewFields": {
|
||||
"ExchangeRate": "550435C0500F1000",
|
||||
"RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C",
|
||||
"NewFields": {
|
||||
"Sequence": 465,
|
||||
"BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
|
||||
"TakerPays": {
|
||||
"value": "237",
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||
},
|
||||
"TakerGets": "200",
|
||||
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,4 +96,4 @@
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +97,4 @@
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "2",
|
||||
"result": {
|
||||
"type": "order",
|
||||
"address": "rK5j9n8baXfL4gzUoZsfxBvvsv97P5swaV",
|
||||
"sequence": 7973823,
|
||||
"id": "4EB6B76237DEEE99F1EA16FAACED2D1E69C5F9CB54F727A4ECA51A08AD3AF466",
|
||||
"specification": {
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
"currency": "USD",
|
||||
"value": "0.000709756467",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "JPY",
|
||||
"value": "0.086630181788",
|
||||
"counterparty": "r94s8px6kSw1uZ1MV98dhSRTvc6VMPoPcN"
|
||||
}
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2015-12-03T00:53:21.000Z",
|
||||
"fee": "0.010001",
|
||||
"balanceChanges": {
|
||||
"rK5j9n8baXfL4gzUoZsfxBvvsv97P5swaV": [
|
||||
{
|
||||
"currency": "XRP",
|
||||
"value": "-0.010001"
|
||||
}
|
||||
]
|
||||
},
|
||||
"orderbookChanges": {
|
||||
"rK5j9n8baXfL4gzUoZsfxBvvsv97P5swaV": [
|
||||
{
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.000709260645"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "JPY",
|
||||
"counterparty": "r94s8px6kSw1uZ1MV98dhSRTvc6VMPoPcN",
|
||||
"value": "0.086665436143"
|
||||
},
|
||||
"sequence": 7973725,
|
||||
"status": "cancelled",
|
||||
"makerExchangeRate": "0.008183892870852266"
|
||||
},
|
||||
{
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
"currency": "USD",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.000709756467"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "JPY",
|
||||
"counterparty": "r94s8px6kSw1uZ1MV98dhSRTvc6VMPoPcN",
|
||||
"value": "0.086630181788"
|
||||
},
|
||||
"sequence": 7973823,
|
||||
"status": "created",
|
||||
"makerExchangeRate": "0.008192946757712049"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ledgerVersion": 17445469,
|
||||
"indexInLedger": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "3",
|
||||
"result": [
|
||||
{
|
||||
"type": "order",
|
||||
"address": "rpP2JgiMyTF5jR5hLG3xHCPi1knBb1v9cM",
|
||||
"sequence": 3372206,
|
||||
"id": "848397FA686BD4A59F91EC1F4DE717360470EE8BD67CAA01D5FD333EDA8D97B3",
|
||||
"specification": {
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
"currency": "JPY",
|
||||
"value": "27865.90216965619",
|
||||
"counterparty": "rJRi8WW24gt9X85PHAxfWNPCizMMhqUQwg"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "40000"
|
||||
}
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"fee": "0.011",
|
||||
"balanceChanges": {
|
||||
"rpP2JgiMyTF5jR5hLG3xHCPi1knBb1v9cM": [
|
||||
{
|
||||
"currency": "XRP",
|
||||
"value": "-0.011"
|
||||
}
|
||||
]
|
||||
},
|
||||
"orderbookChanges": {
|
||||
"rpP2JgiMyTF5jR5hLG3xHCPi1knBb1v9cM": [
|
||||
{
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
"currency": "JPY",
|
||||
"counterparty": "rJRi8WW24gt9X85PHAxfWNPCizMMhqUQwg",
|
||||
"value": "27880.6855384734"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "40000"
|
||||
},
|
||||
"sequence": 3372204,
|
||||
"status": "cancelled",
|
||||
"makerExchangeRate": "0.697017138461835"
|
||||
},
|
||||
{
|
||||
"direction": "buy",
|
||||
"quantity": {
|
||||
"currency": "JPY",
|
||||
"counterparty": "rJRi8WW24gt9X85PHAxfWNPCizMMhqUQwg",
|
||||
"value": "27865.90216965619"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "40000"
|
||||
},
|
||||
"sequence": 3372206,
|
||||
"status": "created",
|
||||
"makerExchangeRate": "0.6966475542414048"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ledgerVersion": 17533547,
|
||||
"indexInLedger": 12
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
getTransaction: require('./get-transaction'),
|
||||
getTransactions: require('./get-transactions')
|
||||
};
|
||||
@@ -4,18 +4,19 @@ const assert = require('assert-diff');
|
||||
const _ = require('lodash');
|
||||
const jayson = require('jayson');
|
||||
|
||||
const RippleAPI = require('../../src').RippleAPI;
|
||||
const createHTTPServer = require('../../src/index').createHTTPServer;
|
||||
const {payTo, ledgerAccept} = require('./utils');
|
||||
|
||||
const apiFixtures = require('../fixtures');
|
||||
const apiRequests = apiFixtures.requests;
|
||||
const apiResponses = apiFixtures.responses;
|
||||
|
||||
const fixtures = require('./fixtures');
|
||||
|
||||
const TIMEOUT = 20000; // how long before each test case times out
|
||||
|
||||
const serverUri = 'ws://127.0.0.1:6006';
|
||||
const apiOptions = {
|
||||
server: 'wss://s1.ripple.com'
|
||||
server: serverUri
|
||||
};
|
||||
|
||||
const httpPort = 3000;
|
||||
@@ -38,11 +39,14 @@ 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() {
|
||||
@@ -60,6 +64,21 @@ describe('http server integration tests', function() {
|
||||
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(() => {
|
||||
@@ -85,32 +104,49 @@ describe('http server integration tests', function() {
|
||||
result => assert(_.isNumber(result.result.validatedLedger.ledgerVersion))
|
||||
);
|
||||
|
||||
createTest(
|
||||
'getTransaction',
|
||||
[{id: '4EB6B76237DEEE99F1EA16FAACED2D1E69C5F9CB54F727A4ECA51A08AD3AF466'}],
|
||||
result => assert.deepEqual(result, fixtures.getTransaction),
|
||||
'2'
|
||||
);
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
createTest(
|
||||
'getTransactions',
|
||||
[{address: 'rpP2JgiMyTF5jR5hLG3xHCPi1knBb1v9cM'}, {
|
||||
it('getTransactions', function() {
|
||||
const params = [{address: newWallet.address}, {
|
||||
options: {
|
||||
binary: true,
|
||||
limit: 1,
|
||||
start:
|
||||
'FBAAC31D6BAEEFA9E501266FD62DA7A7982662BC19BC42F49BB41405C2F820DB'
|
||||
limit: 1
|
||||
}
|
||||
}],
|
||||
result => assert.deepEqual(result, fixtures.getTransactions),
|
||||
'3'
|
||||
);
|
||||
}];
|
||||
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},
|
||||
{settings: apiRequests.prepareSettings.domain},
|
||||
{instructions: {
|
||||
maxFee: '0.000012',
|
||||
sequence: 23,
|
||||
|
||||
@@ -9,73 +9,180 @@ const requests = require('../fixtures/requests');
|
||||
const RippleAPI = require('../../src').RippleAPI;
|
||||
const {isValidAddress} = require('ripple-address-codec');
|
||||
const {isValidSecret} = require('../../src/common');
|
||||
const {payTo, ledgerAccept} = require('./utils');
|
||||
|
||||
|
||||
const TIMEOUT = 30000; // how long before each test case times out
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = process.browser ? 25000 : 10000;
|
||||
const INTERVAL = 1000; // how long to wait between checks for validated ledger
|
||||
|
||||
const serverUrl = 'ws://127.0.0.1:6006';
|
||||
|
||||
function verifyTransaction(testcase, hash, type, options, txData) {
|
||||
function acceptLedger(api) {
|
||||
return api.connection.request({command: 'ledger_accept'});
|
||||
}
|
||||
|
||||
function verifyTransaction(testcase, hash, type, options, txData, address) {
|
||||
console.log('VERIFY...');
|
||||
return testcase.api.getTransaction(hash, options).then(data => {
|
||||
assert(data && data.outcome);
|
||||
assert.strictEqual(data.type, type);
|
||||
assert.strictEqual(data.address, wallet.getAddress());
|
||||
assert.strictEqual(data.address, address);
|
||||
assert.strictEqual(data.outcome.result, 'tesSUCCESS');
|
||||
testcase.transactions.push(hash);
|
||||
if (testcase.transactions !== undefined) {
|
||||
testcase.transactions.push(hash);
|
||||
}
|
||||
return {txJSON: JSON.stringify(txData), id: hash, tx: data};
|
||||
}).catch(error => {
|
||||
if (error instanceof errors.PendingLedgerVersionError) {
|
||||
console.log('NOT VALIDATED YET...');
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => verifyTransaction(testcase, hash, type,
|
||||
options, txData).then(resolve, reject), INTERVAL);
|
||||
options, txData, address).then(resolve, reject), INTERVAL);
|
||||
});
|
||||
}
|
||||
console.log(error.stack);
|
||||
assert(false, 'Transaction not successful: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function testTransaction(testcase, type, lastClosedLedgerVersion, prepared) {
|
||||
function testTransaction(testcase, type, lastClosedLedgerVersion, prepared,
|
||||
address = wallet.getAddress(), secret = wallet.getSecret()) {
|
||||
const txJSON = prepared.txJSON;
|
||||
assert(txJSON, 'missing txJSON');
|
||||
const txData = JSON.parse(txJSON);
|
||||
assert.strictEqual(txData.Account, wallet.getAddress());
|
||||
const signedData = testcase.api.sign(txJSON, wallet.getSecret());
|
||||
assert.strictEqual(txData.Account, address);
|
||||
const signedData = testcase.api.sign(txJSON, secret);
|
||||
console.log('PREPARED...');
|
||||
return testcase.api.submit(signedData.signedTransaction).then(data => {
|
||||
return testcase.api.submit(signedData.signedTransaction)
|
||||
.then(data => testcase.test.title.indexOf('multisign') !== -1 ?
|
||||
acceptLedger(testcase.api).then(() => data) : data).then(data => {
|
||||
console.log('SUBMITTED...');
|
||||
assert.strictEqual(data.resultCode, 'tesSUCCESS');
|
||||
const options = {
|
||||
minLedgerVersion: lastClosedLedgerVersion,
|
||||
maxLedgerVersion: txData.LastLedgerSequence
|
||||
};
|
||||
ledgerAccept(testcase.api);
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => verifyTransaction(testcase, signedData.id, type,
|
||||
options, txData).then(resolve, reject), INTERVAL);
|
||||
options, txData, address).then(resolve, reject), INTERVAL);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setup() {
|
||||
this.api = new RippleAPI({server: 'wss://s1.ripple.com'});
|
||||
function setup(server = 'wss://s1.ripple.com') {
|
||||
this.api = new RippleAPI({server});
|
||||
console.log('CONNECTING...');
|
||||
return this.api.connect().then(() => {
|
||||
console.log('CONNECTED...');
|
||||
});
|
||||
}
|
||||
|
||||
const masterAccount = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh';
|
||||
const masterSecret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
|
||||
function makeTrustLine(testcase, address, secret) {
|
||||
const api = testcase.api;
|
||||
const specification = {
|
||||
currency: 'USD',
|
||||
counterparty: masterAccount,
|
||||
limit: '1341.1',
|
||||
ripplingDisabled: true
|
||||
};
|
||||
const trust = api.prepareTrustline(address, specification, {})
|
||||
.then(data => {
|
||||
const signed = api.sign(data.txJSON, secret);
|
||||
if (address === wallet.getAddress()) {
|
||||
testcase.transactions.push(signed.id);
|
||||
}
|
||||
return api.submit(signed.signedTransaction);
|
||||
})
|
||||
.then(() => ledgerAccept(api));
|
||||
return trust;
|
||||
}
|
||||
|
||||
function makeOrder(api, address, specification, secret) {
|
||||
return api.prepareOrder(address, specification)
|
||||
.then(data => api.sign(data.txJSON, secret))
|
||||
.then(signed => api.submit(signed.signedTransaction))
|
||||
.then(() => ledgerAccept(api));
|
||||
}
|
||||
|
||||
function setupAccounts(testcase) {
|
||||
const api = testcase.api;
|
||||
|
||||
const promise = payTo(api, 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM')
|
||||
.then(() => payTo(api, wallet.getAddress()))
|
||||
.then(() => payTo(api, testcase.newWallet.address))
|
||||
.then(() => payTo(api, 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc'))
|
||||
.then(() => payTo(api, 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q'))
|
||||
.then(() => {
|
||||
return api.prepareSettings(masterAccount, {defaultRipple: true})
|
||||
.then(data => api.sign(data.txJSON, masterSecret))
|
||||
.then(signed => api.submit(signed.signedTransaction))
|
||||
.then(() => ledgerAccept(api));
|
||||
})
|
||||
.then(() => makeTrustLine(testcase, wallet.getAddress(),
|
||||
wallet.getSecret()))
|
||||
.then(() => makeTrustLine(testcase, testcase.newWallet.address,
|
||||
testcase.newWallet.secret))
|
||||
.then(() => payTo(api, wallet.getAddress(), '123', 'USD', masterAccount))
|
||||
.then(() => payTo(api, 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q'))
|
||||
.then(() => {
|
||||
const orderSpecification = {
|
||||
direction: 'buy',
|
||||
quantity: {
|
||||
currency: 'USD',
|
||||
value: '432',
|
||||
counterparty: masterAccount
|
||||
},
|
||||
totalPrice: {
|
||||
currency: 'XRP',
|
||||
value: '432'
|
||||
}
|
||||
};
|
||||
return makeOrder(testcase.api, testcase.newWallet.address,
|
||||
orderSpecification, testcase.newWallet.secret);
|
||||
})
|
||||
.then(() => {
|
||||
const orderSpecification = {
|
||||
direction: 'buy',
|
||||
quantity: {
|
||||
currency: 'XRP',
|
||||
value: '1741'
|
||||
},
|
||||
totalPrice: {
|
||||
currency: 'USD',
|
||||
value: '171',
|
||||
counterparty: masterAccount
|
||||
}
|
||||
};
|
||||
return makeOrder(testcase.api, masterAccount, orderSpecification,
|
||||
masterSecret);
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
return this.api.disconnect();
|
||||
}
|
||||
|
||||
function suiteSetup() {
|
||||
this.transactions = [];
|
||||
return setup.bind(this)().then(() => {
|
||||
return this.api.getLedgerVersion().then(ledgerVersion => {
|
||||
|
||||
return setup.bind(this)(serverUrl)
|
||||
.then(() => ledgerAccept(this.api))
|
||||
.then(() => this.newWallet = this.api.generateAddress())
|
||||
// two times to give time to server to send `ledgerClosed` event
|
||||
// so getLedgerVersion will return right value
|
||||
.then(() => ledgerAccept(this.api))
|
||||
.then(() => this.api.getLedgerVersion())
|
||||
.then(ledgerVersion => {
|
||||
this.startLedgerVersion = ledgerVersion;
|
||||
});
|
||||
}).then(teardown.bind(this));
|
||||
})
|
||||
.then(() => setupAccounts(this))
|
||||
.then(() => teardown.bind(this)());
|
||||
}
|
||||
|
||||
describe('integration tests', function() {
|
||||
@@ -84,14 +191,14 @@ describe('integration tests', function() {
|
||||
this.timeout(TIMEOUT);
|
||||
|
||||
before(suiteSetup);
|
||||
beforeEach(setup);
|
||||
beforeEach(_.partial(setup, serverUrl));
|
||||
afterEach(teardown);
|
||||
|
||||
|
||||
it('settings', function() {
|
||||
return this.api.getLedgerVersion().then(ledgerVersion => {
|
||||
return this.api.prepareSettings(address,
|
||||
requests.prepareSettings, instructions).then(prepared =>
|
||||
requests.prepareSettings.domain, instructions).then(prepared =>
|
||||
testTransaction(this, 'settings', ledgerVersion, prepared));
|
||||
});
|
||||
});
|
||||
@@ -140,10 +247,10 @@ describe('integration tests', function() {
|
||||
}
|
||||
};
|
||||
return this.api.getLedgerVersion().then(ledgerVersion => {
|
||||
return this.api.prepareOrder(address,
|
||||
orderSpecification, instructions).then(prepared =>
|
||||
testTransaction(this, 'order', ledgerVersion, prepared)
|
||||
).then(result => {
|
||||
return this.api.prepareOrder(address, orderSpecification, instructions)
|
||||
.then(prepared =>
|
||||
testTransaction(this, 'order', ledgerVersion, prepared))
|
||||
.then(result => {
|
||||
const txData = JSON.parse(result.txJSON);
|
||||
return this.api.getOrders(address).then(orders => {
|
||||
assert(orders && orders.length > 0);
|
||||
@@ -155,8 +262,9 @@ describe('integration tests', function() {
|
||||
assert.deepEqual(createdOrder.specification, orderSpecification);
|
||||
return txData;
|
||||
});
|
||||
}).then(txData => this.api.prepareOrderCancellation(
|
||||
address, {orderSequence: txData.Sequence}, instructions)
|
||||
})
|
||||
.then(txData => this.api.prepareOrderCancellation(
|
||||
address, {orderSequence: txData.Sequence}, instructions)
|
||||
.then(prepared => testTransaction(this, 'orderCancellation',
|
||||
ledgerVersion, prepared))
|
||||
);
|
||||
@@ -232,7 +340,7 @@ describe('integration tests', function() {
|
||||
it('getSettings', function() {
|
||||
return this.api.getSettings(address).then(data => {
|
||||
assert(data);
|
||||
assert.strictEqual(data.domain, requests.prepareSettings.domain);
|
||||
assert.strictEqual(data.domain, requests.prepareSettings.domain.domain);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -244,7 +352,7 @@ describe('integration tests', function() {
|
||||
},
|
||||
counter: {
|
||||
currency: 'USD',
|
||||
counterparty: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q'
|
||||
counterparty: masterAccount
|
||||
}
|
||||
};
|
||||
return this.api.getOrderbook(address, orderbook).then(book => {
|
||||
@@ -272,11 +380,11 @@ describe('integration tests', function() {
|
||||
address: address
|
||||
},
|
||||
destination: {
|
||||
address: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
|
||||
address: this.newWallet.address,
|
||||
amount: {
|
||||
value: '0.000001',
|
||||
value: '1',
|
||||
currency: 'USD',
|
||||
counterparty: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q'
|
||||
counterparty: masterAccount
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -289,8 +397,24 @@ describe('integration tests', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('getPaths - send all', function() {
|
||||
const pathfind = requests.getPaths.sendAll;
|
||||
const pathfind = {
|
||||
source: {
|
||||
address: address,
|
||||
amount: {
|
||||
currency: 'USD',
|
||||
value: '0.005'
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: this.newWallet.address,
|
||||
amount: {
|
||||
currency: 'USD'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return this.api.getPaths(pathfind).then(data => {
|
||||
assert(data && data.length > 0);
|
||||
assert(_.every(data, path => {
|
||||
@@ -313,3 +437,63 @@ describe('integration tests', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('integration tests - standalone rippled', function() {
|
||||
const instructions = {maxLedgerVersionOffset: 10};
|
||||
this.timeout(TIMEOUT);
|
||||
|
||||
beforeEach(_.partial(setup, serverUrl));
|
||||
afterEach(teardown);
|
||||
const address = 'r5nx8ZkwEbFztnc8Qyi22DE9JYjRzNmvs';
|
||||
const secret = 'ss6F8381Br6wwpy9p582H8sBt19J3';
|
||||
const signer1address = 'rQDhz2ZNXmhxzCYwxU6qAbdxsHA4HV45Y2';
|
||||
const signer1secret = 'shK6YXzwYfnFVn3YZSaMh5zuAddKx';
|
||||
const signer2address = 'r3RtUvGw9nMoJ5FuHxuoVJvcENhKtuF9ud';
|
||||
const signer2secret = 'shUHQnL4EH27V4EiBrj6EfhWvZngF';
|
||||
|
||||
it('submit multisigned transaction', function() {
|
||||
const signers = {
|
||||
threshold: 2,
|
||||
weights: [
|
||||
{address: signer1address, weight: 1},
|
||||
{address: signer2address, weight: 1}
|
||||
]
|
||||
};
|
||||
let minLedgerVersion = null;
|
||||
return payTo(this.api, address).then(() => {
|
||||
return this.api.getLedgerVersion().then(ledgerVersion => {
|
||||
minLedgerVersion = ledgerVersion;
|
||||
return this.api.prepareSettings(address, {signers}, instructions)
|
||||
.then(prepared => {
|
||||
return testTransaction(this, 'settings', ledgerVersion, prepared,
|
||||
address, secret);
|
||||
});
|
||||
});
|
||||
}).then(() => {
|
||||
const multisignInstructions =
|
||||
_.assign({}, instructions, {signersCount: 2});
|
||||
return this.api.prepareSettings(
|
||||
address, {domain: 'example.com'}, multisignInstructions)
|
||||
.then(prepared => {
|
||||
const signed1 = this.api.sign(
|
||||
prepared.txJSON, signer1secret, {signAs: signer1address});
|
||||
const signed2 = this.api.sign(
|
||||
prepared.txJSON, signer2secret, {signAs: signer2address});
|
||||
const combined = this.api.combine([
|
||||
signed1.signedTransaction, signed2.signedTransaction
|
||||
]);
|
||||
return this.api.submit(combined.signedTransaction)
|
||||
.then(response => acceptLedger(this.api).then(() => response))
|
||||
.then(response => {
|
||||
assert.strictEqual(response.resultCode, 'tesSUCCESS');
|
||||
const options = {minLedgerVersion};
|
||||
return verifyTransaction(this, combined.id, 'settings',
|
||||
options, {}, address);
|
||||
}).catch(error => {
|
||||
console.log(error.message);
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
961
test/integration/rippled.cfg
Normal file
961
test/integration/rippled.cfg
Normal file
@@ -0,0 +1,961 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Rippled Server Instance Configuration Example
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Contents
|
||||
#
|
||||
# 1. Server
|
||||
#
|
||||
# 2. Peer Protocol
|
||||
#
|
||||
# 3. Ripple Protocol
|
||||
#
|
||||
# 4. HTTPS Client
|
||||
#
|
||||
# 5. Database
|
||||
#
|
||||
# 6. Diagnostics
|
||||
#
|
||||
# 7. Voting
|
||||
#
|
||||
# 8. Example Settings
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Purpose
|
||||
#
|
||||
# This file documents and provides examples of all rippled server process
|
||||
# configuration options. When the rippled server instance is launched, it
|
||||
# looks for a file with the following name:
|
||||
#
|
||||
# rippled.cfg
|
||||
#
|
||||
# For more information on where the rippled server instance searches for
|
||||
# the file please visit the Ripple wiki. Specifically, the section explaining
|
||||
# the --conf command line option:
|
||||
#
|
||||
# https://ripple.com/wiki/Rippled#--conf.3Dpath
|
||||
#
|
||||
# This file should be named rippled.cfg. This file is UTF-8 with Dos, UNIX,
|
||||
# or Mac style end of lines. Blank lines and lines beginning with '#' are
|
||||
# ignored. Undefined sections are reserved. No escapes are currently defined.
|
||||
#
|
||||
# Notation
|
||||
#
|
||||
# In this document a simple BNF notation is used. Angle brackets denote
|
||||
# required elements, square brackets denote optional elements, and single
|
||||
# quotes indicate string literals. A vertical bar separating 1 or more
|
||||
# elements is a logical "or"; Any one of the elements may be chosen.
|
||||
# Parenthesis are notational only, and used to group elements, they are not
|
||||
# part of the syntax unless they appear in quotes. White space may always
|
||||
# appear between elements, it has no effect on values.
|
||||
#
|
||||
# <key> A required identifier
|
||||
# '=' The equals sign character
|
||||
# | Logical "or"
|
||||
# ( ) Used for grouping
|
||||
#
|
||||
#
|
||||
# An identifier is a string of upper or lower case letters, digits, or
|
||||
# underscores subject to the requirement that the first character of an
|
||||
# identifier must be a letter. Identifiers are not case sensitive (but
|
||||
# values may be).
|
||||
#
|
||||
# Some configuration sections contain key/value pairs. A line containing
|
||||
# a key/value pair has this syntax:
|
||||
#
|
||||
# <identifier> '=' <value>
|
||||
#
|
||||
# Depending on the section and key, different value types are possible:
|
||||
#
|
||||
# <integer> A signed integer
|
||||
# <unsigned> An unsigned integer
|
||||
# <flag> A boolean. 1 = true/yes/on, 0 = false/no/off.
|
||||
#
|
||||
# Consult the documentation on the key in question to determine the possible
|
||||
# value types.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 1. Server
|
||||
#
|
||||
#----------
|
||||
#
|
||||
#
|
||||
#
|
||||
# rippled offers various server protocols to clients making inbound
|
||||
# connections. The listening ports rippled uses are "universal" ports
|
||||
# which may be configured to handshake in one or more of the available
|
||||
# supported protocols. These universal ports simplify administration:
|
||||
# A single open port can be used for multiple protocols.
|
||||
#
|
||||
# NOTE At least one server port must be defined in order
|
||||
# to accept incoming network connections.
|
||||
#
|
||||
#
|
||||
# [server]
|
||||
#
|
||||
# A list of port names and key/value pairs. A port name must start with a
|
||||
# letter and contain only letters and numbers. The name is not case-sensitive.
|
||||
# For each name in this list, rippled will look for a configuration file
|
||||
# section with the same name and use it to create a listening port. The
|
||||
# name is informational only; the choice of name does not affect the function
|
||||
# of the listening port.
|
||||
#
|
||||
# Key/value pairs specified in this section are optional, and apply to all
|
||||
# listening ports unless the port overrides the value in its section. They
|
||||
# may be considered default values.
|
||||
#
|
||||
# Suggestion:
|
||||
#
|
||||
# To avoid a conflict with port names and future configuration sections,
|
||||
# we recommend prepending "port_" to the port name. This prefix is not
|
||||
# required, but suggested.
|
||||
#
|
||||
# This example defines two ports with different port numbers and settings:
|
||||
#
|
||||
# [server]
|
||||
# port_public
|
||||
# port_private
|
||||
# port = 80
|
||||
#
|
||||
# [port_public]
|
||||
# ip=0.0.0.0
|
||||
# port = 443
|
||||
# protocol=peer,https
|
||||
#
|
||||
# [port_private]
|
||||
# ip=127.0.0.1
|
||||
# protocol=http
|
||||
#
|
||||
# When rippled is used as a command line client (for example, issuing a
|
||||
# server stop command), the first port advertising the http or https
|
||||
# protocol will be used to make the connection.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [<name>]
|
||||
#
|
||||
# A series of key/value pairs that define the settings for the port with
|
||||
# the corresponding name. These keys are possible:
|
||||
#
|
||||
# ip = <IP-address>
|
||||
#
|
||||
# Required. Determines the IP address of the network interface to bind
|
||||
# to. To bind to all available interfaces, uses 0.0.0.0
|
||||
#
|
||||
# port = <number>
|
||||
#
|
||||
# Required. Sets the port number to use for this port.
|
||||
#
|
||||
# protocol = [ http, https, peer ]
|
||||
#
|
||||
# Required. A comma-separated list of protocols to support:
|
||||
#
|
||||
# http JSON-RPC over HTTP
|
||||
# https JSON-RPC over HTTPS
|
||||
# ws Websockets
|
||||
# wss Secure Websockets
|
||||
# peer Peer Protocol
|
||||
#
|
||||
# Restrictions:
|
||||
#
|
||||
# Only one port may be configured to support the peer protocol.
|
||||
# A port cannot have websocket and non websocket protocols at the
|
||||
# same time. It is possible have both Websockets and Secure Websockets
|
||||
# together in one port.
|
||||
#
|
||||
# NOTE If no ports support the peer protocol, rippled cannot
|
||||
# receive incoming peer connections or become a superpeer.
|
||||
#
|
||||
# user = <text>
|
||||
# password = <text>
|
||||
#
|
||||
# When set, these credentials will be required on HTTP/S requests.
|
||||
# The credentials must be provided using HTTP's Basic Authentication
|
||||
# headers. If either or both fields are empty, then no credentials are
|
||||
# required. IP address restrictions, if any, will be checked in addition
|
||||
# to the credentials specified here.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# using HTTP's Basic Authentication headers when making outbound HTTP/S
|
||||
# requests.
|
||||
#
|
||||
# admin = [ IP, IP, IP, ... ]
|
||||
#
|
||||
# A comma-separated list of IP addresses.
|
||||
#
|
||||
# When set, grants administrative command access to the specified IP
|
||||
# addresses. These commands may be issued over http, https, ws, or wss
|
||||
# if configured on the port. If unspecified, the default is to not allow
|
||||
# administrative commands.
|
||||
#
|
||||
# *SECURITY WARNING*
|
||||
# 0.0.0.0 may be specified to allow access from any IP address. It must
|
||||
# be the only address specified and cannot be combined with other IPs.
|
||||
# Use of this address can compromise server security, please consider its
|
||||
# use carefully.
|
||||
#
|
||||
# admin_user = <text>
|
||||
# admin_password = <text>
|
||||
#
|
||||
# When set, clients must provide these credentials in the submitted
|
||||
# JSON for any administrative command requests submitted to the HTTP/S,
|
||||
# WS, or WSS protocol interfaces. If administrative commands are
|
||||
# disabled for a port, these credentials have no effect.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# in the submitted JSON for any administrative command requests when
|
||||
# invoking JSON-RPC commands on remote servers.
|
||||
#
|
||||
# ssl_key = <filename>
|
||||
# ssl_cert = <filename>
|
||||
# ssl_chain = <filename>
|
||||
#
|
||||
# Use the specified files when configuring SSL on the port.
|
||||
#
|
||||
# NOTE If no files are specified and secure protocols are selected,
|
||||
# rippled will generate an internal self-signed certificate.
|
||||
#
|
||||
# The files have these meanings:
|
||||
#
|
||||
# ssl_key
|
||||
#
|
||||
# Specifies the filename holding the SSL key in PEM format.
|
||||
#
|
||||
# ssl_cert
|
||||
#
|
||||
# Specifies the path to the SSL certificate file in PEM format.
|
||||
# This is not needed if the chain includes it.
|
||||
#
|
||||
# ssl_chain
|
||||
#
|
||||
# If you need a certificate chain, specify the path to the
|
||||
# certificate chain here. The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_startup]
|
||||
#
|
||||
# Specify a list of RPC commands to run at startup.
|
||||
#
|
||||
# Examples:
|
||||
# { "command" : "server_info" }
|
||||
# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ping_frequency]
|
||||
#
|
||||
# <number>
|
||||
#
|
||||
# The amount of time to wait in seconds, before sending a websocket 'ping'
|
||||
# message. Ping messages are used to determine if the remote end of the
|
||||
# connection is no longer available.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 2. Peer Protocol
|
||||
#
|
||||
#-----------------
|
||||
#
|
||||
# These settings control security and access attributes of the Peer to Peer
|
||||
# server section of the rippled process. Peer Protocol implements the
|
||||
# Ripple Payment protocol. It is over peer connections that transactions
|
||||
# and validations are passed from to machine to machine, to determine the
|
||||
# contents of validated ledgers.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [ips]
|
||||
#
|
||||
# List of hostnames or ips where the Ripple protocol is served. For a starter
|
||||
# list, you can either copy entries from: https://ripple.com/ripple.txt or if
|
||||
# you prefer you can specify r.ripple.com 51235
|
||||
#
|
||||
# One IPv4 address or domain names per line is allowed. A port may must be
|
||||
# specified after adding a space to the address. By convention, if known,
|
||||
# IPs are listed in from most to least trusted.
|
||||
#
|
||||
# Examples:
|
||||
# 192.168.0.1
|
||||
# 192.168.0.1 3939
|
||||
# r.ripple.com 51235
|
||||
#
|
||||
# This will give you a good, up-to-date list of addresses:
|
||||
#
|
||||
# [ips]
|
||||
# r.ripple.com 51235
|
||||
#
|
||||
# The default is: [ips_fixed] addresses (if present) or r.ripple.com 51235
|
||||
#
|
||||
#
|
||||
# [ips_fixed]
|
||||
#
|
||||
# List of IP addresses or hostnames to which rippled should always attempt to
|
||||
# maintain peer connections with. This is useful for manually forming private
|
||||
# networks, for example to configure a validation server that connects to the
|
||||
# Ripple network through a public-facing server, or for building a set
|
||||
# of cluster peers.
|
||||
#
|
||||
# One IPv4 address or domain names per line is allowed. A port must be
|
||||
# specified after adding a space to the address.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_private]
|
||||
#
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0: Request peers to broadcast your address. Normal outbound peer connections [default]
|
||||
# 1: Request peers not broadcast your address. Only connect to configured peers.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peers_max]
|
||||
#
|
||||
# The largest number of desired peer connections (incoming or outgoing).
|
||||
# Cluster and fixed peers do not count towards this total. There are
|
||||
# implementation-defined lower limits imposed on this value for security
|
||||
# purposes.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [node_seed]
|
||||
#
|
||||
# This is used for clustering. To force a particular node seed or key, the
|
||||
# key can be set here. The format is the same as the validation_seed field.
|
||||
# To obtain a validation seed, use the validation_create command.
|
||||
#
|
||||
# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
|
||||
# shfArahZT9Q9ckTf3s1psJ7C7qzVN
|
||||
#
|
||||
#
|
||||
#
|
||||
# [cluster_nodes]
|
||||
#
|
||||
# To extend full trust to other nodes, place their node public keys here.
|
||||
# Generally, you should only do this for nodes under common administration.
|
||||
# Node public keys start with an 'n'. To give a node a name for identification
|
||||
# place a space after the public key and then the name.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [sntp_servers]
|
||||
#
|
||||
# IP address or domain of NTP servers to use for time synchronization.
|
||||
#
|
||||
# These NTP servers are suitable for rippled servers located in the United
|
||||
# States:
|
||||
# time.windows.com
|
||||
# time.apple.com
|
||||
# time.nist.gov
|
||||
# pool.ntp.org
|
||||
#
|
||||
#
|
||||
#
|
||||
# [overlay]
|
||||
#
|
||||
# Controls settings related to the peer to peer overlay.
|
||||
#
|
||||
# A set of key/value pair parameters to configure the overlay.
|
||||
#
|
||||
# public_ip = <IP-address>
|
||||
#
|
||||
# If the server has a known, fixed public IPv4 address,
|
||||
# specify that IP address here in dotted decimal notation.
|
||||
# Peers will use this information to reject attempt to proxy
|
||||
# connections to or from this server.
|
||||
#
|
||||
# ip_limit = <number>
|
||||
#
|
||||
# The maximum number of incoming peer connections allowed by a single
|
||||
# IP that isn't classified as "private" in RFC1918. The implementation
|
||||
# imposes some hard and soft upper limits on this value to prevent a
|
||||
# single host from consuming all inbound slots. If the value is not
|
||||
# present the server will autoconfigure an appropriate limit.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [transaction_queue] EXPERIMENTAL
|
||||
#
|
||||
# This section is EXPERIMENTAL, and should not be
|
||||
# present for production configuration settings.
|
||||
#
|
||||
# A set of key/value pair parameters to tune the performance of the
|
||||
# transaction queue.
|
||||
#
|
||||
# ledgers_in_queue = <number>
|
||||
#
|
||||
# The queue will be limited to this <number> of average ledgers'
|
||||
# worth of transactions. If the queue fills up, the transactions
|
||||
# with the lowest fees will be dropped from the queue any time a
|
||||
# transaction with a higher fee level is added. Default: 20.
|
||||
#
|
||||
# retry_sequence_percent = <number>
|
||||
#
|
||||
# If a client resubmits a transaction, the new transaction's fee
|
||||
# must be more than <number> percent higher than the original
|
||||
# transaction's fee, or meet the current open ledger fee to be
|
||||
# considered. Default: 125.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 3. Ripple Protocol
|
||||
#
|
||||
#-------------------
|
||||
#
|
||||
# These settings affect the behavior of the server instance with respect
|
||||
# to Ripple payment protocol level activities such as validating and
|
||||
# closing ledgers, establishing a quorum, or adjusting fees in response
|
||||
# to server overloads.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [node_size]
|
||||
#
|
||||
# Tunes the servers based on the expected load and available memory. Legal
|
||||
# sizes are "tiny", "small", "medium", "large", and "huge". We recommend
|
||||
# you start at the default and raise the setting if you have extra memory.
|
||||
# The default is "tiny".
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validation_quorum]
|
||||
#
|
||||
# Sets the minimum number of trusted validations a ledger must have before
|
||||
# the server considers it fully validated. Note that if you are validating,
|
||||
# your validation counts.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [ledger_history]
|
||||
#
|
||||
# The number of past ledgers to acquire on server startup and the minimum to
|
||||
# maintain while running.
|
||||
#
|
||||
# To serve clients, servers need historical ledger data. Servers that don't
|
||||
# need to serve clients can set this to "none". Servers that want complete
|
||||
# history can set this to "full".
|
||||
#
|
||||
# This must be less than or equal to online_delete (if online_delete is used)
|
||||
#
|
||||
# The default is: 256
|
||||
#
|
||||
#
|
||||
#
|
||||
# [fetch_depth]
|
||||
#
|
||||
# The number of past ledgers to serve to other peers that request historical
|
||||
# ledger data (or "full" for no limit).
|
||||
#
|
||||
# Servers that require low latency and high local performance may wish to
|
||||
# restrict the historical ledgers they are willing to serve. Setting this
|
||||
# below 32 can harm network stability as servers require easy access to
|
||||
# recent history to stay in sync. Values below 128 are not recommended.
|
||||
#
|
||||
# The default is: full
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validation_seed]
|
||||
#
|
||||
# To perform validation, this section should contain either a validation seed
|
||||
# or key. The validation seed is used to generate the validation
|
||||
# public/private key pair. To obtain a validation seed, use the
|
||||
# validation_create command.
|
||||
#
|
||||
# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
|
||||
# shfArahZT9Q9ckTf3s1psJ7C7qzVN
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validators]
|
||||
#
|
||||
# List of nodes to always accept as validators. Nodes are specified by domain
|
||||
# or public key.
|
||||
#
|
||||
# For domains, rippled will probe for https web servers at the specified
|
||||
# domain in the following order: ripple.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# For public key entries, a comment may optionally be specified after adding
|
||||
# a space to the public key.
|
||||
#
|
||||
# Examples:
|
||||
# ripple.com
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validators_file]
|
||||
#
|
||||
# Path to file contain a list of nodes to always accept as validators. Use
|
||||
# this to specify a file other than this file to manage your validators list.
|
||||
#
|
||||
# If this entry is not present or empty and no nodes from previous runs were
|
||||
# found in the database, rippled will look for a validators.txt in the config
|
||||
# directory. If not found there, it will attempt to retrieve the file from
|
||||
# the [validators_site] web site.
|
||||
#
|
||||
# After specifying a different [validators_file] or changing the contents of
|
||||
# the validators file, issue a RPC unl_load command to have rippled load the
|
||||
# file.
|
||||
#
|
||||
# Specify the file by specifying its full path.
|
||||
#
|
||||
# Examples:
|
||||
# C:/home/johndoe/ripple/validators.txt
|
||||
# /home/johndoe/ripple/validators.txt
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validators_site]
|
||||
#
|
||||
# Specifies where to find validators.txt for UNL boostrapping and RPC
|
||||
# unl_network command.
|
||||
#
|
||||
# Example: ripple.com
|
||||
#
|
||||
#
|
||||
#
|
||||
# [path_search]
|
||||
# When searching for paths, the default search aggressiveness. This can take
|
||||
# exponentially more resources as the size is increased.
|
||||
#
|
||||
# The default is: 7
|
||||
#
|
||||
# [path_search_fast]
|
||||
# [path_search_max]
|
||||
# When searching for paths, the minimum and maximum search aggressiveness.
|
||||
#
|
||||
# If you do not need pathfinding, you can set path_search_max to zero to
|
||||
# disable it and avoid some expensive bookkeeping.
|
||||
#
|
||||
# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 10.
|
||||
#
|
||||
# [path_search_old]
|
||||
#
|
||||
# For clients that use the legacy path finding interfaces, the search
|
||||
# aggressiveness to use. The default is 7.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [fee_default]
|
||||
#
|
||||
# Sets the base cost of a transaction in drops. Used when the server has
|
||||
# no other source of fee information, such as signing transactions offline.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 4. HTTPS Client
|
||||
#
|
||||
#----------------
|
||||
#
|
||||
# The rippled server instance uses HTTPS GET requests in a variety of
|
||||
# circumstances, including but not limited to contacting trusted domains to
|
||||
# fetch information such as mapping an email address to a Ripple Payment
|
||||
# Network address.
|
||||
#
|
||||
# [ssl_verify]
|
||||
#
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0. HTTPS client connections will not verify certificates.
|
||||
# 1. Certificates will be checked for HTTPS client connections.
|
||||
#
|
||||
# If not specified, this parameter defaults to 1.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [ssl_verify_file]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the certificate verification file for
|
||||
# HTTPS client requests.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [ssl_verify_dir]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
#
|
||||
# A file system path leading to a file or directory containing the root
|
||||
# certificates that the server will accept for verifying HTTP servers.
|
||||
# Used only for outbound HTTPS client connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 5. Database
|
||||
#
|
||||
#------------
|
||||
#
|
||||
# rippled creates 4 SQLite database to hold bookkeeping information
|
||||
# about transactions, local credentials, and various other things.
|
||||
# It also creates the NodeDB, which holds all the objects that
|
||||
# make up the current and historical ledgers.
|
||||
#
|
||||
# The size of the NodeDB grows in proportion to the amount of new data and the
|
||||
# amount of historical data (a configurable setting) so the performance of the
|
||||
# underlying storage media where the NodeDB is placed can significantly affect
|
||||
# the performance of the server.
|
||||
#
|
||||
# Partial pathnames will be considered relative to the location of
|
||||
# the rippled.cfg file.
|
||||
#
|
||||
# [node_db] Settings for the Node Database (required)
|
||||
#
|
||||
# Format (without spaces):
|
||||
# One or more lines of case-insensitive key / value pairs:
|
||||
# <key> '=' <value>
|
||||
# ...
|
||||
#
|
||||
# Example:
|
||||
# type=nudb
|
||||
# path=db/nudb
|
||||
#
|
||||
# The "type" field must be present and controls the choice of backend:
|
||||
#
|
||||
# type = NuDB
|
||||
#
|
||||
# NuDB is a high-performance database written by Ripple Labs and optimized
|
||||
# for rippled and solid-state drives.
|
||||
#
|
||||
# NuDB maintains its high speed regardless of the amount of history
|
||||
# stored. Online delete may be selected, but is not required. NuDB is
|
||||
# available on all platforms that rippled runs on.
|
||||
#
|
||||
# type = RocksDB
|
||||
#
|
||||
# RocksDB is an open-source, general-purpose key/value store - see
|
||||
# http://rocksdb.org/ for more details.
|
||||
#
|
||||
# RocksDB is an alternative backend for systems that don't use solid-state
|
||||
# drives. Because RocksDB's performance degrades as it stores more data,
|
||||
# keeping full history is not advised, and using online delete is
|
||||
# recommended. RocksDB is not available on Windows.
|
||||
#
|
||||
# The RocksDB backend also provides these optional parameters:
|
||||
#
|
||||
# compression 0 for none, 1 for Snappy compression
|
||||
#
|
||||
#
|
||||
#
|
||||
# Required keys:
|
||||
# path Location to store the database (all types)
|
||||
#
|
||||
# Optional keys:
|
||||
#
|
||||
# These keys are possible for any type of backend:
|
||||
#
|
||||
# online_delete Minimum value of 256. Enable automatic purging
|
||||
# of older ledger information. Maintain at least this
|
||||
# number of ledger records online. Must be greater
|
||||
# than or equal to ledger_history.
|
||||
#
|
||||
# advisory_delete 0 for disabled, 1 for enabled. If set, then
|
||||
# require administrative RPC call "can_delete"
|
||||
# to enable online deletion of ledger records.
|
||||
#
|
||||
# Notes:
|
||||
# The 'node_db' entry configures the primary, persistent storage.
|
||||
#
|
||||
# The 'import_db' is used with the '--import' command line option to
|
||||
# migrate the specified database into the current database given
|
||||
# in the [node_db] section.
|
||||
#
|
||||
# [import_db] Settings for performing a one-time import (optional)
|
||||
# [database_path] Path to the book-keeping databases.
|
||||
#
|
||||
# There are 4 bookkeeping SQLite database that the server creates and
|
||||
# maintains. If you omit this configuration setting, it will default to
|
||||
# creating a directory called "db" located in the same place as your
|
||||
# rippled.cfg file. Partial pathnames will be considered relative to
|
||||
# the location of the rippled executable.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 6. Diagnostics
|
||||
#
|
||||
#---------------
|
||||
#
|
||||
# These settings are designed to help server administrators diagnose
|
||||
# problems, and obtain detailed information about the activities being
|
||||
# performed by the rippled process.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [debug_logfile]
|
||||
#
|
||||
# Specifies where a debug logfile is kept. By default, no debug log is kept.
|
||||
# Unless absolute, the path is relative the directory containing this file.
|
||||
#
|
||||
# Example: debug.log
|
||||
#
|
||||
#
|
||||
#
|
||||
# [insight]
|
||||
#
|
||||
# Configuration parameters for the Beast. Insight stats collection module.
|
||||
#
|
||||
# Insight is a module that collects information from the areas of rippled
|
||||
# that have instrumentation. The configuration parameters control where the
|
||||
# collection metrics are sent. The parameters are expressed as key = value
|
||||
# pairs with no white space. The main parameter is the choice of server:
|
||||
#
|
||||
# "server"
|
||||
#
|
||||
# Choice of server to send metrics to. Currently the only choice is
|
||||
# "statsd" which sends UDP packets to a StatsD daemon, which must be
|
||||
# running while rippled is running. More information on StatsD is
|
||||
# available here:
|
||||
# https://github.com/b/statsd_spec
|
||||
#
|
||||
# When server=statsd, these additional keys are used:
|
||||
#
|
||||
# "address" The UDP address and port of the listening StatsD server,
|
||||
# in the format, n.n.n.n:port.
|
||||
#
|
||||
# "prefix" A string prepended to each collected metric. This is used
|
||||
# to distinguish between different running instances of rippled.
|
||||
#
|
||||
# If this section is missing, or the server type is unspecified or unknown,
|
||||
# statistics are not collected or reported.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# [insight]
|
||||
# server=statsd
|
||||
# address=192.168.0.95:4201
|
||||
# prefix=my_validator
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 7. Voting
|
||||
#
|
||||
#----------
|
||||
#
|
||||
# The vote settings configure settings for the entire Ripple network.
|
||||
# While a single instance of rippled cannot unilaterally enforce network-wide
|
||||
# settings, these choices become part of the instance's vote during the
|
||||
# consensus process for each voting ledger.
|
||||
#
|
||||
# [voting]
|
||||
#
|
||||
# A set of key/value pair parameters used during voting ledgers.
|
||||
#
|
||||
# reference_fee = <drops>
|
||||
#
|
||||
# The cost of the reference transaction fee, specified in drops.
|
||||
# The reference transaction is the simplest form of transaction.
|
||||
# It represents an XRP payment between two parties.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# reference_fee = 10 # 10 drops
|
||||
#
|
||||
# account_reserve = <drops>
|
||||
#
|
||||
# The account reserve requirement is specified in drops. The portion of an
|
||||
# account's XRP balance that is at or below the reserve may only be
|
||||
# spent on transaction fees, and not transferred out of the account.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# account_reserve = 20000000 # 20 XRP
|
||||
#
|
||||
# owner_reserve = <drops>
|
||||
#
|
||||
# The owner reserve is the amount of XRP reserved in the account for
|
||||
# each ledger item owned by the account. Ledger items an account may
|
||||
# own include trust lines, open orders, and tickets.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# owner_reserve = 5000000 # 5 XRP
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 8. Example Settings
|
||||
#
|
||||
#--------------------
|
||||
#
|
||||
# Administrators can use these values as a starting point for configuring
|
||||
# their instance of rippled, but each value should be checked to make sure
|
||||
# it meets the business requirements for the organization.
|
||||
#
|
||||
# Server
|
||||
#
|
||||
# These example configuration settings create these ports:
|
||||
#
|
||||
# "peer"
|
||||
#
|
||||
# Peer protocol open to everyone. This is required to accept
|
||||
# incoming rippled connections. This does not affect automatic
|
||||
# or manual outgoing Peer protocol connections.
|
||||
#
|
||||
# "rpc"
|
||||
#
|
||||
# Administrative RPC commands over HTTPS, when originating from
|
||||
# the same machine (via the loopback adapter at 127.0.0.1).
|
||||
#
|
||||
# "wss_admin"
|
||||
#
|
||||
# Admin level API commands over Secure Websockets, when originating
|
||||
# from the same machine (via the loopback adapter at 127.0.0.1).
|
||||
#
|
||||
# This port is commented out but can be enabled by removing
|
||||
# the '#' from each corresponding line including the entry under [server]
|
||||
#
|
||||
# "wss_public"
|
||||
#
|
||||
# Guest level API commands over Secure Websockets, open to everyone.
|
||||
#
|
||||
# For HTTPS and Secure Websockets ports, if no certificate and key file
|
||||
# are specified then a self-signed certificate will be generated on startup.
|
||||
# If you have a certificate and key file, uncomment the corresponding lines
|
||||
# and ensure the paths to the files are correct.
|
||||
#
|
||||
# NOTE
|
||||
#
|
||||
# To accept connections on well known ports such as 80 (HTTP) or
|
||||
# 443 (HTTPS), most operating systems will require rippled to
|
||||
# run with administrator privileges, or else rippled will not start.
|
||||
|
||||
[server]
|
||||
port_rpc_admin_local
|
||||
#port_peer
|
||||
port_ws_admin_local
|
||||
#port_ws_public
|
||||
#port_ws_admin_public
|
||||
#ssl_key = /etc/ssl/private/server.key
|
||||
#ssl_cert = /etc/ssl/certs/server.crt
|
||||
|
||||
[port_rpc_admin_local]
|
||||
port = 5005
|
||||
ip = 127.0.0.1
|
||||
admin = 127.0.0.1
|
||||
protocol = http
|
||||
|
||||
[port_peer]
|
||||
port = 51235
|
||||
ip = 0.0.0.0
|
||||
protocol = peer
|
||||
|
||||
[port_ws_admin_local]
|
||||
port = 6006
|
||||
ip = 127.0.0.1
|
||||
admin = 127.0.0.1
|
||||
protocol = ws
|
||||
|
||||
[port_ws_admin_public]
|
||||
port = 5007
|
||||
ip = 0.0.0.0
|
||||
admin = 192.168.50.1
|
||||
protocol = ws
|
||||
|
||||
[port_ws_public]
|
||||
port = 5006
|
||||
ip = 0.0.0.0
|
||||
protocol = ws
|
||||
|
||||
#[port_ws_public]
|
||||
#port = 5005
|
||||
#ip = 127.0.0.1
|
||||
#protocol = wss
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
[node_size]
|
||||
medium
|
||||
|
||||
# This is primary persistent datastore for rippled. This includes transaction
|
||||
# metadata, account states, and ledger headers. Helpful information can be
|
||||
# found here: https://ripple.com/wiki/NodeBackEnd
|
||||
# delete old ledgers while maintaining at least 2000. Do not require an
|
||||
# external administrative command to initiate deletion.
|
||||
[node_db]
|
||||
type=RocksDB
|
||||
path=/var/lib/rippled/db/rocksdb
|
||||
open_files=2000
|
||||
filter_bits=12
|
||||
cache_mb=256
|
||||
file_size_mb=8
|
||||
file_size_mult=2
|
||||
online_delete=2000
|
||||
advisory_delete=0
|
||||
|
||||
[database_path]
|
||||
/var/lib/rippled/db
|
||||
|
||||
# This needs to be an absolute directory reference, not a relative one.
|
||||
# Modify this value as required.
|
||||
[debug_logfile]
|
||||
/var/log/rippled.debug.log
|
||||
|
||||
[sntp_servers]
|
||||
time.windows.com
|
||||
time.apple.com
|
||||
time.nist.gov
|
||||
pool.ntp.org
|
||||
|
||||
# Where to find some other servers speaking the Ripple protocol.
|
||||
#
|
||||
#[ips]
|
||||
#r.ripple.com 51235
|
||||
|
||||
# Public keys of the validators that this rippled instance trusts. The latest
|
||||
# list of validators can be obtained from https://ripple.com/ripple.txt
|
||||
#
|
||||
# See also https://wiki.ripple.com/Ripple.txt
|
||||
#
|
||||
[validators]
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
|
||||
n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
# The number of validators rippled needs to accept a consensus.
|
||||
# Don't change this unless you know what you're doing.
|
||||
[validation_quorum]
|
||||
3
|
||||
|
||||
# Turn down default logging to save disk space in the long run.
|
||||
# Valid values here are trace, debug, info, warning, error, and fatal
|
||||
[rpc_startup]
|
||||
{ "command": "log_level", "severity": "trace" }
|
||||
#{ "command": "log_level", "severity": "warning" }
|
||||
|
||||
# If ssl_verify is 1, certificates will be validated.
|
||||
# To allow the use of self-signed certificates for development or internal use,
|
||||
# set to ssl_verify to 0.
|
||||
[ssl_verify]
|
||||
1
|
||||
|
||||
[features]
|
||||
SusPay
|
||||
MultiSign
|
||||
56
test/integration/utils.js
Normal file
56
test/integration/utils.js
Normal file
@@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
const masterAccount = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh';
|
||||
const masterSecret = 'snoPBrXtMeMyMHUVTgbuqAfg1SUTb';
|
||||
|
||||
function ledgerAccept(api) {
|
||||
const request = {command: 'ledger_accept'};
|
||||
return api.connection.request(request);
|
||||
}
|
||||
|
||||
function pay(api, from, to, amount, secret, currency = 'XRP', counterparty) {
|
||||
const paymentSpecification = {
|
||||
source: {
|
||||
address: from,
|
||||
maxAmount: {
|
||||
value: amount,
|
||||
currency: currency
|
||||
}
|
||||
},
|
||||
destination: {
|
||||
address: to,
|
||||
amount: {
|
||||
value: amount,
|
||||
currency: currency
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (counterparty !== undefined) {
|
||||
paymentSpecification.source.maxAmount.counterparty = counterparty;
|
||||
paymentSpecification.destination.amount.counterparty = counterparty;
|
||||
}
|
||||
|
||||
let id = null;
|
||||
return api.preparePayment(from, paymentSpecification, {})
|
||||
.then(data => api.sign(data.txJSON, secret))
|
||||
.then(signed => {
|
||||
id = signed.id;
|
||||
return api.submit(signed.signedTransaction);
|
||||
})
|
||||
.then(() => ledgerAccept(api))
|
||||
.then(() => id);
|
||||
}
|
||||
|
||||
|
||||
function payTo(api, to, amount = '4003218', currency = 'XRP', counterparty) {
|
||||
return pay(api, masterAccount, to, amount, masterSecret, currency,
|
||||
counterparty);
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
pay,
|
||||
payTo,
|
||||
ledgerAccept
|
||||
};
|
||||
14
test/integration/wallet-web.js
Normal file
14
test/integration/wallet-web.js
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
function getAddress() {
|
||||
return 'rQDhz2ZNXmhxzCYwxU6qAbdxsHA4HV45Y2';
|
||||
}
|
||||
|
||||
function getSecret() {
|
||||
return 'shK6YXzwYfnFVn3YZSaMh5zuAddKx';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAddress,
|
||||
getSecret
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
57
test/localintegrationrunner.html
Normal file
57
test/localintegrationrunner.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- encoding must be set for mocha's special characters to render properly -->
|
||||
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="deb"></div>
|
||||
<div id="mocha"></div>
|
||||
<script src="../node_modules/mocha/mocha.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var phantomTest = /PhantomJS/;
|
||||
if (phantomTest.test(navigator.userAgent)) {
|
||||
// mocha-phantomjs-core has wrong shim for Function.bind, so we
|
||||
// will replace it with correct one
|
||||
// this bind polyfill copied from MDN documentation
|
||||
Function.prototype.bind = function(oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function() {},
|
||||
fBound = function() {
|
||||
return fToBind.apply(this instanceof fNOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// native functions don't have a prototype
|
||||
fNOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script src="../test-compiled-for-web/ripple-for-web-tests.js"></script>
|
||||
<script>
|
||||
mocha.ui('bdd')
|
||||
</script>
|
||||
|
||||
<script src="../test-compiled-for-web/integration/integration-test.js"></script>
|
||||
|
||||
<script>
|
||||
mocha.run()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
63
test/localrunner.html
Normal file
63
test/localrunner.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!-- encoding must be set for mocha's special characters to render properly -->
|
||||
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="deb"></div>
|
||||
<div id="mocha"></div>
|
||||
<script src="../node_modules/mocha/mocha.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var phantomTest = /PhantomJS/;
|
||||
if (phantomTest.test(navigator.userAgent)) {
|
||||
// mocha-phantomjs-core has wrong shim for Function.bind, so we
|
||||
// will replace it with correct one
|
||||
// this bind polyfill copied from MDN documentation
|
||||
Function.prototype.bind = function(oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function() {},
|
||||
fBound = function() {
|
||||
return fToBind.apply(this instanceof fNOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// native functions don't have a prototype
|
||||
fNOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script src="../test-compiled-for-web/ripple-for-web-tests.js"></script>
|
||||
<script>
|
||||
mocha.ui('bdd')
|
||||
</script>
|
||||
|
||||
<script src="../test-compiled-for-web/api-test.js"></script>
|
||||
|
||||
<script src="../test-compiled-for-web/broadcast-api-test.js"></script>
|
||||
|
||||
<script src="../test-compiled-for-web/connection-test.js"></script>
|
||||
|
||||
<script src="../test-compiled-for-web/rangeset-test.js"></script>
|
||||
|
||||
<script>
|
||||
mocha.run()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -72,6 +72,7 @@ module.exports = function(port) {
|
||||
|
||||
mock.on('connection', function(conn) {
|
||||
this.socket = conn;
|
||||
conn.config = {};
|
||||
conn.on('message', function(requestJSON) {
|
||||
const request = JSON.parse(requestJSON);
|
||||
mock.emit('request_' + request.command, request, conn);
|
||||
@@ -95,10 +96,22 @@ module.exports = function(port) {
|
||||
mock.expectedRequests[this.event] -= 1;
|
||||
});
|
||||
|
||||
mock.on('request_config', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'config');
|
||||
conn.config = _.assign(conn.config, request.data);
|
||||
});
|
||||
|
||||
mock.on('request_echo', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'echo');
|
||||
conn.send(JSON.stringify(request.data));
|
||||
});
|
||||
|
||||
mock.on('request_server_info', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'server_info');
|
||||
if (mock.returnErrorOnServerInfo) {
|
||||
if (conn.config.returnErrorOnServerInfo) {
|
||||
conn.send(createResponse(request, fixtures.server_info.error));
|
||||
} else if (conn.config.disconnectOnServerInfo) {
|
||||
conn.terminate();
|
||||
} else {
|
||||
conn.send(createResponse(request, fixtures.server_info.normal));
|
||||
}
|
||||
@@ -249,6 +262,11 @@ module.exports = function(port) {
|
||||
}
|
||||
});
|
||||
|
||||
mock.on('request_submit_multisigned', function(request, conn) {
|
||||
assert.strictEqual(request.command, 'submit_multisigned');
|
||||
conn.send(createResponse(request, fixtures.submit.success));
|
||||
});
|
||||
|
||||
mock.on('request_account_lines', function(request, conn) {
|
||||
if (request.account === addresses.ACCOUNT) {
|
||||
conn.send(accountLinesResponse.normal(request));
|
||||
@@ -305,6 +323,8 @@ module.exports = function(port) {
|
||||
}
|
||||
if (request.source_account === addresses.NOTFOUND) {
|
||||
response = createResponse(request, fixtures.path_find.srcActNotFound);
|
||||
} else if (request.source_account === addresses.SOURCE_LOW_FUNDS) {
|
||||
response = createResponse(request, fixtures.path_find.sourceAmountLow);
|
||||
} else if (request.source_account === addresses.OTHER_ACCOUNT) {
|
||||
response = createResponse(request, fixtures.path_find.sendUSD);
|
||||
} else if (request.source_account === addresses.THIRD_ACCOUNT) {
|
||||
|
||||
15
test/mocked-server.js
Normal file
15
test/mocked-server.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
const port = 34371;
|
||||
|
||||
const createMockRippled = require('./mock-rippled');
|
||||
|
||||
function main() {
|
||||
console.log('starting server on port ' + port);
|
||||
createMockRippled(port);
|
||||
console.log('starting server on port ' + String(port + 1));
|
||||
createMockRippled(port + 1);
|
||||
}
|
||||
|
||||
main();
|
||||
41
test/setup-api-web.js
Normal file
41
test/setup-api-web.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
'use strict';
|
||||
|
||||
const {RippleAPI, RippleAPIBroadcast} = require('ripple-api');
|
||||
const ledgerClosed = require('./fixtures/rippled/ledger-close');
|
||||
|
||||
const port = 34371;
|
||||
|
||||
function setup(port_ = port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api = new RippleAPI({server: 'ws://localhost:' + port_});
|
||||
this.api.connect().then(() => {
|
||||
this.api.once('ledger', () => resolve());
|
||||
this.api.connection._ws.emit('message', JSON.stringify(ledgerClosed));
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
function setupBroadcast() {
|
||||
const servers = [port, port + 1].map(port_ => 'ws://localhost:' + port_);
|
||||
this.api = new RippleAPIBroadcast(servers);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.api.connect().then(() => {
|
||||
this.api.once('ledger', () => resolve());
|
||||
this.api._apis[0].connection._ws.emit('message',
|
||||
JSON.stringify(ledgerClosed));
|
||||
}).catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
if (this.api.isConnected()) {
|
||||
return this.api.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setup: setup,
|
||||
teardown: teardown,
|
||||
setupBroadcast: setupBroadcast
|
||||
};
|
||||
Reference in New Issue
Block a user