Merge branch 'develop' into release

* develop:
  Update ws to 1.0.1
  run integration tests using standalone server
  Add multisignature support
  Add sample code to cancel all orders for a specified account
  Remove references to browser support
  add check for windows eol on commit removes windows eols from some files
  Fix error on ledger subscription message without validated_ledgers
This commit is contained in:
Alan Cohen
2016-01-04 19:47:24 -08:00
79 changed files with 2541 additions and 1076 deletions

View File

@@ -1,6 +1,6 @@
#ripple-lib #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
[![Circle CI](https://circleci.com/gh/ripple/ripple-lib/tree/develop.svg?style=svg)](https://circleci.com/gh/ripple/ripple-lib/tree/develop) [![Coverage Status](https://coveralls.io/repos/ripple/ripple-lib/badge.png?branch=develop)](https://coveralls.io/r/ripple/ripple-lib?branch=develop) [![Circle CI](https://circleci.com/gh/ripple/ripple-lib/tree/develop.svg?style=svg)](https://circleci.com/gh/ripple/ripple-lib/tree/develop) [![Coverage Status](https://coveralls.io/repos/ripple/ripple-lib/badge.png?branch=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 ###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 + Issue [rippled API](https://ripple.com/build/rippled-apis/) requests
+ Listen to events on the Ripple network (transaction, ledger, etc.) + Listen to events on the Ripple network (transaction, ledger, etc.)
+ Sign and submit transactions to the Ripple network + Sign and submit transactions to the Ripple network

View File

@@ -1,7 +1,16 @@
machine: machine:
node: node:
version: 0.12.0 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: test:
pre:
- rippled -a --start --conf "$HOME/$CIRCLE_PROJECT_REPONAME/test/integration/rippled.cfg":
background: true
override: override:
- scripts/ci.sh "$CIRCLE_NODE_INDEX" "$CIRCLE_NODE_TOTAL": - scripts/ci.sh "$CIRCLE_NODE_INDEX" "$CIRCLE_NODE_TOTAL":
parallel: true parallel: true
post:
- killall /usr/bin/rippled

View File

@@ -54,6 +54,7 @@
- [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation) - [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
- [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution) - [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
- [sign](#sign) - [sign](#sign)
- [combine](#combine)
- [submit](#submit) - [submit](#submit)
- [generateAddress](#generateaddress) - [generateAddress](#generateaddress)
- [computeLedgerHash](#computeledgerhash) - [computeLedgerHash](#computeledgerhash)
@@ -269,7 +270,7 @@ Executing a transaction with `RippleAPI` requires the following four steps:
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation) * [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation) * [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution) * [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. 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. 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. 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. 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. 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. 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. 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 accounts issuances. requireAuthorization | boolean | *Optional* If set, this account must individually approve other users in order for those users to hold this accounts issuances.
requireDestinationTag | boolean | *Optional* Requires incoming payments to specify a destination tag. 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 accounts issuances, represented as billionths of a unit. Use `null` to set no fee. transferRate | number,null | *Optional* The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.
### Example ### Example
@@ -1599,18 +1607,18 @@ paths | string | The paths of trustlines and orders to use in executing the paym
### Example ### Example
```javascript ```javascript
const pathfind = { const pathfind = {
"source": { "source": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59" "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
}, },
"destination": { "destination": {
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo", "address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"amount": { "amount": {
"currency": "USD", "currency": "USD",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "100" "value": "100"
} }
} }
}; };
return api.getPaths(pathfind) return api.getPaths(pathfind)
.then(paths => {/* ... */}); .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. 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 accounts issuances. requireAuthorization | boolean | *Optional* If set, this account must individually approve other users in order for those users to hold this accounts issuances.
requireDestinationTag | boolean | *Optional* Requires incoming payments to specify a destination tag. 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 accounts issuances, represented as billionths of a unit. Use `null` to set no fee. transferRate | number,null | *Optional* The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.
### Example ### Example
@@ -3282,7 +3296,7 @@ return api.prepareSuspendedPaymentExecution(address, suspendedPaymentExecution).
## sign ## 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). 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. txJSON | string | Transaction represented as a JSON string in rippled format.
secret | secret string | The secret of the account that is initiating the transaction. 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 ### 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
`submit(signedTransaction: string): Promise<Object>` `submit(signedTransaction: string): Promise<Object>`

38
docs/samples/cancelall.js Normal file
View 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
View 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") %>

View File

@@ -31,6 +31,7 @@
<% include prepareSuspendedPaymentCancellation.md.ejs %> <% include prepareSuspendedPaymentCancellation.md.ejs %>
<% include prepareSuspendedPaymentExecution.md.ejs %> <% include prepareSuspendedPaymentExecution.md.ejs %>
<% include sign.md.ejs %> <% include sign.md.ejs %>
<% include combine.md.ejs %>
<% include submit.md.ejs %> <% include submit.md.ejs %>
<% include generateAddress.md.ejs %> <% include generateAddress.md.ejs %>
<% include computeLedgerHash.md.ejs %> <% include computeLedgerHash.md.ejs %>

View File

@@ -1,6 +1,6 @@
## sign ## 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). Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).

View File

@@ -30,7 +30,7 @@ Executing a transaction with `RippleAPI` requires the following four steps:
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation) * [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation) * [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution) * [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. 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. 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.

110
npm-shrinkwrap.json generated
View File

@@ -4,17 +4,17 @@
"dependencies": { "dependencies": {
"ajv": { "ajv": {
"version": "1.4.10", "version": "1.4.10",
"from": "ajv@>=1.4.8 <2.0.0", "from": "https://registry.npmjs.org/ajv/-/ajv-1.4.10.tgz",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-1.4.10.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-1.4.10.tgz",
"dependencies": { "dependencies": {
"json-stable-stringify": { "json-stable-stringify": {
"version": "1.0.0", "version": "1.0.0",
"from": "json-stable-stringify@>=1.0.0 <2.0.0", "from": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz",
"dependencies": { "dependencies": {
"jsonify": { "jsonify": {
"version": "0.0.0", "version": "0.0.0",
"from": "jsonify@>=0.0.0 <0.1.0", "from": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
} }
} }
@@ -23,155 +23,155 @@
}, },
"ajv-i18n": { "ajv-i18n": {
"version": "0.1.1", "version": "0.1.1",
"from": "ajv-i18n@>=0.1.0 <0.2.0", "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" "resolved": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-0.1.1.tgz"
}, },
"babel-polyfill": { "babel-polyfill": {
"version": "6.3.14", "version": "6.3.14",
"from": "babel-polyfill@>=6.2.0 <7.0.0", "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", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.3.14.tgz",
"dependencies": { "dependencies": {
"core-js": { "core-js": {
"version": "1.2.6", "version": "1.2.6",
"from": "core-js@>=1.0.1 <2.0.0", "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" "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz"
}, },
"babel-regenerator-runtime": { "babel-regenerator-runtime": {
"version": "6.3.13", "version": "6.3.13",
"from": "babel-regenerator-runtime@>=6.3.13 <7.0.0", "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" "resolved": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.3.13.tgz"
} }
} }
}, },
"babel-runtime": { "babel-runtime": {
"version": "5.8.34", "version": "5.8.34",
"from": "babel-runtime@>=5.5.4 <6.0.0", "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", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.34.tgz",
"dependencies": { "dependencies": {
"core-js": { "core-js": {
"version": "1.2.6", "version": "1.2.6",
"from": "core-js@>=1.0.0 <2.0.0", "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" "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz"
} }
} }
}, },
"bignumber.js": { "bignumber.js": {
"version": "2.1.2", "version": "2.1.2",
"from": "bignumber.js@>=2.0.3 <3.0.0", "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" "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.1.2.tgz"
}, },
"https-proxy-agent": { "https-proxy-agent": {
"version": "1.0.0", "version": "1.0.0",
"from": "https-proxy-agent@>=1.0.0 <2.0.0", "from": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
"dependencies": { "dependencies": {
"agent-base": { "agent-base": {
"version": "2.0.1", "version": "2.0.1",
"from": "agent-base@>=2.0.0 <3.0.0", "from": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz",
"dependencies": { "dependencies": {
"semver": { "semver": {
"version": "5.0.3", "version": "5.0.3",
"from": "semver@>=5.0.1 <5.1.0", "from": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz" "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
} }
} }
}, },
"debug": { "debug": {
"version": "2.2.0", "version": "2.2.0",
"from": "debug@>=2.0.0 <3.0.0", "from": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"dependencies": { "dependencies": {
"ms": { "ms": {
"version": "0.7.1", "version": "0.7.1",
"from": "ms@0.7.1", "from": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
} }
} }
}, },
"extend": { "extend": {
"version": "3.0.0", "version": "3.0.0",
"from": "extend@>=3.0.0 <4.0.0", "from": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
} }
} }
}, },
"jayson": { "jayson": {
"version": "1.2.2", "version": "1.2.2",
"from": "jayson@>=1.2.2 <2.0.0", "from": "https://registry.npmjs.org/jayson/-/jayson-1.2.2.tgz",
"resolved": "https://registry.npmjs.org/jayson/-/jayson-1.2.2.tgz", "resolved": "https://registry.npmjs.org/jayson/-/jayson-1.2.2.tgz",
"dependencies": { "dependencies": {
"JSONStream": { "JSONStream": {
"version": "1.0.3", "version": "1.0.3",
"from": "JSONStream@1.0.3", "from": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.3.tgz",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.3.tgz", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.3.tgz",
"dependencies": { "dependencies": {
"jsonparse": { "jsonparse": {
"version": "1.0.0", "version": "1.0.0",
"from": "jsonparse@>=1.0.0 <1.1.0", "from": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz" "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz"
}, },
"through": { "through": {
"version": "2.3.8", "version": "2.3.8",
"from": "through@>=2.2.7 <3.0.0", "from": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
} }
} }
}, },
"commander": { "commander": {
"version": "1.3.2", "version": "1.3.2",
"from": "commander@1.3.2", "from": "https://registry.npmjs.org/commander/-/commander-1.3.2.tgz",
"resolved": "https://registry.npmjs.org/commander/-/commander-1.3.2.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-1.3.2.tgz",
"dependencies": { "dependencies": {
"keypress": { "keypress": {
"version": "0.1.0", "version": "0.1.0",
"from": "keypress@>=0.1.0 <0.2.0", "from": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz",
"resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz" "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz"
} }
} }
}, },
"eyes": { "eyes": {
"version": "0.1.8", "version": "0.1.8",
"from": "eyes@0.1.8", "from": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz" "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz"
}, },
"lodash": { "lodash": {
"version": "3.6.0", "version": "3.6.0",
"from": "lodash@3.6.0", "from": "https://registry.npmjs.org/lodash/-/lodash-3.6.0.tgz",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.6.0.tgz" "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.6.0.tgz"
} }
} }
}, },
"lodash": { "lodash": {
"version": "3.10.1", "version": "3.10.1",
"from": "lodash@>=3.1.0 <4.0.0", "from": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
}, },
"ripple-address-codec": { "ripple-address-codec": {
"version": "2.0.1", "version": "2.0.1",
"from": "ripple-address-codec@>=2.0.1 <3.0.0", "from": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz", "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz",
"dependencies": { "dependencies": {
"hash.js": { "hash.js": {
"version": "1.0.3", "version": "1.0.3",
"from": "hash.js@>=1.0.3 <2.0.0", "from": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"dependencies": { "dependencies": {
"inherits": { "inherits": {
"version": "2.0.1", "version": "2.0.1",
"from": "inherits@>=2.0.1 <3.0.0", "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
} }
} }
}, },
"x-address-codec": { "x-address-codec": {
"version": "0.7.2", "version": "0.7.2",
"from": "x-address-codec@>=0.7.0 <0.8.0", "from": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.2.tgz",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.2.tgz", "resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.2.tgz",
"dependencies": { "dependencies": {
"base-x": { "base-x": {
"version": "1.0.1", "version": "1.0.1",
"from": "base-x@>=1.0.1 <2.0.0", "from": "https://registry.npmjs.org/base-x/-/base-x-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-1.0.1.tgz" "resolved": "https://registry.npmjs.org/base-x/-/base-x-1.0.1.tgz"
} }
} }
@@ -180,76 +180,76 @@
}, },
"ripple-binary-codec": { "ripple-binary-codec": {
"version": "0.1.1", "version": "0.1.1",
"from": "ripple-binary-codec@>=0.1.1 <0.2.0", "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", "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.1.tgz",
"dependencies": { "dependencies": {
"bn.js": { "bn.js": {
"version": "3.3.0", "version": "3.3.0",
"from": "bn.js@>=3.2.0 <4.0.0", "from": "https://registry.npmjs.org/bn.js/-/bn.js-3.3.0.tgz",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-3.3.0.tgz" "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-3.3.0.tgz"
}, },
"create-hash": { "create-hash": {
"version": "1.1.2", "version": "1.1.2",
"from": "create-hash@>=1.1.2 <2.0.0", "from": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz",
"dependencies": { "dependencies": {
"cipher-base": { "cipher-base": {
"version": "1.0.2", "version": "1.0.2",
"from": "cipher-base@>=1.0.1 <2.0.0", "from": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.2.tgz" "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.2.tgz"
}, },
"ripemd160": { "ripemd160": {
"version": "1.0.1", "version": "1.0.1",
"from": "ripemd160@>=1.0.0 <2.0.0", "from": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz" "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz"
}, },
"sha.js": { "sha.js": {
"version": "2.4.4", "version": "2.4.4",
"from": "sha.js@>=2.3.6 <3.0.0", "from": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.4.tgz",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.4.tgz" "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.4.tgz"
} }
} }
}, },
"decimal.js": { "decimal.js": {
"version": "4.0.3", "version": "4.0.3",
"from": "decimal.js@>=4.0.2 <5.0.0", "from": "https://registry.npmjs.org/decimal.js/-/decimal.js-4.0.3.tgz",
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-4.0.3.tgz" "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-4.0.3.tgz"
}, },
"inherits": { "inherits": {
"version": "2.0.1", "version": "2.0.1",
"from": "inherits@>=2.0.0 <3.0.0", "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
} }
} }
}, },
"ripple-hashes": { "ripple-hashes": {
"version": "0.1.0", "version": "0.1.0",
"from": "ripple-hashes@>=0.1.0 <0.2.0", "from": "https://registry.npmjs.org/ripple-hashes/-/ripple-hashes-0.1.0.tgz",
"resolved": "https://registry.npmjs.org/ripple-hashes/-/ripple-hashes-0.1.0.tgz", "resolved": "https://registry.npmjs.org/ripple-hashes/-/ripple-hashes-0.1.0.tgz",
"dependencies": { "dependencies": {
"create-hash": { "create-hash": {
"version": "1.1.2", "version": "1.1.2",
"from": "create-hash@>=1.1.2 <2.0.0", "from": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz",
"dependencies": { "dependencies": {
"cipher-base": { "cipher-base": {
"version": "1.0.2", "version": "1.0.2",
"from": "cipher-base@>=1.0.1 <2.0.0", "from": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.2.tgz" "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.2.tgz"
}, },
"inherits": { "inherits": {
"version": "2.0.1", "version": "2.0.1",
"from": "inherits@>=2.0.1 <3.0.0", "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}, },
"ripemd160": { "ripemd160": {
"version": "1.0.1", "version": "1.0.1",
"from": "ripemd160@>=1.0.0 <2.0.0", "from": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz" "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz"
}, },
"sha.js": { "sha.js": {
"version": "2.4.4", "version": "2.4.4",
"from": "sha.js@>=2.3.6 <3.0.0", "from": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.4.tgz",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.4.tgz" "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.4.tgz"
} }
} }
@@ -258,39 +258,39 @@
}, },
"ripple-keypairs": { "ripple-keypairs": {
"version": "0.10.0", "version": "0.10.0",
"from": "ripple-keypairs@>=0.10.0 <0.11.0", "from": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-0.10.0.tgz",
"resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-0.10.0.tgz", "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-0.10.0.tgz",
"dependencies": { "dependencies": {
"bn.js": { "bn.js": {
"version": "3.3.0", "version": "3.3.0",
"from": "bn.js@>=3.1.1 <4.0.0", "from": "https://registry.npmjs.org/bn.js/-/bn.js-3.3.0.tgz",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-3.3.0.tgz" "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-3.3.0.tgz"
}, },
"brorand": { "brorand": {
"version": "1.0.5", "version": "1.0.5",
"from": "brorand@>=1.0.5 <2.0.0", "from": "https://registry.npmjs.org/brorand/-/brorand-1.0.5.tgz",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.0.5.tgz" "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.0.5.tgz"
}, },
"elliptic": { "elliptic": {
"version": "5.2.1", "version": "5.2.1",
"from": "elliptic@>=5.1.0 <6.0.0", "from": "https://registry.npmjs.org/elliptic/-/elliptic-5.2.1.tgz",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-5.2.1.tgz", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-5.2.1.tgz",
"dependencies": { "dependencies": {
"inherits": { "inherits": {
"version": "2.0.1", "version": "2.0.1",
"from": "inherits@>=2.0.1 <2.1.0", "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
} }
} }
}, },
"hash.js": { "hash.js": {
"version": "1.0.3", "version": "1.0.3",
"from": "hash.js@>=1.0.3 <2.0.0", "from": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"dependencies": { "dependencies": {
"inherits": { "inherits": {
"version": "2.0.1", "version": "2.0.1",
"from": "inherits@>=2.0.1 <3.0.0", "from": "inherits@>=2.0.1 <2.1.0",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
} }
} }
@@ -299,13 +299,13 @@
}, },
"ripple-lib-transactionparser": { "ripple-lib-transactionparser": {
"version": "0.6.0", "version": "0.6.0",
"from": "ripple-lib-transactionparser@>=0.6.0 <0.7.0", "from": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.6.0.tgz",
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.6.0.tgz" "resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.6.0.tgz"
}, },
"ws": { "ws": {
"version": "0.7.2", "version": "1.0.1",
"from": "ws@>=0.7.1 <0.8.0", "from": "ws@1.0.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-0.7.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz",
"dependencies": { "dependencies": {
"options": { "options": {
"version": "0.0.6", "version": "0.0.6",

View File

@@ -27,7 +27,7 @@
"ripple-hashes": "^0.1.0", "ripple-hashes": "^0.1.0",
"ripple-keypairs": "^0.10.0", "ripple-keypairs": "^0.10.0",
"ripple-lib-transactionparser": "^0.6.0", "ripple-lib-transactionparser": "^0.6.0",
"ws": "^0.7.1" "ws": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
"assert-diff": "^1.0.1", "assert-diff": "^1.0.1",

18
scripts/checkeol.sh Executable file
View 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

View File

@@ -3,6 +3,10 @@
NODE_INDEX="$1" NODE_INDEX="$1"
TOTAL_NODES="$2" TOTAL_NODES="$2"
function checkEOL {
./scripts/checkeol.sh
}
typecheck() { typecheck() {
npm install -g flow-bin npm install -g flow-bin
flow --version flow --version
@@ -47,6 +51,7 @@ doctest() {
} }
oneNode() { oneNode() {
checkEOL
doctest doctest
lint lint
typecheck typecheck
@@ -57,7 +62,7 @@ oneNode() {
twoNodes() { twoNodes() {
case "$NODE_INDEX" in case "$NODE_INDEX" in
0) doctest; lint; integrationtest;; 0) doctest; lint; integrationtest;;
1) typecheck; unittest;; 1) checkEOL; typecheck; unittest;;
*) echo "ERROR: invalid usage"; exit 2;; *) echo "ERROR: invalid usage"; exit 2;;
esac esac
} }
@@ -65,7 +70,7 @@ twoNodes() {
threeNodes() { threeNodes() {
case "$NODE_INDEX" in case "$NODE_INDEX" in
0) doctest; lint; integrationtest;; 0) doctest; lint; integrationtest;;
1) typecheck;; 1) checkEOL; typecheck;;
2) unittest;; 2) unittest;;
*) echo "ERROR: invalid usage"; exit 2;; *) echo "ERROR: invalid usage"; exit 2;;
esac esac

View File

@@ -16,28 +16,3 @@ echo ""
echo "publish to npm" echo "publish to npm"
npm publish npm publish
exit_on_error 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 ../..

View File

@@ -16,28 +16,3 @@ echo ""
echo "publish rc to npm" echo "publish rc to npm"
npm publish --tag beta npm publish --tag beta
exit_on_error 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 ../..

View File

@@ -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 ..

View File

@@ -44,6 +44,7 @@ const prepareSuspendedPaymentCancellation =
require('./transaction/suspended-payment-cancellation'); require('./transaction/suspended-payment-cancellation');
const prepareSettings = require('./transaction/settings'); const prepareSettings = require('./transaction/settings');
const sign = require('./transaction/sign'); const sign = require('./transaction/sign');
const combine = require('./transaction/combine');
const submit = require('./transaction/submit'); const submit = require('./transaction/submit');
const errors = require('./common').errors; const errors = require('./common').errors;
const generateAddress = const generateAddress =
@@ -125,6 +126,7 @@ _.assign(RippleAPI.prototype, {
prepareSuspendedPaymentCancellation, prepareSuspendedPaymentCancellation,
prepareSettings, prepareSettings,
sign, sign,
combine,
submit, submit,
generateAddress, generateAddress,

View File

@@ -38,6 +38,17 @@ class Connection extends EventEmitter {
this._nextRequestID = 1; 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 // return value is array of arguments to Connection.emit
_parseMessage(message) { _parseMessage(message) {
const data = JSON.parse(message); const data = JSON.parse(message);
@@ -48,10 +59,7 @@ class Connection extends EventEmitter {
return [data.id.toString(), data]; return [data.id.toString(), data];
} else if (isStreamMessageType(data.type)) { } else if (isStreamMessageType(data.type)) {
if (data.type === 'ledgerClosed') { if (data.type === 'ledgerClosed') {
this._ledgerVersion = Number(data.ledger_index); this._updateLedgerVersions(data);
this._availableLedgerVersions.reset();
this._availableLedgerVersions.parseAndAddRanges(
data.validated_ledgers);
} }
return [data.type, data]; return [data.type, data];
} else if (data.type === undefined && data.error) { } else if (data.type === undefined && data.error) {
@@ -99,10 +107,8 @@ class Connection extends EventEmitter {
command: 'subscribe', command: 'subscribe',
streams: ['ledger'] streams: ['ledger']
}; };
return this.request(request).then(response => { return this.request(request).then(data => {
this._ledgerVersion = Number(response.ledger_index); this._updateLedgerVersions(data);
this._availableLedgerVersions.parseAndAddRanges(
response.validated_ledgers);
this._isReady = true; this._isReady = true;
this.emit('connected'); this.emit('connected');
}); });

View File

@@ -94,7 +94,8 @@ function loadSchemas() {
require('./schemas/input/compute-ledger-hash'), require('./schemas/input/compute-ledger-hash'),
require('./schemas/input/sign.json'), require('./schemas/input/sign.json'),
require('./schemas/input/submit.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 titles = _.map(schemas, schema => schema.title);
const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1)); const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1));

View 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"]
}

View File

@@ -11,6 +11,17 @@
"type": "string", "type": "string",
"format": "secret", "format": "secret",
"description": "The secret of the account that is initiating the transaction." "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, "additionalProperties": false,

View File

@@ -28,6 +28,11 @@
"description": "Offset from current validated legder version to highest ledger version that the transaction can be included in.", "description": "Offset from current validated legder version to highest ledger version that the transaction can be included in.",
"type": "integer", "type": "integer",
"minimum": 0 "minimum": 0
},
"signersCount": {
"description": "Number of signers that will be signing this transaction.",
"type": "integer",
"minimum": 1
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View File

@@ -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." "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"} "memos": {"$ref": "memos"}
}, },
"additionalProperties": false "additionalProperties": false

View File

@@ -1,55 +1,55 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
export type RippledAmountIOU = { export type RippledAmountIOU = {
currency: string, currency: string,
value: string, value: string,
issuer?: string issuer?: string
} }
export type RippledAmount = string | RippledAmountIOU export type RippledAmount = string | RippledAmountIOU
export type Amount = { export type Amount = {
value: string, value: string,
currency: string, currency: string,
counterparty?: string counterparty?: string
} }
// Amount where counterparty and value are optional // Amount where counterparty and value are optional
export type LaxLaxAmount = { export type LaxLaxAmount = {
currency: string, currency: string,
value?: string, value?: string,
counterparty?: string counterparty?: string
} }
// A currency-counterparty pair, or just currency if it's XRP // A currency-counterparty pair, or just currency if it's XRP
export type Issue = { export type Issue = {
currency: string, currency: string,
counterparty?: string counterparty?: string
} }
export type Adjustment = { export type Adjustment = {
address: string, address: string,
amount: Amount, amount: Amount,
tag?: number tag?: number
} }
export type MaxAdjustment = { export type MaxAdjustment = {
address: string, address: string,
maxAmount: Amount, maxAmount: Amount,
tag?: number tag?: number
} }
export type MinAdjustment = { export type MinAdjustment = {
address: string, address: string,
minAmount: Amount, minAmount: Amount,
tag?: number tag?: number
} }
export type Memo = { export type Memo = {
type?: string, type?: string,
format?: string, format?: string,
data?: string data?: string
} }

View File

@@ -47,6 +47,7 @@ module.exports = {
prepareSuspendedPaymentExecution: _.partial(schemaValidate, prepareSuspendedPaymentExecution: _.partial(schemaValidate,
'prepareSuspendedPaymentExecutionParameters'), 'prepareSuspendedPaymentExecutionParameters'),
sign: _.partial(schemaValidate, 'signParameters'), sign: _.partial(schemaValidate, 'signParameters'),
combine: _.partial(schemaValidate, 'combineParameters'),
submit: _.partial(schemaValidate, 'submitParameters'), submit: _.partial(schemaValidate, 'submitParameters'),
computeLedgerHash: _.partial(schemaValidate, 'computeLedgerHashParameters'), computeLedgerHash: _.partial(schemaValidate, 'computeLedgerHashParameters'),
generateAddress: _.partial(schemaValidate, 'generateAddressParameters'), generateAddress: _.partial(schemaValidate, 'generateAddressParameters'),

View File

@@ -1,5 +1,6 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
const _ = require('lodash');
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const AccountFields = require('./utils').constants.AccountFields; const AccountFields = require('./utils').constants.AccountFields;
@@ -22,6 +23,26 @@ function parseFields(data: Object): Object {
settings[info.name] = parseField(info, fieldValue); 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; return settings;
} }

View File

@@ -52,10 +52,10 @@ function parseFlags(tx: Object) {
function parseSettings(tx: Object) { function parseSettings(tx: Object) {
const txType = tx.TransactionType; 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({}, parseFlags(tx), parseFields(tx));
return _.assign(regularKey, parseFlags(tx), parseFields(tx));
} }
module.exports = parseSettings; module.exports = parseSettings;

View File

@@ -22,7 +22,8 @@ function parseTransactionType(type) {
SetRegularKey: 'settings', SetRegularKey: 'settings',
SuspendedPaymentCreate: 'suspendedPaymentCreation', SuspendedPaymentCreate: 'suspendedPaymentCreation',
SuspendedPaymentFinish: 'suspendedPaymentExecution', SuspendedPaymentFinish: 'suspendedPaymentExecution',
SuspendedPaymentCancel: 'suspendedPaymentCancellation' SuspendedPaymentCancel: 'suspendedPaymentCancellation',
SignerListSet: 'settings'
}; };
return mapping[type] || null; return mapping[type] || null;
} }

View File

@@ -1,135 +1,135 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
import type {Amount, Memo} from '../common/types.js'; import type {Amount, Memo} from '../common/types.js';
type Outcome = { type Outcome = {
result: string, result: string,
ledgerVersion: number, ledgerVersion: number,
indexInLedger: number, indexInLedger: number,
fee: string, fee: string,
balanceChanges: { balanceChanges: {
[key: string]: [{ [key: string]: [{
currency: string, currency: string,
counterparty?: string, counterparty?: string,
value: string value: string
}] }]
}, },
orderbookChanges: Object, orderbookChanges: Object,
timestamp?: string timestamp?: string
} }
type Adjustment = { type Adjustment = {
address: string, address: string,
amount: { amount: {
currency: string, currency: string,
counterparty?: string, counterparty?: string,
value: string value: string
}, },
tag?: number tag?: number
} }
type Trustline = { type Trustline = {
currency: string, currency: string,
counterparty: string, counterparty: string,
limit: string, limit: string,
qualityIn?: number, qualityIn?: number,
qualityOut?: number, qualityOut?: number,
ripplingDisabled?: boolean, ripplingDisabled?: boolean,
authorized?: boolean, authorized?: boolean,
frozen?: boolean frozen?: boolean
} }
type Settings = { type Settings = {
passwordSpent?: boolean, passwordSpent?: boolean,
requireDestinationTag?: boolean, requireDestinationTag?: boolean,
requireAuthorization?: boolean, requireAuthorization?: boolean,
disallowIncomingXRP?: boolean, disallowIncomingXRP?: boolean,
disableMasterKey?: boolean, disableMasterKey?: boolean,
enableTransactionIDTracking?: boolean, enableTransactionIDTracking?: boolean,
noFreeze?: boolean, noFreeze?: boolean,
globalFreeze?: boolean, globalFreeze?: boolean,
defaultRipple?: boolean, defaultRipple?: boolean,
emailHash?: string, emailHash?: string,
messageKey?: string, messageKey?: string,
domain?: string, domain?: string,
transferRate?: number, transferRate?: number,
regularKey?: string regularKey?: string
} }
type OrderCancellation = { type OrderCancellation = {
orderSequence: number orderSequence: number
} }
type Payment = { type Payment = {
source: Adjustment, source: Adjustment,
destination: Adjustment, destination: Adjustment,
paths?: string, paths?: string,
memos?: Array<Memo>, memos?: Array<Memo>,
invoiceID?: string, invoiceID?: string,
allowPartialPayment?: boolean, allowPartialPayment?: boolean,
noDirectRipple?: boolean, noDirectRipple?: boolean,
limitQuality?: boolean limitQuality?: boolean
} }
type PaymentTransaction = { type PaymentTransaction = {
type: string, type: string,
specification: Payment, specification: Payment,
outcome: Outcome, outcome: Outcome,
id: string, id: string,
address: string, address: string,
sequence: number sequence: number
} }
export type Order = { export type Order = {
direction: string, direction: string,
quantity: Amount, quantity: Amount,
totalPrice: Amount, totalPrice: Amount,
immediateOrCancel?: boolean, immediateOrCancel?: boolean,
fillOrKill?: boolean, fillOrKill?: boolean,
passive?: boolean passive?: boolean
} }
type OrderTransaction = { type OrderTransaction = {
type: string, type: string,
specification: Order, specification: Order,
outcome: Outcome, outcome: Outcome,
id: string, id: string,
address: string, address: string,
sequence: number sequence: number
} }
type OrderCancellationTransaction = { type OrderCancellationTransaction = {
type: string, type: string,
specification: OrderCancellation, specification: OrderCancellation,
outcome: Outcome, outcome: Outcome,
id: string, id: string,
address: string, address: string,
sequence: number sequence: number
} }
type TrustlineTransaction = { type TrustlineTransaction = {
type: string, type: string,
specification: Trustline, specification: Trustline,
outcome: Outcome, outcome: Outcome,
id: string, id: string,
address: string, address: string,
sequence: number sequence: number
} }
type SettingsTransaction = { type SettingsTransaction = {
type: string, type: string,
specification: Settings, specification: Settings,
outcome: Outcome, outcome: Outcome,
id: string, id: string,
address: string, address: string,
sequence: number sequence: number
} }
export type TransactionOptions = { export type TransactionOptions = {
minLedgerVersion?: number, minLedgerVersion?: number,
maxLedgerVersion?: number maxLedgerVersion?: number
} }
export type TransactionType = PaymentTransaction | OrderTransaction | export type TransactionType = PaymentTransaction | OrderTransaction |
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction

View File

@@ -1,33 +1,33 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
export type TrustLineSpecification = { export type TrustLineSpecification = {
currency: string, currency: string,
counterparty: string, counterparty: string,
limit: string, limit: string,
qualityIn?: number, qualityIn?: number,
qualityOut?: number, qualityOut?: number,
ripplingDisabled?: boolean, ripplingDisabled?: boolean,
authorized?: boolean, authorized?: boolean,
frozen?: boolean frozen?: boolean
} }
export type Trustline = { export type Trustline = {
specification: TrustLineSpecification, specification: TrustLineSpecification,
counterparty: { counterparty: {
limit: string, limit: string,
ripplingDisabled?: boolean, ripplingDisabled?: boolean,
frozen?: boolean, frozen?: boolean,
authorized?: boolean authorized?: boolean
}, },
state: { state: {
balance: string balance: string
} }
} }
export type TrustlinesOptions = { export type TrustlinesOptions = {
counterparty?: string, counterparty?: string,
currency?: string, currency?: string,
limit?: number, limit?: number,
ledgerVersion?: number ledgerVersion?: number
} }

View File

@@ -1,50 +1,50 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
import type {Amount} from '../common/types.js'; import type {Amount} from '../common/types.js';
export type OrdersOptions = { export type OrdersOptions = {
limit?: number, limit?: number,
ledgerVersion?: number ledgerVersion?: number
} }
export type OrderSpecification = { export type OrderSpecification = {
direction: string, direction: string,
quantity: Amount, quantity: Amount,
totalPrice: Amount, totalPrice: Amount,
immediateOrCancel?: boolean, immediateOrCancel?: boolean,
fillOrKill?: boolean, fillOrKill?: boolean,
// If enabled, the offer will not consume offers that exactly match it, and // 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 // instead becomes an Offer node in the ledger. It will still consume offers
// that cross it. // that cross it.
passive?: boolean passive?: boolean
} }
export type Order = { export type Order = {
specification: OrderSpecification, specification: OrderSpecification,
properties: { properties: {
maker: string, maker: string,
sequence: number, sequence: number,
makerExchangeRate: string makerExchangeRate: string
} }
} }
export type GetLedger = { export type GetLedger = {
accepted: boolean, accepted: boolean,
closed: boolean, closed: boolean,
stateHash: string, stateHash: string,
closeTime: number, closeTime: number,
closeTimeResolution: number, closeTimeResolution: number,
closeFlags: number, closeFlags: number,
ledgerHash: string, ledgerHash: string,
ledgerVersion: number, ledgerVersion: number,
parentLedgerHash: string, parentLedgerHash: string,
parentCloseTime: number, parentCloseTime: number,
totalDrops: string, totalDrops: string,
transactionHash: string, transactionHash: string,
transactions?: Array<Object>, transactions?: Array<Object>,
rawTransactions?: string, rawTransactions?: string,
transactionHashes?: Array<string>, transactionHashes?: Array<string>,
rawState?: string, rawState?: string,
stateHashes?: Array<string> stateHashes?: Array<string>
} }

View 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;

View File

@@ -1,53 +1,53 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
type SettingPasswordSpent = { type SettingPasswordSpent = {
passwordSpent?: boolean, passwordSpent?: boolean,
} }
type SettingRequireDestinationTag = { type SettingRequireDestinationTag = {
requireDestinationTag?: boolean, requireDestinationTag?: boolean,
} }
type SettingRequireAuthorization = { type SettingRequireAuthorization = {
requireAuthorization?: boolean, requireAuthorization?: boolean,
} }
type SettingDisallowIncomingXRP = { type SettingDisallowIncomingXRP = {
disallowIncomingXRP?: boolean, disallowIncomingXRP?: boolean,
} }
type SettingDisableMasterKey = { type SettingDisableMasterKey = {
disableMasterKey?: boolean, disableMasterKey?: boolean,
} }
type SettingEnableTransactionIDTracking = { type SettingEnableTransactionIDTracking = {
enableTransactionIDTracking?: boolean, enableTransactionIDTracking?: boolean,
} }
type SettingNoFreeze = { type SettingNoFreeze = {
noFreeze?: boolean, noFreeze?: boolean,
} }
type SettingGlobalFreeze = { type SettingGlobalFreeze = {
globalFreeze?: boolean, globalFreeze?: boolean,
} }
type SettingDefaultRipple = { type SettingDefaultRipple = {
defaultRipple?: boolean, defaultRipple?: boolean,
} }
type SettingEmailHash = { type SettingEmailHash = {
emailHash?: ?string, emailHash?: ?string,
} }
type SettingMessageKey = { type SettingMessageKey = {
messageKey?: string, messageKey?: string,
} }
type SettingDomain = { type SettingDomain = {
domain?: string, domain?: string,
} }
type SettingTransferRate = { type SettingTransferRate = {
transferRate?: ?number, transferRate?: ?number,
} }
type SettingRegularKey = { type SettingRegularKey = {
regularKey?: string regularKey?: string
} }
export type Settings = SettingRegularKey | export type Settings = SettingRegularKey |
SettingTransferRate | SettingDomain | SettingMessageKey | SettingTransferRate | SettingDomain | SettingMessageKey |
SettingEmailHash | SettingDefaultRipple | SettingEmailHash | SettingDefaultRipple |
SettingGlobalFreeze | SettingNoFreeze | SettingEnableTransactionIDTracking | SettingGlobalFreeze | SettingNoFreeze | SettingEnableTransactionIDTracking |
SettingDisableMasterKey | SettingDisallowIncomingXRP | SettingDisableMasterKey | SettingDisallowIncomingXRP |
SettingRequireAuthorization | SettingRequireDestinationTag | SettingRequireAuthorization | SettingRequireDestinationTag |
SettingPasswordSpent SettingPasswordSpent

View File

@@ -70,7 +70,17 @@ function convertTransferRate(transferRate: number | string): number | string {
return (new BigNumber(transferRate)).shift(9).toNumber(); 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 { ): Object {
if (settings.regularKey !== undefined) { if (settings.regularKey !== undefined) {
const removeRegularKey = { const removeRegularKey = {
@@ -83,15 +93,20 @@ function createSettingsTransaction(account: string, settings: Settings
return _.assign({}, removeRegularKey, {RegularKey: settings.regularKey}); 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 = { const txJSON: Object = {
TransactionType: 'AccountSet', TransactionType: 'AccountSet',
Account: account Account: account
}; };
if (settings.memos !== undefined) {
txJSON.Memos = _.map(settings.memos, utils.convertMemo);
}
setTransactionFlags(txJSON, _.omit(settings, 'memos')); setTransactionFlags(txJSON, _.omit(settings, 'memos'));
setTransactionFields(txJSON, settings); setTransactionFields(txJSON, settings);
@@ -101,6 +116,15 @@ function createSettingsTransaction(account: string, settings: Settings
return txJSON; 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, function prepareSettings(address: string, settings: Settings,
instructions: Instructions = {} instructions: Instructions = {}
): Promise<Prepare> { ): Promise<Prepare> {

View File

@@ -6,23 +6,38 @@ const binary = require('ripple-binary-codec');
const {computeBinaryTransactionHash} = require('ripple-hashes'); const {computeBinaryTransactionHash} = require('ripple-hashes');
const validate = utils.common.validate; const validate = utils.common.validate;
function computeSignature(txJSON, privateKey) { function computeSignature(tx: Object, privateKey: string, signAs: ?string) {
const signingData = binary.encodeForSigning(txJSON); const signingData = signAs ?
binary.encodeForMultisigning(tx, signAs) : binary.encodeForSigning(tx);
return keypairs.sign(signingData, privateKey); return keypairs.sign(signingData, privateKey);
} }
function sign(txJSON: string, secret: string function sign(txJSON: string, secret: string, options: Object = {}
): {signedTransaction: string; id: string} { ): {signedTransaction: string; id: string} {
validate.sign({txJSON, secret}); validate.sign({txJSON, secret});
// we can't validate that the secret matches the account because // we can't validate that the secret matches the account because
// the secret could correspond to the regular key // the secret could correspond to the regular key
const tx = JSON.parse(txJSON); const tx = JSON.parse(txJSON);
const keypair = keypairs.deriveKeypair(secret); if (tx.TxnSignature || tx.Signers) {
if (tx.SigningPubKey === undefined) { throw new utils.common.errors.ValidationError(
tx.SigningPubKey = keypair.publicKey; '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); const serialized = binary.encode(tx);
return { return {
signedTransaction: serialized, signedTransaction: serialized,

View File

@@ -3,15 +3,7 @@
const _ = require('lodash'); const _ = require('lodash');
const utils = require('./utils'); const utils = require('./utils');
const {validate} = utils.common; const {validate} = utils.common;
import type {Submit} from './types.js';
type Submit = {
success: boolean,
engineResult: string,
engineResultCode: number,
engineResultMessage?: string,
txBlob?: string,
txJson?: Object
}
function isImmediateRejection(engineResult: string): boolean { function isImmediateRejection(engineResult: string): boolean {
// note: "tel" errors mean the local server refused to process the // note: "tel" errors mean the local server refused to process the
@@ -23,7 +15,7 @@ function isImmediateRejection(engineResult: string): boolean {
return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej'); return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej');
} }
function formatResponse(response) { function formatSubmitResponse(response) {
const data = { const data = {
resultCode: response.engine_result, resultCode: response.engine_result,
resultMessage: response.engine_result_message resultMessage: response.engine_result_message
@@ -36,11 +28,12 @@ function formatResponse(response) {
function submit(signedTransaction: string): Promise<Submit> { function submit(signedTransaction: string): Promise<Submit> {
validate.submit({signedTransaction}); validate.submit({signedTransaction});
const request = { const request = {
command: 'submit', command: 'submit',
tx_blob: signedTransaction tx_blob: signedTransaction
}; };
return this.connection.request(request).then(formatResponse); return this.connection.request(request).then(formatSubmitResponse);
} }
module.exports = submit; module.exports = submit;

View File

@@ -1,19 +1,29 @@
/* @flow */ /* @flow */
'use strict'; 'use strict';
export type Instructions = { export type Instructions = {
sequence?: number, sequence?: number,
fee?: string, fee?: string,
maxFee?: string, maxFee?: string,
maxLedgerVersion?: number, maxLedgerVersion?: number,
maxLedgerVersionOffset?: number maxLedgerVersionOffset?: number,
} signersCount?: number
}
export type Prepare = {
txJSON: string, export type Prepare = {
instructions: { txJSON: string,
fee: string, instructions: {
sequence: number, fee: string,
maxLedgerVersion?: number sequence: number,
} maxLedgerVersion?: number
} }
}
export type Submit = {
success: boolean,
engineResult: string,
engineResultCode: number,
engineResultMessage?: string,
txBlob?: string,
txJson?: Object
}

View File

@@ -27,6 +27,10 @@ function setCanonicalFlag(txJSON) {
txJSON.Flags = txJSON.Flags >>> 0; txJSON.Flags = txJSON.Flags >>> 0;
} }
function scaleValue(value, multiplier) {
return (new BigNumber(value)).times(multiplier).toString();
}
function prepareTransaction(txJSON: Object, api: Object, function prepareTransaction(txJSON: Object, api: Object,
instructions: Instructions instructions: Instructions
): Promise<Prepare> { ): Promise<Prepare> {
@@ -51,8 +55,10 @@ function prepareTransaction(txJSON: Object, api: Object,
} }
function prepareFee(): Promise<Object> { function prepareFee(): Promise<Object> {
const multiplier = instructions.signersCount === undefined ? 1 :
instructions.signersCount + 1;
if (instructions.fee !== undefined) { if (instructions.fee !== undefined) {
txJSON.Fee = common.xrpToDrops(instructions.fee); txJSON.Fee = scaleValue(common.xrpToDrops(instructions.fee), multiplier);
return Promise.resolve(txJSON); return Promise.resolve(txJSON);
} }
const cushion = api._feeCushion; const cushion = api._feeCushion;
@@ -60,9 +66,10 @@ function prepareTransaction(txJSON: Object, api: Object,
const feeDrops = common.xrpToDrops(fee); const feeDrops = common.xrpToDrops(fee);
if (instructions.maxFee !== undefined) { if (instructions.maxFee !== undefined) {
const maxFeeDrops = common.xrpToDrops(instructions.maxFee); const maxFeeDrops = common.xrpToDrops(instructions.maxFee);
txJSON.Fee = BigNumber.min(feeDrops, maxFeeDrops).toString(); const normalFee = BigNumber.min(feeDrops, maxFeeDrops).toString();
txJSON.Fee = scaleValue(normalFee, multiplier);
} else { } else {
txJSON.Fee = feeDrops; txJSON.Fee = scaleValue(feeDrops, multiplier);
} }
return txJSON; return txJSON;
}); });

View File

@@ -183,20 +183,20 @@ describe('RippleAPI', function() {
it('prepareSettings', function() { it('prepareSettings', function() {
return this.api.prepareSettings( return this.api.prepareSettings(
address, requests.prepareSettings, instructions).then( address, requests.prepareSettings.domain, instructions).then(
_.partial(checkResult, responses.prepareSettings.flags, 'prepare')); _.partial(checkResult, responses.prepareSettings.flags, 'prepare'));
}); });
it('prepareSettings - no maxLedgerVersion', function() { it('prepareSettings - no maxLedgerVersion', function() {
return this.api.prepareSettings( return this.api.prepareSettings(
address, requests.prepareSettings, {maxLedgerVersion: null}).then( address, requests.prepareSettings.domain, {maxLedgerVersion: null}).then(
_.partial(checkResult, responses.prepareSettings.noMaxLedgerVersion, _.partial(checkResult, responses.prepareSettings.noMaxLedgerVersion,
'prepare')); 'prepare'));
}); });
it('prepareSettings - no instructions', function() { it('prepareSettings - no instructions', function() {
return this.api.prepareSettings( return this.api.prepareSettings(
address, requests.prepareSettings).then( address, requests.prepareSettings.domain).then(
_.partial( _.partial(
checkResult, checkResult,
responses.prepareSettings.noInstructions, responses.prepareSettings.noInstructions,
@@ -244,6 +244,23 @@ describe('RippleAPI', function() {
'prepare')); '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() { it('prepareSuspendedPaymentCreation', function() {
const localInstructions = _.defaults({ const localInstructions = _.defaults({
maxFee: '0.000012' maxFee: '0.000012'
@@ -312,6 +329,14 @@ describe('RippleAPI', function() {
schemaValidator.schemaValidate('sign', result); 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() { it('submit', function() {
return this.api.submit(responses.sign.normal.signedTransaction).then( return this.api.submit(responses.sign.normal.signedTransaction).then(
_.partial(checkResult, responses.submit, 'submit')); _.partial(checkResult, responses.submit, 'submit'));
@@ -326,6 +351,11 @@ describe('RippleAPI', function() {
}); });
}); });
it('combine', function() {
const combined = this.api.combine(requests.combine.setDomain);
checkResult(responses.combine.single, 'sign', combined);
});
describe('RippleAPI', function() { describe('RippleAPI', function() {
it('getBalances', function() { it('getBalances', function() {
@@ -1255,7 +1285,7 @@ describe('RippleAPI - offline', function() {
it('prepareSettings and sign', function() { it('prepareSettings and sign', function() {
const api = new RippleAPI(); const api = new RippleAPI();
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'; const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
const settings = requests.prepareSettings; const settings = requests.prepareSettings.domain;
const instructions = { const instructions = {
sequence: 23, sequence: 23,
maxLedgerVersion: 8820051, maxLedgerVersion: 8820051,

View File

@@ -42,7 +42,6 @@ describe('RippleAPIBroadcast', function() {
this.mocks.forEach(mock => mock.socket.send(JSON.stringify(ledgerNext))); this.mocks.forEach(mock => mock.socket.send(JSON.stringify(ledgerNext)));
setTimeout(() => { setTimeout(() => {
console.log('-- ledgerVersion', this.api.ledgerVersion);
assert.strictEqual(gotLedger, 1); assert.strictEqual(gotLedger, 1);
done(); done();
}, 50); }, 50);

View File

@@ -7,6 +7,7 @@ const assert = require('assert-diff');
const setupAPI = require('./setup-api'); const setupAPI = require('./setup-api');
const RippleAPI = require('ripple-api').RippleAPI; const RippleAPI = require('ripple-api').RippleAPI;
const utils = RippleAPI._PRIVATE.ledgerUtils; const utils = RippleAPI._PRIVATE.ledgerUtils;
const ledgerClose = require('./fixtures/rippled/ledger-close.json');
function unused() { function unused() {
@@ -261,4 +262,13 @@ describe('Connection', function() {
this.api.connection._onMessage(JSON.stringify({type: 'unknown'})); 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));
});
}); });

2
test/fixtures/requests/combine.json vendored Normal file
View File

@@ -0,0 +1,2 @@
[ "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
"12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1F1" ]

View File

@@ -1,9 +1,9 @@
{ {
"base": { "base": {
"currency": "USD", "currency": "USD",
"counterparty": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw" "counterparty": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw"
}, },
"counter": { "counter": {
"currency": "XRP" "currency": "XRP"
} }
} }

View File

@@ -1,13 +1,13 @@
{ {
"source": { "source": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59" "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
}, },
"destination": { "destination": {
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo", "address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"amount": { "amount": {
"currency": "USD", "currency": "USD",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "100" "value": "100"
} }
} }
} }

View File

@@ -1,15 +1,15 @@
{ {
"source": { "source": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"amount": { "amount": {
"currency": "USD", "currency": "USD",
"value": "5" "value": "5"
} }
}, },
"destination": { "destination": {
"address": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", "address": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"amount": { "amount": {
"currency": "USD" "currency": "USD"
} }
} }
} }

View File

@@ -1,20 +1,20 @@
{ {
"source": { "source": {
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo", "address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"currencies": [ "currencies": [
{ {
"currency": "LTC" "currency": "LTC"
}, },
{ {
"currency": "USD" "currency": "USD"
} }
] ]
}, },
"destination": { "destination": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"amount": { "amount": {
"currency": "USD", "currency": "USD",
"value": "0.000001" "value": "0.000001"
} }
} }
} }

View File

@@ -1,12 +1,12 @@
{ {
"source": { "source": {
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J" "address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J"
}, },
"destination": { "destination": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"amount": { "amount": {
"value": "0.000002", "value": "0.000002",
"currency": "XRP" "currency": "XRP"
} }
} }
} }

View File

@@ -20,7 +20,10 @@ module.exports = {
allOptions: require('./prepare-payment-all-options'), allOptions: require('./prepare-payment-all-options'),
noCounterparty: require('./prepare-payment-no-counterparty') noCounterparty: require('./prepare-payment-no-counterparty')
}, },
prepareSettings: require('./prepare-settings'), prepareSettings: {
domain: require('./prepare-settings'),
signers: require('./prepare-settings-signers')
},
prepareSuspendedPaymentCreation: { prepareSuspendedPaymentCreation: {
normal: require('./prepare-suspended-payment-creation'), normal: require('./prepare-suspended-payment-creation'),
full: require('./prepare-suspended-payment-creation-full') full: require('./prepare-suspended-payment-creation-full')
@@ -40,7 +43,8 @@ module.exports = {
}, },
sign: { sign: {
normal: require('./sign'), normal: require('./sign'),
suspended: require('./sign-suspended.json') suspended: require('./sign-suspended.json'),
signAs: require('./sign-as')
}, },
getPaths: { getPaths: {
normal: require('./getpaths/normal'), normal: require('./getpaths/normal'),
@@ -61,5 +65,8 @@ module.exports = {
computeLedgerHash: { computeLedgerHash: {
header: require('./compute-ledger-hash'), header: require('./compute-ledger-hash'),
transactions: require('./compute-ledger-hash-transactions') transactions: require('./compute-ledger-hash-transactions')
},
combine: {
setDomain: require('./combine.json')
} }
}; };

View File

@@ -1,17 +1,17 @@
{ {
"source": { "source": {
"address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM", "address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"amount": { "amount": {
"value": "0.01", "value": "0.01",
"currency": "USD", "currency": "USD",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM" "counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
} }
}, },
"destination": { "destination": {
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo", "address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"minAmount": { "minAmount": {
"value": "0.01", "value": "0.01",
"currency": "XRP" "currency": "XRP"
} }
} }
} }

View File

@@ -1,17 +1,17 @@
{ {
"source": { "source": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", "address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"amount": { "amount": {
"value": "0.01", "value": "0.01",
"currency": "XRP" "currency": "XRP"
} }
}, },
"destination": { "destination": {
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo", "address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"minAmount": { "minAmount": {
"value": "0.01", "value": "0.01",
"currency": "XRP" "currency": "XRP"
} }
}, },
"allowPartialPayment": true "allowPartialPayment": true
} }

View 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
View 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
View File

@@ -0,0 +1,4 @@
{
"signedTransaction": "12000322800000002400000004201B000000116840000000000F42407300770B6578616D706C652E636F6D811407C532442A675C881BA1235354D4AB9D023243A6F3E01073210287AAAB8FBE8C4C4A47F6F1228C6E5123A7ED844BFE88A9B22C2F7CC34279EEAA74473045022100B09DDF23144595B5A9523B20E605E138DC6549F5CA7B5984D7C32B0E3469DF6B022018845CA6C203D4B6288C87DDA439134C83E7ADF8358BD41A8A9141A9B631419F8114517D9B9609229E0CDFE2428B586738C5B2E84D45E1E0107321026C784C1987F83BACBF02CD3E484AFC84ADE5CA6B36ED4DCA06D5BA233B9D382774473045022100E484F54FF909469FA2033E22EFF3DF8EDFE62217062680BB2F3EDF2F185074FE0220350DB29001C710F0450DAF466C5D819DC6D6A3340602DE9B6CB7DA8E17C90F798114FE9337B0574213FA5BCC0A319DBB4A7AC0CCA894E1F1",
"id": "8A3BFD2214B4C8271ED62648FCE9ADE4EE82EF01827CF7D1F7ED497549A368CC"
}

View File

@@ -31,4 +31,4 @@
"ledgerVersion": 14, "ledgerVersion": 14,
"indexInLedger": 0 "indexInLedger": 0
} }
} }

View File

@@ -32,4 +32,4 @@
"ledgerVersion": 14, "ledgerVersion": 14,
"indexInLedger": 0 "indexInLedger": 0
} }
} }

View File

@@ -331,4 +331,4 @@
"balance": "0" "balance": "0"
} }
} }
] ]

View File

@@ -81,13 +81,15 @@ module.exports = {
regularKey: require('./prepare-settings-regular-key.json'), regularKey: require('./prepare-settings-regular-key.json'),
removeRegularKey: require('./prepare-settings-remove-regular-key.json'), removeRegularKey: require('./prepare-settings-remove-regular-key.json'),
flags: require('./prepare-settings.json'), flags: require('./prepare-settings.json'),
flagsMultisign: require('./prepare-settings-multisign.json'),
flagSet: require('./prepare-settings-flag-set.json'), flagSet: require('./prepare-settings-flag-set.json'),
flagClear: require('./prepare-settings-flag-clear.json'), flagClear: require('./prepare-settings-flag-clear.json'),
setTransferRate: require('./prepare-settings-set-transfer-rate.json'), setTransferRate: require('./prepare-settings-set-transfer-rate.json'),
fieldClear: require('./prepare-settings-field-clear.json'), fieldClear: require('./prepare-settings-field-clear.json'),
noInstructions: require('./prepare-settings-no-instructions.json'), noInstructions: require('./prepare-settings-no-instructions.json'),
signed: require('./prepare-settings-signed.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: { prepareSuspendedPaymentCreation: {
normal: require('./prepare-suspended-payment-creation'), normal: require('./prepare-suspended-payment-creation'),
@@ -108,7 +110,11 @@ module.exports = {
}, },
sign: { sign: {
normal: require('./sign.json'), 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'), submit: require('./submit.json'),
ledgerEvent: require('./ledger-event.json') ledgerEvent: require('./ledger-event.json')

View File

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

View File

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

View 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
}
}

View File

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

View File

@@ -1,4 +1,4 @@
{ {
"signedTransaction": "12000322800000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402202FBF6A6F74DFDA17C7341D532B66141206BC71A147C08DBDA6A950AA9A1741DC022055859A39F2486A46487F8DA261E3D80B4FDD26178A716A929F26377D1BEC7E43770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304F9EA7C04746573747D0B74657874656420646174617E0A706C61696E2F74657874E1F1", "signedTransaction": "12000322800000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402202FBF6A6F74DFDA17C7341D532B66141206BC71A147C08DBDA6A950AA9A1741DC022055859A39F2486A46487F8DA261E3D80B4FDD26178A716A929F26377D1BEC7E43770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304F9EA7C04746573747D0B74657874656420646174617E0A706C61696E2F74657874E1F1",
"id": "4755D26FAC39E3E477870D4E03CC6783DDDF967FFBE240606755D3D03702FC16" "id": "4755D26FAC39E3E477870D4E03CC6783DDDF967FFBE240606755D3D03702FC16"
} }

View 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
View File

@@ -0,0 +1,4 @@
{
"signedTransaction": "120000240000000261400000003B9ACA00684000000000000032730081142E244E6F20104E57C0C60BD823CB312BF10928C78314B5F762798A53D543A014CAF8B297CFF8F2F937E8F3E01073210330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD02074473045022100BB6FC77F26BC88587204CAA79B2230C420D7EC937B8AC3A0CF9B0BE988BAB0D002203BF86893BA3B764375FFFAD9D54A4AAEDABD07C4D72ADB9C1B20C10B4DD712898114B5F762798A53D543A014CAF8B297CFF8F2F937E8E1F1",
"id": "AB7632D7C07E591658635CED6A5DDE832B22CA066907CB131DEFAAA925B98185"
}

View File

@@ -29,4 +29,4 @@
}, },
"status": "success", "status": "success",
"type": "response" "type": "response"
} }

View File

@@ -1,12 +1,12 @@
{ {
"fee_base": 10, "fee_base": 10,
"fee_ref": 10, "fee_ref": 10,
"ledger_hash": "9141FA171F2C0CE63E609466AF728FF66C12F7ACD4B4B50B0947A7F3409D593A", "ledger_hash": "9141FA171F2C0CE63E609466AF728FF66C12F7ACD4B4B50B0947A7F3409D593A",
"ledger_index": 14804627, "ledger_index": 14804627,
"ledger_time": 490945840, "ledger_time": 490945840,
"reserve_base": 20000000, "reserve_base": 20000000,
"reserve_inc": 5000000, "reserve_inc": 5000000,
"txn_count": 19, "txn_count": 19,
"type": "ledgerClosed", "type": "ledgerClosed",
"validated_ledgers": "13983423-14804627" "validated_ledgers": "13983423-14804627"
} }

View File

@@ -1,13 +1,13 @@
{ {
"id": 0, "id": 0,
"status": "error", "status": "error",
"type": "response", "type": "response",
"error": "lgrNotFound", "error": "lgrNotFound",
"error_code": 20, "error_code": 20,
"error_message": "ledgerNotFound", "error_message": "ledgerNotFound",
"request": { "request": {
"command": "ledger", "command": "ledger",
"id": 3, "id": 3,
"ledger_index": 34 "ledger_index": 34
} }
} }

View File

@@ -1,95 +1,95 @@
{ {
"id": 0, "id": 0,
"status": "success", "status": "success",
"type": "response", "type": "response",
"result": { "result": {
"TransactionType": "OfferCancel", "TransactionType": "OfferCancel",
"Flags": 0, "Flags": 0,
"Sequence": 466, "Sequence": 466,
"OfferSequence": 465, "OfferSequence": 465,
"LastLedgerSequence": 14661888, "LastLedgerSequence": 14661888,
"Fee": "12000", "Fee": "12000",
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025", "SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
"TxnSignature": "3045022100E4148E9809C5CE13BC5583E8CA665614D9FF02D6589D13BA7FBB67CF45EAC0BF02201B84DC18A921260BCEE685908260888BC20D4375DB4A8702F25B346CAD7F3387", "TxnSignature": "3045022100E4148E9809C5CE13BC5583E8CA665614D9FF02D6589D13BA7FBB67CF45EAC0BF02201B84DC18A921260BCEE685908260888BC20D4375DB4A8702F25B346CAD7F3387",
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b", "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
"hash": "809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E", "hash": "809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E",
"ledger_index": 14661789, "ledger_index": 14661789,
"inLedger": 14661789, "inLedger": 14661789,
"meta": { "meta": {
"TransactionIndex": 4, "TransactionIndex": 4,
"AffectedNodes": [ "AffectedNodes": [
{ {
"ModifiedNode": { "ModifiedNode": {
"LedgerEntryType": "AccountRoot", "LedgerEntryType": "AccountRoot",
"PreviousTxnLgrSeq": 14661788, "PreviousTxnLgrSeq": 14661788,
"PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2", "PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9", "LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
"PreviousFields": { "PreviousFields": {
"Sequence": 466, "Sequence": 466,
"OwnerCount": 4, "OwnerCount": 4,
"Balance": "71827095" "Balance": "71827095"
}, },
"FinalFields": { "FinalFields": {
"Flags": 0, "Flags": 0,
"Sequence": 467, "Sequence": 467,
"OwnerCount": 3, "OwnerCount": 3,
"Balance": "71815095", "Balance": "71815095",
"Domain": "726970706C652E636F6D", "Domain": "726970706C652E636F6D",
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b" "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
} }
} }
}, },
{ {
"ModifiedNode": { "ModifiedNode": {
"LedgerEntryType": "DirectoryNode", "LedgerEntryType": "DirectoryNode",
"LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250", "LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
"FinalFields": { "FinalFields": {
"Flags": 0, "Flags": 0,
"RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250", "RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
"Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b" "Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
} }
} }
}, },
{ {
"DeletedNode": { "DeletedNode": {
"LedgerEntryType": "DirectoryNode", "LedgerEntryType": "DirectoryNode",
"LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000", "LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
"FinalFields": { "FinalFields": {
"Flags": 0, "Flags": 0,
"ExchangeRate": "550435C0500F1000", "ExchangeRate": "550435C0500F1000",
"RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000", "RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
"TakerPaysCurrency": "0000000000000000000000005553440000000000", "TakerPaysCurrency": "0000000000000000000000005553440000000000",
"TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3", "TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3",
"TakerGetsCurrency": "0000000000000000000000000000000000000000", "TakerGetsCurrency": "0000000000000000000000000000000000000000",
"TakerGetsIssuer": "0000000000000000000000000000000000000000" "TakerGetsIssuer": "0000000000000000000000000000000000000000"
} }
} }
}, },
{ {
"DeletedNode": { "DeletedNode": {
"LedgerEntryType": "Offer", "LedgerEntryType": "Offer",
"LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C", "LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C",
"FinalFields": { "FinalFields": {
"Flags": 0, "Flags": 0,
"Sequence": 465, "Sequence": 465,
"PreviousTxnLgrSeq": 14661788, "PreviousTxnLgrSeq": 14661788,
"BookNode": "0000000000000000", "BookNode": "0000000000000000",
"OwnerNode": "0000000000000000", "OwnerNode": "0000000000000000",
"PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2", "PreviousTxnID": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
"BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000", "BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
"TakerPays": { "TakerPays": {
"value": "237", "value": "237",
"currency": "USD", "currency": "USD",
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q" "issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}, },
"TakerGets": "200", "TakerGets": "200",
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b" "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
} }
} }
} }
], ],
"TransactionResult": "tesSUCCESS" "TransactionResult": "tesSUCCESS"
}, },
"validated": true "validated": true
} }
} }

View File

@@ -48,4 +48,4 @@
}, },
"status": "success", "status": "success",
"type": "response" "type": "response"
} }

View File

@@ -1,92 +1,92 @@
{ {
"id": 0, "id": 0,
"status": "success", "status": "success",
"type": "response", "type": "response",
"result": { "result": {
"TransactionType": "OfferCreate", "TransactionType": "OfferCreate",
"Flags": 0, "Flags": 0,
"Sequence": 465, "Sequence": 465,
"LastLedgerSequence": 14661886, "LastLedgerSequence": 14661886,
"TakerPays": { "TakerPays": {
"value": "237", "value": "237",
"currency": "USD", "currency": "USD",
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q" "issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}, },
"TakerGets": "200", "TakerGets": "200",
"Fee": "12000", "Fee": "12000",
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025", "SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
"TxnSignature": "3045022100FA4CBD0A54A38906F8D4C18FBA4DBCE45B98F9C5A33BC9102CB5911E9E20E88F022032C47AC74E60042FF1517C866680A41B396D61146FBA9E60B4CF74E373CA7AD2", "TxnSignature": "3045022100FA4CBD0A54A38906F8D4C18FBA4DBCE45B98F9C5A33BC9102CB5911E9E20E88F022032C47AC74E60042FF1517C866680A41B396D61146FBA9E60B4CF74E373CA7AD2",
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b", "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
"hash": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2", "hash": "5D9B0B246255815B63983C188B4C23325B3544F605CDBE3004769EE9E990D2F2",
"ledger_index": 14661788, "ledger_index": 14661788,
"inLedger": 14661788, "inLedger": 14661788,
"meta": { "meta": {
"TransactionIndex": 2, "TransactionIndex": 2,
"AffectedNodes": [ "AffectedNodes": [
{ {
"ModifiedNode": { "ModifiedNode": {
"LedgerEntryType": "AccountRoot", "LedgerEntryType": "AccountRoot",
"PreviousTxnLgrSeq": 14660978, "PreviousTxnLgrSeq": 14660978,
"PreviousTxnID": "566D4DE22972C5BAD2506CFFA928B21D2BD33FA52FE16712D17D727681FAA4B1", "PreviousTxnID": "566D4DE22972C5BAD2506CFFA928B21D2BD33FA52FE16712D17D727681FAA4B1",
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9", "LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
"PreviousFields": { "PreviousFields": {
"Sequence": 465, "Sequence": 465,
"OwnerCount": 3, "OwnerCount": 3,
"Balance": "71839095" "Balance": "71839095"
}, },
"FinalFields": { "FinalFields": {
"Flags": 0, "Flags": 0,
"Sequence": 466, "Sequence": 466,
"OwnerCount": 4, "OwnerCount": 4,
"Balance": "71827095", "Balance": "71827095",
"Domain": "726970706C652E636F6D", "Domain": "726970706C652E636F6D",
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b" "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
} }
} }
}, },
{ {
"ModifiedNode": { "ModifiedNode": {
"LedgerEntryType": "DirectoryNode", "LedgerEntryType": "DirectoryNode",
"LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250", "LedgerIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
"FinalFields": { "FinalFields": {
"Flags": 0, "Flags": 0,
"RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250", "RootIndex": "6FCB8B0AF9F22ACF762B7712BF44C6CF172FD2BECD849509604EB7DB3AD2C250",
"Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b" "Owner": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
} }
} }
}, },
{ {
"CreatedNode": { "CreatedNode": {
"LedgerEntryType": "DirectoryNode", "LedgerEntryType": "DirectoryNode",
"LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000", "LedgerIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
"NewFields": { "NewFields": {
"ExchangeRate": "550435C0500F1000", "ExchangeRate": "550435C0500F1000",
"RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000", "RootIndex": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
"TakerPaysCurrency": "0000000000000000000000005553440000000000", "TakerPaysCurrency": "0000000000000000000000005553440000000000",
"TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3" "TakerPaysIssuer": "DD39C650A96EDA48334E70CC4A85B8B2E8502CD3"
} }
} }
}, },
{ {
"CreatedNode": { "CreatedNode": {
"LedgerEntryType": "Offer", "LedgerEntryType": "Offer",
"LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C", "LedgerIndex": "D0BEA7E310CDCEED282911314B0D6D00BB7E3B985EAA275AE2AC2DE3763AAF0C",
"NewFields": { "NewFields": {
"Sequence": 465, "Sequence": 465,
"BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000", "BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA63550435C0500F1000",
"TakerPays": { "TakerPays": {
"value": "237", "value": "237",
"currency": "USD", "currency": "USD",
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q" "issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}, },
"TakerGets": "200", "TakerGets": "200",
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b" "Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b"
} }
} }
} }
], ],
"TransactionResult": "tesSUCCESS" "TransactionResult": "tesSUCCESS"
}, },
"validated": true "validated": true
} }
} }

View File

@@ -96,4 +96,4 @@
}, },
"status": "success", "status": "success",
"type": "response" "type": "response"
} }

View File

@@ -97,4 +97,4 @@
}, },
"status": "success", "status": "success",
"type": "response" "type": "response"
} }

View File

@@ -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
}
}
}

View File

@@ -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
}
}
]
}

View File

@@ -1,6 +0,0 @@
'use strict';
module.exports = {
getTransaction: require('./get-transaction'),
getTransactions: require('./get-transactions')
};

View File

@@ -4,18 +4,19 @@ const assert = require('assert-diff');
const _ = require('lodash'); const _ = require('lodash');
const jayson = require('jayson'); const jayson = require('jayson');
const RippleAPI = require('../../src').RippleAPI;
const createHTTPServer = require('../../src/index').createHTTPServer; const createHTTPServer = require('../../src/index').createHTTPServer;
const {payTo, ledgerAccept} = require('./utils');
const apiFixtures = require('../fixtures'); const apiFixtures = require('../fixtures');
const apiRequests = apiFixtures.requests; const apiRequests = apiFixtures.requests;
const apiResponses = apiFixtures.responses; const apiResponses = apiFixtures.responses;
const fixtures = require('./fixtures');
const TIMEOUT = 20000; // how long before each test case times out const TIMEOUT = 20000; // how long before each test case times out
const serverUri = 'ws://127.0.0.1:6006';
const apiOptions = { const apiOptions = {
server: 'wss://s1.ripple.com' server: serverUri
}; };
const httpPort = 3000; const httpPort = 3000;
@@ -38,11 +39,14 @@ function random() {
return _.fill(Array(16), 0); return _.fill(Array(16), 0);
} }
describe('http server integration tests', function() { describe('http server integration tests', function() {
this.timeout(TIMEOUT); this.timeout(TIMEOUT);
let server = null; let server = null;
let client = null; let client = null;
let paymentId = null;
let newWallet = null;
function createTestInternal(testName, methodName, params, testFunc, id) { function createTestInternal(testName, methodName, params, testFunc, id) {
it(testName, function() { it(testName, function() {
@@ -60,6 +64,21 @@ describe('http server integration tests', function() {
makeNamedParams(params), testFunc, id); 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() { beforeEach(function() {
server = createHTTPServer(apiOptions, httpPort); server = createHTTPServer(apiOptions, httpPort);
return server.start().then(() => { return server.start().then(() => {
@@ -85,32 +104,49 @@ describe('http server integration tests', function() {
result => assert(_.isNumber(result.result.validatedLedger.ledgerVersion)) result => assert(_.isNumber(result.result.validatedLedger.ledgerVersion))
); );
createTest( it('getTransaction', function() {
'getTransaction', const params = [{id: paymentId}];
[{id: '4EB6B76237DEEE99F1EA16FAACED2D1E69C5F9CB54F727A4ECA51A08AD3AF466'}], return new Promise((resolve, reject) => {
result => assert.deepEqual(result, fixtures.getTransaction), client.request('getTransaction', makePositionalParams(params),
'2' (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( it('getTransactions', function() {
'getTransactions', const params = [{address: newWallet.address}, {
[{address: 'rpP2JgiMyTF5jR5hLG3xHCPi1knBb1v9cM'}, {
options: { options: {
binary: true, binary: true,
limit: 1, limit: 1
start:
'FBAAC31D6BAEEFA9E501266FD62DA7A7982662BC19BC42F49BB41405C2F820DB'
} }
}], }];
result => assert.deepEqual(result, fixtures.getTransactions), return new Promise((resolve, reject) => {
'3' 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( createTest(
'prepareSettings', 'prepareSettings',
[ [
{address}, {address},
{settings: apiRequests.prepareSettings}, {settings: apiRequests.prepareSettings.domain},
{instructions: { {instructions: {
maxFee: '0.000012', maxFee: '0.000012',
sequence: 23, sequence: 23,

View File

@@ -9,73 +9,179 @@ const requests = require('../fixtures/requests');
const RippleAPI = require('../../src').RippleAPI; const RippleAPI = require('../../src').RippleAPI;
const {isValidAddress} = require('ripple-address-codec'); const {isValidAddress} = require('ripple-address-codec');
const {isValidSecret} = require('../../src/common'); const {isValidSecret} = require('../../src/common');
const {payTo, ledgerAccept} = require('./utils');
const TIMEOUT = 30000; // how long before each test case times out const TIMEOUT = 10000; // how long before each test case times out
const INTERVAL = 1000; // how long to wait between checks for validated ledger 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...'); console.log('VERIFY...');
return testcase.api.getTransaction(hash, options).then(data => { return testcase.api.getTransaction(hash, options).then(data => {
assert(data && data.outcome); assert(data && data.outcome);
assert.strictEqual(data.type, type); assert.strictEqual(data.type, type);
assert.strictEqual(data.address, wallet.getAddress()); assert.strictEqual(data.address, address);
assert.strictEqual(data.outcome.result, 'tesSUCCESS'); 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}; return {txJSON: JSON.stringify(txData), id: hash, tx: data};
}).catch(error => { }).catch(error => {
if (error instanceof errors.PendingLedgerVersionError) { if (error instanceof errors.PendingLedgerVersionError) {
console.log('NOT VALIDATED YET...'); console.log('NOT VALIDATED YET...');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
setTimeout(() => verifyTransaction(testcase, hash, type, 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); 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; const txJSON = prepared.txJSON;
assert(txJSON, 'missing txJSON'); assert(txJSON, 'missing txJSON');
const txData = JSON.parse(txJSON); const txData = JSON.parse(txJSON);
assert.strictEqual(txData.Account, wallet.getAddress()); assert.strictEqual(txData.Account, address);
const signedData = testcase.api.sign(txJSON, wallet.getSecret()); const signedData = testcase.api.sign(txJSON, secret);
console.log('PREPARED...'); 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...'); console.log('SUBMITTED...');
assert.strictEqual(data.resultCode, 'tesSUCCESS'); assert.strictEqual(data.resultCode, 'tesSUCCESS');
const options = { const options = {
minLedgerVersion: lastClosedLedgerVersion, minLedgerVersion: lastClosedLedgerVersion,
maxLedgerVersion: txData.LastLedgerSequence maxLedgerVersion: txData.LastLedgerSequence
}; };
ledgerAccept(testcase.api);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
setTimeout(() => verifyTransaction(testcase, signedData.id, type, setTimeout(() => verifyTransaction(testcase, signedData.id, type,
options, txData).then(resolve, reject), INTERVAL); options, txData, address).then(resolve, reject), INTERVAL);
}); });
}); });
} }
function setup() { function setup(server = 'wss://s1.ripple.com') {
this.api = new RippleAPI({server: 'wss://s1.ripple.com'}); this.api = new RippleAPI({server});
console.log('CONNECTING...'); console.log('CONNECTING...');
return this.api.connect().then(() => { return this.api.connect().then(() => {
console.log('CONNECTED...'); 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() { function teardown() {
return this.api.disconnect(); return this.api.disconnect();
} }
function suiteSetup() { function suiteSetup() {
this.transactions = []; 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; this.startLedgerVersion = ledgerVersion;
}); })
}).then(teardown.bind(this)); .then(() => setupAccounts(this))
.then(() => teardown.bind(this)());
} }
describe('integration tests', function() { describe('integration tests', function() {
@@ -84,14 +190,14 @@ describe('integration tests', function() {
this.timeout(TIMEOUT); this.timeout(TIMEOUT);
before(suiteSetup); before(suiteSetup);
beforeEach(setup); beforeEach(_.partial(setup, serverUrl));
afterEach(teardown); afterEach(teardown);
it('settings', function() { it('settings', function() {
return this.api.getLedgerVersion().then(ledgerVersion => { return this.api.getLedgerVersion().then(ledgerVersion => {
return this.api.prepareSettings(address, return this.api.prepareSettings(address,
requests.prepareSettings, instructions).then(prepared => requests.prepareSettings.domain, instructions).then(prepared =>
testTransaction(this, 'settings', ledgerVersion, prepared)); testTransaction(this, 'settings', ledgerVersion, prepared));
}); });
}); });
@@ -140,10 +246,10 @@ describe('integration tests', function() {
} }
}; };
return this.api.getLedgerVersion().then(ledgerVersion => { return this.api.getLedgerVersion().then(ledgerVersion => {
return this.api.prepareOrder(address, return this.api.prepareOrder(address, orderSpecification, instructions)
orderSpecification, instructions).then(prepared => .then(prepared =>
testTransaction(this, 'order', ledgerVersion, prepared) testTransaction(this, 'order', ledgerVersion, prepared))
).then(result => { .then(result => {
const txData = JSON.parse(result.txJSON); const txData = JSON.parse(result.txJSON);
return this.api.getOrders(address).then(orders => { return this.api.getOrders(address).then(orders => {
assert(orders && orders.length > 0); assert(orders && orders.length > 0);
@@ -155,8 +261,9 @@ describe('integration tests', function() {
assert.deepEqual(createdOrder.specification, orderSpecification); assert.deepEqual(createdOrder.specification, orderSpecification);
return txData; 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', .then(prepared => testTransaction(this, 'orderCancellation',
ledgerVersion, prepared)) ledgerVersion, prepared))
); );
@@ -232,7 +339,7 @@ describe('integration tests', function() {
it('getSettings', function() { it('getSettings', function() {
return this.api.getSettings(address).then(data => { return this.api.getSettings(address).then(data => {
assert(data); assert(data);
assert.strictEqual(data.domain, requests.prepareSettings.domain); assert.strictEqual(data.domain, requests.prepareSettings.domain.domain);
}); });
}); });
@@ -244,7 +351,7 @@ describe('integration tests', function() {
}, },
counter: { counter: {
currency: 'USD', currency: 'USD',
counterparty: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q' counterparty: masterAccount
} }
}; };
return this.api.getOrderbook(address, orderbook).then(book => { return this.api.getOrderbook(address, orderbook).then(book => {
@@ -272,11 +379,11 @@ describe('integration tests', function() {
address: address address: address
}, },
destination: { destination: {
address: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc', address: this.newWallet.address,
amount: { amount: {
value: '0.000001', value: '1',
currency: 'USD', currency: 'USD',
counterparty: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q' counterparty: masterAccount
} }
} }
}; };
@@ -289,8 +396,24 @@ describe('integration tests', function() {
}); });
}); });
it('getPaths - send all', 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 => { return this.api.getPaths(pathfind).then(data => {
assert(data && data.length > 0); assert(data && data.length > 0);
assert(_.every(data, path => { assert(_.every(data, path => {
@@ -313,3 +436,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;
});
});
});
});
});

View 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
View 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
};

View File

@@ -249,6 +249,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) { mock.on('request_account_lines', function(request, conn) {
if (request.account === addresses.ACCOUNT) { if (request.account === addresses.ACCOUNT) {
conn.send(accountLinesResponse.normal(request)); conn.send(accountLinesResponse.normal(request));