mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-12 08:35:48 +00:00
Compare commits
33 Commits
0.19.0
...
1.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d1132b7fa | ||
|
|
e07fa11923 | ||
|
|
7c92adbf45 | ||
|
|
d55aa2339f | ||
|
|
95e39153da | ||
|
|
65d8260908 | ||
|
|
1aa9feda71 | ||
|
|
2e5b435b11 | ||
|
|
54f12862dc | ||
|
|
226ef862ae | ||
|
|
4a0d675726 | ||
|
|
b2b6715ac0 | ||
|
|
823d93b86c | ||
|
|
7a42db99c9 | ||
|
|
f28ec27614 | ||
|
|
a36e23ebfa | ||
|
|
e978ef1888 | ||
|
|
9af3968508 | ||
|
|
86ce7b707c | ||
|
|
e0eb27ed8e | ||
|
|
2570e2a6d8 | ||
|
|
c71540e77a | ||
|
|
8eba827d11 | ||
|
|
90be539b09 | ||
|
|
43c08e5ea7 | ||
|
|
3f22b12216 | ||
|
|
a72041a321 | ||
|
|
71a0c16fec | ||
|
|
27ab98160a | ||
|
|
4eaaa8188d | ||
|
|
187154a2b0 | ||
|
|
c175e3f58e | ||
|
|
2ea22a099e |
@@ -7,3 +7,4 @@ script:
|
||||
- yarn compile
|
||||
- yarn test
|
||||
- yarn build
|
||||
- yarn lint
|
||||
|
||||
10
Gulpfile.js
10
Gulpfile.js
@@ -50,10 +50,12 @@ function getWebpackConfig(extension, overrides) {
|
||||
use: 'null',
|
||||
}, {
|
||||
test: /\.ts$/,
|
||||
use: 'ts-loader',
|
||||
include: [
|
||||
path.resolve(__dirname, 'src')
|
||||
]
|
||||
use: [{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
compilerOptions: {declaration: false}
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
test: /\.json/,
|
||||
use: 'json-loader',
|
||||
|
||||
137
HISTORY.md
137
HISTORY.md
@@ -1,5 +1,142 @@
|
||||
# ripple-lib Release History
|
||||
|
||||
## 1.0.0-beta.2 (2018-06-08)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
+ During transaction preparation, there is now a maximum fee. Also, when a transaction is signed, its fee is checked and an error is thrown if the fee exceeds the maximum. The default `maxFeeXRP` is `'2'` (2 XRP). Override this value in the RippleAPI constructor.
|
||||
+ Attempting to prepare a transaction with an exact `fee` higher than `maxFeeXRP` causes a `ValidationError` to be thrown.
|
||||
+ Attempting to sign a transaction with a fee higher than `maxFeeXRP` causes a `ValidationError` to be thrown.
|
||||
+ The value returned by `getFee()` is capped at `maxFeeXRP`.
|
||||
|
||||
### Other Changes
|
||||
|
||||
+ In Transaction Instructions, the `maxFee` parameter is deprecated. Use the `maxFeeXRP` parameter in the RippleAPI constructor.
|
||||
|
||||
#### Overview of new fee limit
|
||||
|
||||
Most users of ripple-lib do not need to make any code changes to accommodate the new soft limit on fees. The limit is designed to protect against the most severe cases where an unintentionally high fee may be used.
|
||||
|
||||
+ When having ripple-lib provide the fee with a `prepare*` method, a maximum fee of `maxFeeXRP` (default 2 XRP) applies. You can prepare more economical transactions by setting a lower `maxFeeXRP`, or support high-priority transactions by setting a higher `maxFeeXRP` in the RippleAPI constructor.
|
||||
+ When using `sign` with a Fee higher than `maxFeeXRP`, a `ValidationError` is thrown.
|
||||
|
||||
If you have any questions or concerns, please open an issue on GitHub.
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
ef348a2805098e61395b689b410cbf4bfd35e4d72e38c89f4ab74ec5e19793f5 ripple-1.0.0-beta.2-debug.js
|
||||
ea33fd53df8c7176d5fbf52dae0b64aade7180860f26449062cdbefaf8bd4d9b ripple-1.0.0-beta.2-min.js
|
||||
fe5cc6e97c9b8a1470dacb34f16a64255cd639a25381abe9db1ba79e102456f2 ripple-1.0.0-beta.2.js
|
||||
```
|
||||
|
||||
## 1.0.0-beta.1 (2018-05-24)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
+ Amounts in drops and XRP are checked for validity. Some
|
||||
methods may now throw a `BigNumber Error` or `ValidationError` if the amount
|
||||
is invalid. This may include methods that previously did not throw.
|
||||
+ Note that 1 drop is equivalent to 0.000001 XRP and 1 XRP is equivalent to 1,000,000 drops.
|
||||
+ Using drops is recommended. All rippled APIs require XRP amounts to be
|
||||
expressed in drops.
|
||||
|
||||
### Other Changes
|
||||
|
||||
+ Allow specifying amounts in drops for consistency with the `rippled`
|
||||
APIs.
|
||||
+ Export `xrpToDrops()` and `dropsToXrp()` functions.
|
||||
+ Potentially breaking change: Improve errors. For example, `RippledError` now includes the full response from
|
||||
the `rippled` server ([#687](https://github.com/ripple/ripple-lib/issues/687)). `NotConnectedError`
|
||||
may be thrown with a different message than before.
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
a80ebb39e186640246306eadb2879147458c8271fd3c6cb32e6ef78d0b4b01a5 ripple-1.0.0-beta.1-debug.js
|
||||
81bcc4b5fd6fd52220ed151242eaddd63eb29c4078845edc68f65b769557d126 ripple-1.0.0-beta.1-min.js
|
||||
738b4d65b58cf4e3542fa396f8d319a24cd7d0b7aff5ff629a900e244f735ff4 ripple-1.0.0-beta.1.js
|
||||
```
|
||||
|
||||
## 1.0.0-beta.0 (2018-05-10)
|
||||
|
||||
+ [Add `request`, `hasNextPage`, and
|
||||
`requestNextPage`](https://github.com/ripple/ripple-lib/pull/887).
|
||||
+ This provides support for all rippled APIs, including subscriptions.
|
||||
|
||||
When using rippled APIs, you must:
|
||||
+ For all XRP amounts, use drops (1 drop = 0.000001 XRP).
|
||||
+ Instead of `counterparty`, use `issuer`.
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
ab2094979a3d6b320c7bc22bc5946c50fa5e29af0976d352e7689b0a4d840c55 ripple-1.0.0-beta.0-debug.js
|
||||
0e7f7d740606c2866ebf63776b13b41a555848e1a1419e2c8058d2e6c562d7fd ripple-1.0.0-beta.0-min.js
|
||||
bd05e8806832ca4192aea7ba2d0362baa9f44605f8e8e6676acd25eb0b94b778 ripple-1.0.0-beta.0.js
|
||||
```
|
||||
|
||||
## 0.22.0 (2018-05-10)
|
||||
|
||||
+ [`getOrderbook` - return raw order data](https://github.com/ripple/ripple-lib/pull/886). The full `BookOffer` data is now provided under `data`.
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
33f71b55c4adec4452826e44fe7809377364df04222b60f0fce01e7de2daff33 ripple-0.22.0-debug.js
|
||||
63232888a4ea77065e8e8eb8fdaa8ebfe3a785428fe935e2667c1ea54c837f29 ripple-0.22.0-min.js
|
||||
ab98026fabe296bd938297c48cb58e01dfdbe90f3c66c9617d6a3e1efd4c6b93 ripple-0.22.0.js
|
||||
```
|
||||
|
||||
## 0.21.0 (2018-04-11)
|
||||
|
||||
+ [Upgrade https-proxy-agent](https://github.com/ripple/ripple-lib/pull/883)
|
||||
+ [Add getAccountObjects](https://github.com/ripple/ripple-lib/pull/881)
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
3ab52209ad4a80393c8c08ef3f4aa9cfb47bc76c0ede2ee9fa7f5ca180ba4d67 ripple-0.21.0-debug.js
|
||||
3b1efccded347bed5f64757098a1ea6a513bb8932d922d00af47cd24e001dc14 ripple-0.21.0-min.js
|
||||
db08e5a3eab1f659b4c803543374398004d950ba720adc4b9a7658817cb5c94b ripple-0.21.0.js
|
||||
```
|
||||
|
||||
## 0.20.0 (2018-04-09)
|
||||
|
||||
+ [Add support for using a keypair with sign()](https://github.com/ripple/ripple-lib/pull/769)
|
||||
+ [Fix a bug caused by jsonschema v1.2.3 by pinning to v1.2.2](https://github.com/ripple/ripple-lib/pull/882)
|
||||
+ [Improve Payment Channel documentation](https://github.com/ripple/ripple-lib/pull/877)
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
389811a9baa72f77e2a43d0b48045762d29a6f616ed5fd2660ba76fc12a3ecc5 ripple-0.20.0-debug.js
|
||||
c1746ea0dd55318cb4e1ef3955ef14759d9d70861437c69abafc10169916f068 ripple-0.20.0-min.js
|
||||
17958b0e46395d2b2a35a003693c0babdfb5382513d3cc58a62f8648ad710b0e ripple-0.20.0.js
|
||||
```
|
||||
|
||||
## 0.19.1 (2018-03-22)
|
||||
|
||||
+ [Fix: Include TypeScript declarations in npm package](https://github.com/ripple/ripple-lib/pull/863)
|
||||
+ [Fix: Documentation link to checkCash](https://github.com/ripple/ripple-lib/pull/871)
|
||||
+ [Internal: Clean up types and migrate more APIs to new request method](https://github.com/ripple/ripple-lib/pull/857)
|
||||
+ [Internal: Fix Payment source and destination types](https://github.com/ripple/ripple-lib/pull/870)
|
||||
|
||||
The SHA-256 checksums for the browser version of this release can be found
|
||||
below.
|
||||
```
|
||||
% shasum -a 256 *
|
||||
3ed5332aa035c07bae6c1abfdfc8ca77cdbb05cc4b88878f544f1ea4cb793f4d ripple-0.19.1-debug.js
|
||||
2f5507aa00a40ab6a94de1822af87db5e927edef3885aef5d9b39ccb623ccb54 ripple-0.19.1-min.js
|
||||
1e439aee1b220242d56ea687a9b55a67b8614212c1ddbd70a4fcf34503fc487a ripple-0.19.1.js
|
||||
```
|
||||
|
||||
## 0.19.0 (2018-03-02)
|
||||
|
||||
+ [Add support for Checks](https://github.com/ripple/ripple-lib/pull/853)
|
||||
|
||||
12
README.md
12
README.md
@@ -26,7 +26,17 @@ Install `ripple-lib`:
|
||||
$ yarn add ripple-lib
|
||||
```
|
||||
|
||||
Then see the [documentation](https://github.com/ripple/ripple-lib/blob/develop/docs/index.md) and [code samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples)
|
||||
Then see the [documentation](https://github.com/ripple/ripple-lib/blob/develop/docs/index.md) and [code samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples).
|
||||
|
||||
### Mailing lists
|
||||
|
||||
We have a low-traffic mailing list for announcements of new ripple-lib releases. (About 1 email per week)
|
||||
|
||||
+ [Subscribe to ripple-lib-announce](https://groups.google.com/forum/#!forum/ripple-lib-announce)
|
||||
|
||||
If you're using the XRP Ledger in production, you should run a [rippled server](https://github.com/ripple/rippled) and subscribe to the ripple-server mailing list as well.
|
||||
|
||||
+ [Subscribe to ripple-server](https://groups.google.com/forum/#!forum/ripple-server)
|
||||
|
||||
## Running tests
|
||||
|
||||
|
||||
1191
docs/index.md
1191
docs/index.md
File diff suppressed because it is too large
Load Diff
@@ -19,14 +19,13 @@ Currencies are represented as either 3-character currency codes or 40-character
|
||||
## Value
|
||||
A *value* is a quantity of a currency represented as a decimal string. Be careful: JavaScript's native number format does not have sufficient precision to represent all values. XRP has different precision from other currencies.
|
||||
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
|
||||
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). This smallest unit is called a "drop". XRP has a maximum value of `100000000000` (1e11). Some RippleAPI methods accept XRP in order to maintain compatibility with older versions of the API. For consistency with the `rippled` APIs, we recommend formally specifying XRP values in *drops* in all API requests, and converting them to XRP for display. This is similar to Bitcoin's *satoshis* and Ethereum's *wei*. 1 XRP = 1,000,000 drops.
|
||||
|
||||
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
|
||||
|
||||
|
||||
## Amount
|
||||
|
||||
Example amount:
|
||||
Example 100.00 USD amount:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -36,15 +35,16 @@ Example amount:
|
||||
}
|
||||
```
|
||||
|
||||
Example XRP amount:
|
||||
Example 3.0 XRP amount, in drops:
|
||||
```json
|
||||
{
|
||||
"currency": "XRP",
|
||||
"value": "2000"
|
||||
"currency": "drops",
|
||||
"value": "3000000"
|
||||
}
|
||||
```
|
||||
(Requires `ripple-lib` version 1.0.0 or higher.)
|
||||
|
||||
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value. For XRP, there is no counterparty.
|
||||
An *amount* is an object specifying a currency, a quantity of that currency, and the counterparty (issuer) on the trustline that holds the value. For XRP, there is no counterparty.
|
||||
|
||||
A *lax amount* allows the counterparty to be omitted for all currencies. If the counterparty is not specified in an amount within a transaction specification, then any counterparty may be used for that amount.
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ If you omit the `server` parameter, RippleAPI operates [offline](#offline-functi
|
||||
|
||||
1. Install [Node.js](https://nodejs.org) and [Yarn](https://yarnpkg.com/en/docs/install). Most Linux distros have a package for Node.js; check that it's the version you want.
|
||||
2. Use yarn to install RippleAPI:
|
||||
`yarn install ripple-lib`
|
||||
`yarn add ripple-lib`
|
||||
|
||||
After you have installed ripple-lib, you can create scripts using the [boilerplate](#boilerplate) and run them using the Node.js executable, typically named `node`:
|
||||
|
||||
|
||||
33
docs/src/getAccountObjects.md.ejs
Normal file
33
docs/src/getAccountObjects.md.ejs
Normal file
@@ -0,0 +1,33 @@
|
||||
## getAccountObjects
|
||||
|
||||
`getAccountObjects(address: string, options: object): Promise<AccountObjectsResponse>`
|
||||
|
||||
Returns objects owned by an account. For an account's trust lines and balances, see `getTrustlines` and `getBalances`.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/get-account-objects.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<%- renderSchema('output/get-account-objects.json') %>
|
||||
|
||||
The types of objects that may be returned include:
|
||||
* Offer objects for orders that are currently live, unfunded, or expired but not yet removed.
|
||||
* RippleState objects for trust lines where this account's side is not in the default state.
|
||||
* A SignerList object if the account has multi-signing enabled.
|
||||
* Escrow objects for held payments that have not yet been executed or canceled.
|
||||
* PayChannel objects for open payment channels.
|
||||
* Check objects for pending checks.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
return api.getAccountObjects(address: address).then(objects =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/get-account-objects.json') %>
|
||||
@@ -6,7 +6,7 @@ Returns the estimated transaction fee for the rippled server the RippleAPI insta
|
||||
|
||||
### Parameters
|
||||
|
||||
This method has no parameters.
|
||||
<%- renderSchema('input/get-fee.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ This method returns a promise that resolves with an object with the following st
|
||||
|
||||
<%- renderSchema('output/get-orderbook.json') %>
|
||||
|
||||
### Raw order data
|
||||
|
||||
(Requires ripple-lib 0.22.0 or higher.) The response includes a `data` property containing the raw order data. This may include `owner_funds`, `Flags`, and other fields.
|
||||
|
||||
For details, see the rippled method [book_offers](https://ripple.com/build/rippled-apis/#book-offers).
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
|
||||
27
docs/src/hasNextPage.md.ejs
Normal file
27
docs/src/hasNextPage.md.ejs
Normal file
@@ -0,0 +1,27 @@
|
||||
## hasNextPage
|
||||
|
||||
`hasNextPage(currentResponse): boolean`
|
||||
|
||||
Returns `true` when there are more pages available.
|
||||
|
||||
When there are more results than contained in the response, the response includes a `marker` field. You can use this convenience method, or check for `marker` yourself.
|
||||
|
||||
See [Markers and Pagination](https://ripple.com/build/rippled-apis/#markers-and-pagination).
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns `true` if `currentResponse` includes a `marker`.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
return api.request('ledger_data', {
|
||||
ledger_index: 'validated'
|
||||
}).then(response => {
|
||||
/* Do something useful with response */
|
||||
|
||||
if (api.hasNextPage(response)) {
|
||||
/* There are more pages available */
|
||||
}
|
||||
}).catch(console.error);
|
||||
```
|
||||
@@ -4,6 +4,10 @@
|
||||
<% include basictypes.md.ejs %>
|
||||
<% include transactions.md.ejs %>
|
||||
<% include specifications.md.ejs %>
|
||||
<% include rippledAPIs.md.ejs %>
|
||||
<% include request.md.ejs %>
|
||||
<% include hasNextPage.md.ejs %>
|
||||
<% include requestNextPage.md.ejs %>
|
||||
<% include methods.md.ejs %>
|
||||
<% include connect.md.ejs %>
|
||||
<% include disconnect.md.ejs %>
|
||||
@@ -21,6 +25,7 @@
|
||||
<% include getOrderbook.md.ejs %>
|
||||
<% include getSettings.md.ejs %>
|
||||
<% include getAccountInfo.md.ejs %>
|
||||
<% include getAccountObjects.md.ejs %>
|
||||
<% include getPaymentChannel.md.ejs %>
|
||||
<% include getLedger.md.ejs %>
|
||||
<% include preparePayment.md.ejs %>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Introduction
|
||||
|
||||
RippleAPI is the official client library to the XRP Ledger. Currently, RippleAPI is only available in JavaScript.
|
||||
RippleAPI (ripple-lib) is the official client library to the XRP Ledger. Currently, RippleAPI is only available in JavaScript.
|
||||
Using RippleAPI, you can:
|
||||
|
||||
* [Query transactions from the XRP Ledger history](#gettransaction)
|
||||
@@ -8,5 +8,3 @@ Using RippleAPI, you can:
|
||||
* [Submit](#submit) transactions to the XRP Ledger, including [Payments](#payment), [Orders](#order), [Settings changes](#settings), and [other types](#transaction-types)
|
||||
* [Generate a new XRP Ledger Address](#generateaddress)
|
||||
* ... and [much more](#api-methods).
|
||||
|
||||
RippleAPI only provides access to *validated*, *immutable* transaction data.
|
||||
|
||||
@@ -22,6 +22,8 @@ All "prepare*" methods have the same return type.
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
|
||||
// Buy 10.10 USD (of the specified issuer) for 2.0 XRP (2000000 drops), fill or kill.
|
||||
const order = <%- importFile('test/fixtures/requests/prepare-order.json') %>;
|
||||
return api.prepareOrder(address, order)
|
||||
.then(prepared => {/* ... */});
|
||||
|
||||
27
docs/src/request.md.ejs
Normal file
27
docs/src/request.md.ejs
Normal file
@@ -0,0 +1,27 @@
|
||||
## request
|
||||
|
||||
`request(command: string, options: object): Promise<object>`
|
||||
|
||||
Returns the response from invoking the specified command, with the specified options, on the connected rippled server.
|
||||
|
||||
Refer to [rippled APIs](https://ripple.com/build/rippled-apis/) for commands and options. All XRP amounts must be specified in drops. One drop is equal to 0.000001 XRP. See [Specifying Currency Amounts](https://ripple.com/build/rippled-apis/#specifying-currency-amounts).
|
||||
|
||||
Most commands return data for the `current` (in-progress, open) ledger by default. Do not rely on this. Always specify a ledger version in your request. In the example below, the 'validated' ledger is requested, which is the most recent ledger that has been validated by the whole network. See [Specifying Ledgers](https://ripple.com/build/rippled-apis/#specifying-ledgers).
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with the response from rippled.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
// Replace 'ledger' with your desired rippled command
|
||||
return api.request('ledger', {
|
||||
ledger_index: 'validated'
|
||||
}).then(response => {
|
||||
/* Do something useful with response */
|
||||
console.log(JSON.stringify(response, null, 2))
|
||||
}).catch(console.error);
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/ledger.json') %>
|
||||
29
docs/src/requestNextPage.md.ejs
Normal file
29
docs/src/requestNextPage.md.ejs
Normal file
@@ -0,0 +1,29 @@
|
||||
## requestNextPage
|
||||
|
||||
`requestNextPage(command: string, params: object = {}, currentResponse: object): Promise<object>`
|
||||
|
||||
Requests the next page of data.
|
||||
|
||||
You can use this convenience method, or include `currentResponse.marker` in `params` yourself, when using `request`.
|
||||
|
||||
See [Markers and Pagination](https://ripple.com/build/rippled-apis/#markers-and-pagination).
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with the next page of data from rippled.
|
||||
|
||||
If the response does not have a next page, the promise will reject with `new errors.NotFoundError('response does not have a next page')`.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const command = 'ledger_data'
|
||||
const params = {
|
||||
ledger_index: 'validated'
|
||||
}
|
||||
return api.request(command, params).then(response => {
|
||||
return api.requestNextPage(command, params, response)
|
||||
}).then(response_page_2 => {
|
||||
/* Do something useful with second page of response */
|
||||
}).catch(console.error);
|
||||
```
|
||||
66
docs/src/rippledAPIs.md.ejs
Normal file
66
docs/src/rippledAPIs.md.ejs
Normal file
@@ -0,0 +1,66 @@
|
||||
# rippled APIs
|
||||
|
||||
ripple-lib relies on [rippled APIs](https://ripple.com/build/rippled-apis/) for all online functionality. With ripple-lib version 1.0.0 and higher, you can easily access rippled APIs through ripple-lib. Use the `request()`, `hasNextPage()`, and `requestNextPage()` methods:
|
||||
* Use `request()` to issue any `rippled` command, including `account_currencies`, `subscribe`, and `unsubscribe`. [Full list of API Methods](https://ripple.com/build/rippled-apis/#api-methods).
|
||||
* Use `hasNextPage()` to determine whether a response has more pages. This is true when the response includes a [`marker` field](https://ripple.com/build/rippled-apis/#markers-and-pagination).
|
||||
* Use `requestNextPage()` to request the next page of data.
|
||||
|
||||
When using rippled APIs, [specify XRP amounts in drops](https://ripple.com/build/rippled-apis/#specifying-currency-amounts). 1 XRP = 1000000 drops.
|
||||
|
||||
## Listening to streams
|
||||
|
||||
The `rippled` server can push updates to your client when various events happen. Refer to [Subscriptions in the `rippled` API docs](https://ripple.com/build/rippled-apis/#subscriptions) for details.
|
||||
|
||||
Note that the `streams` parameter for generic streams takes an array. For example, to subscribe to the `validations` stream, use `{ streams: [ 'validations' ] }`.
|
||||
|
||||
The string names of some generic streams to subscribe to are in the table below. (Refer to `rippled` for an up-to-date list of streams.)
|
||||
|
||||
Type | Description
|
||||
---- | -----------
|
||||
`server` | Sends a message whenever the status of the `rippled` server (for example, network connectivity) changes.
|
||||
`ledger` | Sends a message whenever the consensus process declares a new validated ledger.
|
||||
`transactions` | Sends a message whenever a transaction is included in a closed ledger.
|
||||
`transactions_proposed` | Sends a message whenever a transaction is included in a closed ledger, as well as some transactions that have not yet been included in a validated ledger and may never be. Not all proposed transactions appear before validation. Even some transactions that don't succeed are included in validated ledgers because they take the anti-spam transaction fee.
|
||||
`validations` | Sends a message whenever the server receives a validation message, also called a validation vote, regardless of whether the server trusts the validator.
|
||||
`manifests` | Sends a message whenever the server receives a manifest.
|
||||
`peer_status` | (Admin-only) Information about connected peer `rippled` servers, especially with regards to the consensus process.
|
||||
|
||||
When you subscribe to a stream, you must also listen to the relevant message type(s). Some of the available message types are in the table below. (Refer to `rippled` for an up-to-date list of message types.)
|
||||
|
||||
Type | Description
|
||||
---- | -----------
|
||||
`ledgerClosed` | Sent by the `ledger` stream when the consensus process declares a new fully validated ledger. The message identifies the ledger and provides some information about its contents.
|
||||
`validationReceived` | Sent by the `validations` stream when the server receives a validation message, also called a validation vote, regardless of whether the server trusts the validator.
|
||||
`manifestReceived` | Sent by the `manifests` stream when the server receives a manifest.
|
||||
`transaction` | Sent by many subscriptions including `transactions`, `transactions_proposed`, `accounts`, `accounts_proposed`, and `book` (Order Book). See [Transaction Streams](https://ripple.com/build/rippled-apis/#transaction-streams) for details.
|
||||
`peerStatusChange` | (Admin-only) Reports a large amount of information on the activities of other `rippled` servers to which the server is connected.
|
||||
|
||||
To register your listener function, use `connection.on(type, handler)`.
|
||||
|
||||
Here is an example of listening for transactions on given account(s):
|
||||
```
|
||||
const account = 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn' // Replace with the account you want notifications for
|
||||
api.connect().then(() => { // Omit this if you are already connected
|
||||
|
||||
// 'transaction' can be replaced with the relevant `type` from the table above
|
||||
api.connection.on('transaction', (event) => {
|
||||
|
||||
// Do something useful with `event`
|
||||
console.log(JSON.stringify(event, null, 2))
|
||||
})
|
||||
|
||||
api.request('subscribe', {
|
||||
accounts: [ account ]
|
||||
}).then(response => {
|
||||
if (response.status === 'success') {
|
||||
console.log('Successfully subscribed')
|
||||
}
|
||||
}).catch(error => {
|
||||
// Handle `error`
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
The subscription ends when you unsubscribe or the WebSocket connection is closed.
|
||||
|
||||
For full details, see [rippled Subscriptions](https://ripple.com/build/rippled-apis/#subscriptions).
|
||||
@@ -1,6 +1,9 @@
|
||||
## sign
|
||||
|
||||
`sign(txJSON: string, secret: string, options: Object): {signedTransaction: string, id: string}`
|
||||
```
|
||||
sign(txJSON: string, secret: string, options: Object): {signedTransaction: string, id: string}
|
||||
sign(txJSON: string, keypair: Object, options: Object): {signedTransaction: string, id: string}
|
||||
```
|
||||
|
||||
Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).
|
||||
|
||||
@@ -19,7 +22,8 @@ This method returns an object with the following structure:
|
||||
```javascript
|
||||
const txJSON = '{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Domain":"726970706C652E636F6D","LastLedgerSequence":8820051,"Fee":"12","Sequence":23}';
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
return api.sign(txJSON, secret);
|
||||
const keypair = { privateKey: '00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A', publicKey: '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8' };
|
||||
return api.sign(txJSON, secret); // or: api.sign(txJSON, keypair);
|
||||
```
|
||||
|
||||
<%- renderFixture("responses/sign.json") %>
|
||||
|
||||
@@ -16,7 +16,10 @@ Type | Description
|
||||
[escrowExecution](#escrow-execution) | An `escrowExecution` transaction unlocks the funds in an escrow and sends them to the destination of the escrow, but it will only work if the cryptographic condition is provided.
|
||||
[checkCreate](#check-create) | A `checkCreate` transaction creates a check on the ledger, which is a deferred payment that can be cashed by its intended destination.
|
||||
[checkCancel](#check-cancel) | A `checkCancel` transaction cancels an unreedemed Check, removing it from the ledger without sending any money.
|
||||
[checkCash](#checkCash) | A `checkCash` transaction redeems a Check to receive up to the amount authorized by the corresponding `checkCreate` transaction. Only the `destination` address of a Check can cash it.
|
||||
[checkCash](#check-cash) | A `checkCash` transaction redeems a Check to receive up to the amount authorized by the corresponding `checkCreate` transaction. Only the `destination` address of a Check can cash it.
|
||||
[paymentChannelCreate](#payment-channel-create) | A `paymentChannelCreate` transaction opens a payment channel between two addresses with XRP set aside for asynchronous payments.
|
||||
[paymentChannelFund](#payment-channel-fund) | A `paymentChannelFund` transaction adds XRP to a payment channel and optionally sets a new expiration for the channel.
|
||||
[paymentChannelClaim](#payment-channel-claim) | A `paymentChannelClaim` transaction withdraws XRP from a channel and optionally requests to close it.
|
||||
|
||||
## Transaction Flow
|
||||
|
||||
@@ -50,7 +53,7 @@ Transaction instructions indicate how to execute a transaction, complementary wi
|
||||
|
||||
<%- renderSchema("objects/instructions.json") %>
|
||||
|
||||
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 XRP Ledger's consensus-validated 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 recommend 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 XRP Ledger's consensus-validated 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.
|
||||
|
||||
## Transaction ID
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.19.0",
|
||||
"version": "1.0.0-beta.2",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -8,6 +8,7 @@
|
||||
"build/*"
|
||||
],
|
||||
"main": "dist/npm/",
|
||||
"types": "dist/npm/index.d.ts",
|
||||
"browser": {
|
||||
"ws": "./dist/npm/common/wswrapper.js"
|
||||
},
|
||||
@@ -18,8 +19,8 @@
|
||||
"@types/lodash": "^4.14.85",
|
||||
"@types/ws": "^3.2.0",
|
||||
"bignumber.js": "^4.1.0",
|
||||
"https-proxy-agent": "^1.0.0",
|
||||
"jsonschema": "^1.1.1",
|
||||
"https-proxy-agent": "2.2.1",
|
||||
"jsonschema": "1.2.2",
|
||||
"lodash": "^4.17.4",
|
||||
"ripple-address-codec": "^2.0.1",
|
||||
"ripple-binary-codec": "^0.1.13",
|
||||
|
||||
130
src/api.ts
130
src/api.ts
@@ -1,12 +1,9 @@
|
||||
import * as _ from 'lodash'
|
||||
import {EventEmitter} from 'events'
|
||||
import {Connection, errors, validate} from './common'
|
||||
import {Connection, errors, validate, xrpToDrops, dropsToXrp} from './common'
|
||||
import {
|
||||
connect,
|
||||
disconnect,
|
||||
isConnected,
|
||||
getServerInfo,
|
||||
getFee,
|
||||
getLedgerVersion,
|
||||
formatLedgerClose
|
||||
} from './server/server'
|
||||
@@ -20,6 +17,7 @@ import getOrders from './ledger/orders'
|
||||
import getOrderbook from './ledger/orderbook'
|
||||
import getSettings from './ledger/settings'
|
||||
import getAccountInfo from './ledger/accountinfo'
|
||||
import getAccountObjects from './ledger/accountobjects'
|
||||
import getPaymentChannel from './ledger/payment-channel'
|
||||
import preparePayment from './transaction/payment'
|
||||
import prepareTrustline from './transaction/trustline'
|
||||
@@ -45,22 +43,28 @@ import verifyPaymentChannelClaim from './offline/verify-payment-channel-claim'
|
||||
import getLedger from './ledger/ledger'
|
||||
|
||||
import {
|
||||
AccountObjectsRequest, AccountObjectsResponse,
|
||||
AccountOffersRequest, AccountOffersResponse,
|
||||
AccountInfoRequest, AccountInfoResponse,
|
||||
AccountLinesRequest, AccountLinesResponse,
|
||||
BookOffersRequest, BookOffersResponse,
|
||||
GatewayBalancesRequest, GatewayBalancesResponse
|
||||
GatewayBalancesRequest, GatewayBalancesResponse,
|
||||
LedgerRequest, LedgerResponse,
|
||||
LedgerEntryRequest, LedgerEntryResponse,
|
||||
ServerInfoRequest, ServerInfoResponse
|
||||
} from './common/types/commands'
|
||||
|
||||
|
||||
import RangeSet from './common/rangeset'
|
||||
import * as ledgerUtils from './ledger/utils'
|
||||
import * as schemaValidator from './common/schema-validator'
|
||||
import {getServerInfo, getFee} from './common/serverinfo'
|
||||
import {clamp} from './ledger/utils'
|
||||
|
||||
export type APIOptions = {
|
||||
server?: string,
|
||||
feeCushion?: number,
|
||||
maxFeeXRP?: string,
|
||||
trace?: boolean,
|
||||
proxy?: string,
|
||||
timeout?: number
|
||||
@@ -83,25 +87,13 @@ function getCollectKeyFromCommand(command: string): string|undefined {
|
||||
}
|
||||
}
|
||||
|
||||
// prevent access to non-validated ledger versions
|
||||
export class RestrictedConnection extends Connection {
|
||||
request(request: any, timeout?: number) {
|
||||
const ledger_index = request.ledger_index
|
||||
if (ledger_index !== undefined && ledger_index !== 'validated') {
|
||||
if (!_.isNumber(ledger_index) || ledger_index > this._ledgerVersion) {
|
||||
return Promise.reject(new errors.LedgerVersionError(
|
||||
`ledgerVersion ${ledger_index} is greater than server\'s ` +
|
||||
`most recent validated ledger: ${this._ledgerVersion}`))
|
||||
}
|
||||
}
|
||||
return super.request(request, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
class RippleAPI extends EventEmitter {
|
||||
|
||||
_feeCushion: number
|
||||
connection: RestrictedConnection
|
||||
_maxFeeXRP: string
|
||||
|
||||
// New in > 0.21.0
|
||||
// non-validated ledger versions are allowed, and passed to rippled as-is.
|
||||
connection: Connection
|
||||
|
||||
// these are exposed only for use by unit tests; they are not part of the API.
|
||||
static _PRIVATE = {
|
||||
@@ -115,9 +107,10 @@ class RippleAPI extends EventEmitter {
|
||||
super()
|
||||
validate.apiOptions(options)
|
||||
this._feeCushion = options.feeCushion || 1.2
|
||||
this._maxFeeXRP = options.maxFeeXRP || '2'
|
||||
const serverURL = options.server
|
||||
if (serverURL !== undefined) {
|
||||
this.connection = new RestrictedConnection(serverURL, options)
|
||||
this.connection = new Connection(serverURL, options)
|
||||
this.connection.on('ledgerClosed', message => {
|
||||
this.emit('ledger', formatLedgerClose(message))
|
||||
})
|
||||
@@ -133,45 +126,91 @@ class RippleAPI extends EventEmitter {
|
||||
} else {
|
||||
// use null object pattern to provide better error message if user
|
||||
// tries to call a method that requires a connection
|
||||
this.connection = new RestrictedConnection(null, options)
|
||||
this.connection = new Connection(null, options)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a simple request to the API with the given command and any
|
||||
* additional request body parameters.
|
||||
*
|
||||
* NOTE: This command is under development and should not yet be relied
|
||||
* on by external consumers.
|
||||
*/
|
||||
async _request(command: 'account_info', params: AccountInfoRequest):
|
||||
|
||||
async request(command: 'account_info', params: AccountInfoRequest):
|
||||
Promise<AccountInfoResponse>
|
||||
async _request(command: 'account_lines', params: AccountLinesRequest):
|
||||
async request(command: 'account_lines', params: AccountLinesRequest):
|
||||
Promise<AccountLinesResponse>
|
||||
async _request(command: 'account_offers', params: AccountOffersRequest):
|
||||
|
||||
/**
|
||||
* Returns objects owned by an account.
|
||||
* For an account's trust lines and balances,
|
||||
* see `getTrustlines` and `getBalances`.
|
||||
*/
|
||||
async request(command: 'account_objects', params: AccountObjectsRequest):
|
||||
Promise<AccountObjectsResponse>
|
||||
|
||||
async request(command: 'account_offers', params: AccountOffersRequest):
|
||||
Promise<AccountOffersResponse>
|
||||
async _request(command: 'book_offers', params: BookOffersRequest):
|
||||
async request(command: 'book_offers', params: BookOffersRequest):
|
||||
Promise<BookOffersResponse>
|
||||
async _request(command: 'gateway_balances', params: GatewayBalancesRequest):
|
||||
async request(command: 'gateway_balances', params: GatewayBalancesRequest):
|
||||
Promise<GatewayBalancesResponse>
|
||||
async _request(command: string, params: any = {}) {
|
||||
async request(command: 'ledger', params: LedgerRequest):
|
||||
Promise<LedgerResponse>
|
||||
async request(command: 'ledger_entry', params: LedgerEntryRequest):
|
||||
Promise<LedgerEntryResponse>
|
||||
async request(command: 'server_info', params?: ServerInfoRequest):
|
||||
Promise<ServerInfoResponse>
|
||||
|
||||
async request(command: string, params: object):
|
||||
Promise<object>
|
||||
|
||||
/**
|
||||
* Makes a request to the API with the given command and
|
||||
* additional request body parameters.
|
||||
*/
|
||||
async request(command: string, params: object = {}): Promise<object> {
|
||||
return this.connection.request({
|
||||
...params,
|
||||
command
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are more pages of data.
|
||||
*
|
||||
* When there are more results than contained in the response, the response
|
||||
* includes a `marker` field.
|
||||
*
|
||||
* See https://ripple.com/build/rippled-apis/#markers-and-pagination
|
||||
*/
|
||||
hasNextPage<T extends {marker?: string}>(currentResponse: T): boolean {
|
||||
return !!currentResponse.marker
|
||||
}
|
||||
|
||||
async requestNextPage<T extends {marker?: string}>(
|
||||
command: string,
|
||||
params: object = {},
|
||||
currentResponse: T
|
||||
): Promise<object> {
|
||||
if (!currentResponse.marker) {
|
||||
return Promise.reject(
|
||||
new errors.NotFoundError('response does not have a next page')
|
||||
)
|
||||
}
|
||||
const nextPageParams = Object.assign({}, params, {
|
||||
marker: currentResponse.marker
|
||||
})
|
||||
return this.request(command, nextPageParams)
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes multiple paged requests to the API to return a given number of
|
||||
* resources. __requestAll() will make multiple requests until the `limit`
|
||||
* resources. _requestAll() will make multiple requests until the `limit`
|
||||
* number of resources is reached (if no `limit` is provided, a single request
|
||||
* will be made).
|
||||
*
|
||||
* If the command is unknown, an additional `collect` property is required to
|
||||
* know which response key contains the array of resources.
|
||||
*
|
||||
* NOTE: This command is under development and should not yet be relied
|
||||
* on by external consumers.
|
||||
* NOTE: This command is used by existing methods and is not recommended for
|
||||
* general use. Instead, use rippled's built-in pagination and make multiple
|
||||
* requests as needed.
|
||||
*/
|
||||
async _requestAll(command: 'account_offers', params: AccountOffersRequest):
|
||||
Promise<AccountOffersResponse[]>
|
||||
@@ -204,12 +243,9 @@ class RippleAPI extends EventEmitter {
|
||||
limit: countRemaining,
|
||||
marker
|
||||
}
|
||||
// NOTE: We have to generalize the `this._request()` function signature
|
||||
// here until we add support for unknown commands (since command is some
|
||||
// unknown string).
|
||||
const singleResult = await (<Function>this._request)(command, repeatProps)
|
||||
const singleResult = await this.request(command, repeatProps)
|
||||
const collectedData = singleResult[collectKey]
|
||||
marker = singleResult.marker
|
||||
marker = singleResult['marker']
|
||||
results.push(singleResult)
|
||||
// Make sure we handle when no data (not even an empty array) is returned.
|
||||
const isExpectedFormat = Array.isArray(collectedData)
|
||||
@@ -240,6 +276,7 @@ class RippleAPI extends EventEmitter {
|
||||
getOrderbook = getOrderbook
|
||||
getSettings = getSettings
|
||||
getAccountInfo = getAccountInfo
|
||||
getAccountObjects = getAccountObjects
|
||||
getPaymentChannel = getPaymentChannel
|
||||
getLedger = getLedger
|
||||
|
||||
@@ -266,6 +303,9 @@ class RippleAPI extends EventEmitter {
|
||||
signPaymentChannelClaim = signPaymentChannelClaim
|
||||
verifyPaymentChannelClaim = verifyPaymentChannelClaim
|
||||
errors = errors
|
||||
|
||||
xrpToDrops = xrpToDrops
|
||||
dropsToXrp = dropsToXrp
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -7,12 +7,6 @@ import {RippledError, DisconnectedError, NotConnectedError,
|
||||
TimeoutError, ResponseFormatError, ConnectionError,
|
||||
RippledNotInitializedError} from './errors'
|
||||
|
||||
function isStreamMessageType(type) {
|
||||
return type === 'ledgerClosed' ||
|
||||
type === 'transaction' ||
|
||||
type === 'path_find'
|
||||
}
|
||||
|
||||
export interface ConnectionOptions {
|
||||
trace?: boolean,
|
||||
proxy?: string
|
||||
@@ -90,19 +84,20 @@ class Connection extends EventEmitter {
|
||||
const data = JSON.parse(message)
|
||||
if (data.type === 'response') {
|
||||
if (!(Number.isInteger(data.id) && data.id >= 0)) {
|
||||
throw new ResponseFormatError('valid id not found in response')
|
||||
throw new ResponseFormatError('valid id not found in response', data)
|
||||
}
|
||||
return [data.id.toString(), data]
|
||||
} else if (isStreamMessageType(data.type)) {
|
||||
if (data.type === 'ledgerClosed') {
|
||||
this._updateLedgerVersions(data)
|
||||
this._updateFees(data)
|
||||
}
|
||||
return [data.type, data]
|
||||
} else if (data.type === undefined && data.error) {
|
||||
return ['error', data.error, data.error_message, data] // e.g. slowDown
|
||||
}
|
||||
throw new ResponseFormatError('unrecognized message type: ' + data.type)
|
||||
|
||||
// Possible `data.type` values include 'ledgerClosed',
|
||||
// 'transaction', 'path_find', and many others.
|
||||
if (data.type === 'ledgerClosed') {
|
||||
this._updateLedgerVersions(data)
|
||||
this._updateFees(data)
|
||||
}
|
||||
return [data.type, data]
|
||||
}
|
||||
|
||||
_onMessage(message) {
|
||||
@@ -246,7 +241,7 @@ class Connection extends EventEmitter {
|
||||
_onOpenError(reject, error) {
|
||||
this._onOpenErrorBound = null
|
||||
this._unbindOnUnxpectedClose()
|
||||
reject(new NotConnectedError(error && error.message))
|
||||
reject(new NotConnectedError(error.message, error))
|
||||
}
|
||||
|
||||
_createWebSocket(): WebSocket {
|
||||
@@ -404,7 +399,7 @@ class Connection extends EventEmitter {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._ws.send(message, undefined, error => {
|
||||
if (error) {
|
||||
reject(new DisconnectedError(error.message))
|
||||
reject(new DisconnectedError(error.message, error))
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
@@ -427,7 +422,7 @@ class Connection extends EventEmitter {
|
||||
function onDisconnect() {
|
||||
clearTimeout(timer)
|
||||
self.removeAllListeners(eventName)
|
||||
reject(new DisconnectedError())
|
||||
reject(new DisconnectedError('websocket was closed'))
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
@@ -450,12 +445,12 @@ class Connection extends EventEmitter {
|
||||
|
||||
this.once(eventName, response => {
|
||||
if (response.status === 'error') {
|
||||
_reject(new RippledError(response.error))
|
||||
_reject(new RippledError(response.error, response))
|
||||
} else if (response.status === 'success') {
|
||||
_resolve(response.result)
|
||||
} else {
|
||||
_reject(new ResponseFormatError(
|
||||
'unrecognized status: ' + response.status))
|
||||
'unrecognized status: ' + response.status, response))
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ function loadSchemas() {
|
||||
require('./schemas/objects/memo.json'),
|
||||
require('./schemas/objects/memos.json'),
|
||||
require('./schemas/objects/public-key.json'),
|
||||
require('./schemas/objects/private-key.json'),
|
||||
require('./schemas/objects/uint32.json'),
|
||||
require('./schemas/objects/value.json'),
|
||||
require('./schemas/objects/source-adjustment.json'),
|
||||
@@ -60,6 +61,7 @@ function loadSchemas() {
|
||||
require('./schemas/output/sign.json'),
|
||||
require('./schemas/output/submit.json'),
|
||||
require('./schemas/output/get-account-info.json'),
|
||||
require('./schemas/output/get-account-objects.json'),
|
||||
require('./schemas/output/get-balances.json'),
|
||||
require('./schemas/output/get-balance-sheet.json'),
|
||||
require('./schemas/output/get-ledger.json'),
|
||||
@@ -89,6 +91,7 @@ function loadSchemas() {
|
||||
require('./schemas/input/api-options.json'),
|
||||
require('./schemas/input/get-settings.json'),
|
||||
require('./schemas/input/get-account-info.json'),
|
||||
require('./schemas/input/get-account-objects.json'),
|
||||
require('./schemas/input/get-transaction.json'),
|
||||
require('./schemas/input/get-transactions.json'),
|
||||
require('./schemas/input/get-trustlines.json'),
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
"minimum": 1,
|
||||
"description": "Factor to multiply estimated fee by to provide a cushion in case the required fee rises during submission of a transaction. Defaults to `1.2`."
|
||||
},
|
||||
"maxFeeXRP": {
|
||||
"type": "string",
|
||||
"description": "Maximum fee to use with transactions, in XRP. Must be a string-encoded number. Defaults to `'2'`."
|
||||
},
|
||||
"server": {
|
||||
"type": "string",
|
||||
"description": "URI for rippled websocket port to connect to. Must start with `wss://` or `ws://`.",
|
||||
|
||||
56
src/common/schemas/input/get-account-objects.json
Normal file
56
src/common/schemas/input/get-account-objects.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "getAccountObjectsOptions",
|
||||
"description": "Request options for getAccountObjects",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account to get the account objects of."
|
||||
},
|
||||
"options": {
|
||||
"description": "Options that affect what to return.",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"check",
|
||||
"escrow",
|
||||
"offer",
|
||||
"payment_channel",
|
||||
"signer_list",
|
||||
"state"
|
||||
],
|
||||
"description":
|
||||
"(Optional) Filter results to include only this type of ledger object. The valid types are: `check`, `escrow`, `offer`, `payment_channel`, `signer_list`, and `state` (trust line)."
|
||||
},
|
||||
"ledgerHash": {
|
||||
"type": "string",
|
||||
"description":
|
||||
"(Optional) A 20-byte hex string for the ledger version to use."
|
||||
},
|
||||
"ledgerIndex": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "ledgerVersion"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description":
|
||||
"(Optional) The sequence number of the ledger to use, or a shortcut string to choose a ledger automatically."
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"description":
|
||||
"(Optional) The maximum number of objects to include in the results."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["address"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
13
src/common/schemas/input/get-fee.json
Normal file
13
src/common/schemas/input/get-fee.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "getFeeParameters",
|
||||
"description": "Parameters for getFee",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cushion": {
|
||||
"type": "number",
|
||||
"description": "The fee is the product of the base fee, the `load_factor`, and this cushion. Default is provided by the `RippleAPI` constructor's `feeCushion`."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -10,7 +10,23 @@
|
||||
"secret": {
|
||||
"type": "string",
|
||||
"format": "secret",
|
||||
"description": "The secret of the account that is initiating the transaction."
|
||||
"description": "The secret of the account that is initiating the transaction. (This field is exclusive with keypair)."
|
||||
},
|
||||
"keypair": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"privateKey": {
|
||||
"type": "privateKey",
|
||||
"description": "The uppercase hexadecimal representation of the secp256k1 or Ed25519 private key."
|
||||
},
|
||||
"publicKey": {
|
||||
"type": "publicKey",
|
||||
"description": "The uppercase hexadecimal representation of the secp256k1 or Ed25519 public key."
|
||||
}
|
||||
},
|
||||
"description": "The private and public key of the account that is initiating the transaction. (This field is exclusive with secret).",
|
||||
"required": ["privateKey", "publicKey"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
@@ -25,5 +41,15 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["txJSON", "secret"]
|
||||
"required": ["txJSON"],
|
||||
"oneOf": [
|
||||
{
|
||||
"required": ["secret"],
|
||||
"not": {"required": ["keypair"]}
|
||||
},
|
||||
{
|
||||
"required": ["keypair"],
|
||||
"not": {"required": ["secret"]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"$ref": "value"
|
||||
},
|
||||
"currency": {
|
||||
"description": "The three-character code or hexadecimal string used to denote currencies",
|
||||
"description": "The three-character code or hexadecimal string used to denote currencies, or \"drops\" for the smallest unit of XRP.",
|
||||
"$ref": "currency"
|
||||
},
|
||||
"counterparty": {
|
||||
"description": "The Ripple address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\")",
|
||||
"description": "The Ripple address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\" or \"drops\")",
|
||||
"$ref": "address"
|
||||
}
|
||||
},
|
||||
@@ -24,7 +24,7 @@
|
||||
"properties": {
|
||||
"currency": {
|
||||
"not": {
|
||||
"enum": ["XRP"]
|
||||
"enum": ["XRP", "drops"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -33,7 +33,7 @@
|
||||
{
|
||||
"properties": {
|
||||
"currency": {
|
||||
"enum": ["XRP"]
|
||||
"enum": ["XRP", "drops"]
|
||||
}
|
||||
},
|
||||
"not": {
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"description": "The three-character code or hexadecimal string used to denote currencies",
|
||||
"type": "string",
|
||||
"link": "currency",
|
||||
"pattern": "^([a-zA-Z0-9<>(){}[\\]|?!@#$%^&*]{3}|[A-F0-9]{40})$"
|
||||
"pattern": "^([a-zA-Z0-9<>(){}[\\]|?!@#$%^&*]{3}|[A-F0-9]{40}|drops)$"
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"$ref": "value"
|
||||
},
|
||||
"maxFee": {
|
||||
"description": "The maximum fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.",
|
||||
"description": "Deprecated: Use `maxFeeXRP` in the RippleAPI constructor instead. The maximum fee to pay for this transaction. If this exceeds `maxFeeXRP`, `maxFeeXRP` will be used instead. See [Transaction Fees](#transaction-fees) for more information.",
|
||||
"$ref": "value"
|
||||
},
|
||||
"maxLedgerVersion": {
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "ledgerVersion",
|
||||
"description": "A ledger version number",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["validated", "closed", "current"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
7
src/common/schemas/objects/private-key.json
Normal file
7
src/common/schemas/objects/private-key.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "privateKey",
|
||||
"description": "The hexadecimal representation of a secp256k1 or Ed25519 private key.",
|
||||
"type": "string",
|
||||
"pattern": "^[A-F0-9]+$"
|
||||
}
|
||||
48
src/common/schemas/output/get-account-objects.json
Normal file
48
src/common/schemas/output/get-account-objects.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "AccountObjectsResponse",
|
||||
"description": "Response format for account_objects",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"account": {
|
||||
"$ref": "address",
|
||||
"description":
|
||||
"Unique address of the account this request corresponds to."
|
||||
},
|
||||
"account_objects": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
},
|
||||
"description":
|
||||
"Array of objects owned by this account. Each object is in its raw ledger format."
|
||||
},
|
||||
"ledger_hash": {
|
||||
"type": "string",
|
||||
"description":
|
||||
"(May be omitted) The identifying hash of the ledger that was used to generate this response."
|
||||
},
|
||||
"ledger_index": {
|
||||
"$ref": "ledgerVersion",
|
||||
"description":
|
||||
"(May be omitted) The sequence number of the ledger that was used to generate this response."
|
||||
},
|
||||
"ledger_current_index": {
|
||||
"$ref": "ledgerVersion",
|
||||
"description":
|
||||
"(May be omitted) The sequence number of the ledger that was used to generate this response."
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description":
|
||||
"(May be omitted) The limit that was used in this request, if any."
|
||||
},
|
||||
"validated": {
|
||||
"type": "boolean",
|
||||
"description":
|
||||
"If included and set to true, the information in this request comes from a validated ledger version. Otherwise, the information is subject to change."
|
||||
}
|
||||
},
|
||||
"required": ["account", "account_objects"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -45,9 +45,14 @@
|
||||
},
|
||||
"required": ["fundedAmount", "priceOfFundedAmount"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"data": {
|
||||
"description": "The raw order data. This may include `owner_funds`, `Flags`, and other fields.",
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"required": ["specification", "properties"],
|
||||
"required": ["specification", "properties", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
},
|
||||
"amount": {
|
||||
"$ref": "value",
|
||||
"description": "XRP balance of this channel after claim is processed."
|
||||
"description": "Amount of XRP authorized by this signature."
|
||||
},
|
||||
"balance": {
|
||||
"$ref": "value",
|
||||
"description": "Amount of XRP authorized by signature."
|
||||
"description": "Total XRP balance delivered by this channel after claim is processed."
|
||||
},
|
||||
"signature": {
|
||||
"$ref": "signature",
|
||||
"description": "Signature of this claim."
|
||||
"description": "Signed claim authorizing withdrawal of XRP from the channel. (Required except from the channel's source address.)"
|
||||
},
|
||||
"publicKey": {
|
||||
"$ref": "publicKey",
|
||||
"description": "Public key of the channel's sender"
|
||||
"description": "Public key of the channel. (For verifying the signature.)"
|
||||
},
|
||||
"renew": {
|
||||
"type": "boolean",
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
"close": {
|
||||
"type": "boolean",
|
||||
"description": "Request to close the channel."
|
||||
"description": "Request to close the channel. If the channel has no XRP remaining or the destination address requests it, closes the channel immediately (returning unclaimed XRP to the source address). Otherwise, sets the channel to expire after settleDelay seconds have passed."
|
||||
}
|
||||
},
|
||||
"required": ["channel"],
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
},
|
||||
"publicKey": {
|
||||
"$ref": "publicKey",
|
||||
"description": "Public key of the key pair the source will use to sign claims against this channel."
|
||||
"description": "Public key of the key pair the source may use to sign claims against this channel."
|
||||
},
|
||||
"cancelAfter": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Time when this channel expires."
|
||||
"description": "Time when this channel expires. This expiration cannot be changed after creating the channel."
|
||||
},
|
||||
"sourceTag": {
|
||||
"$ref": "tag",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"expiration": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "New expiration for this channel."
|
||||
"description": "New expiration for this channel. (This does not change the cancelAfter expiration, if the channel has one.) Cannot move the expiration sooner than settleDelay seconds from time of the request."
|
||||
}
|
||||
},
|
||||
"required": ["amount", "channel"],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as _ from 'lodash'
|
||||
import {convertKeysFromSnakeCaseToCamelCase} from './utils'
|
||||
import Connection from './connection'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import {RippleAPI} from '../index'
|
||||
|
||||
export type GetServerInfoResponse = {
|
||||
buildVersion: string,
|
||||
@@ -39,8 +39,8 @@ function renameKeys(object, mapping) {
|
||||
})
|
||||
}
|
||||
|
||||
function getServerInfo(connection: Connection): Promise<GetServerInfoResponse> {
|
||||
return connection.request({command: 'server_info'}).then(response => {
|
||||
function getServerInfo(this: RippleAPI): Promise<GetServerInfoResponse> {
|
||||
return this.request('server_info').then(response => {
|
||||
const info = convertKeysFromSnakeCaseToCamelCase(response.info)
|
||||
renameKeys(info, {hostid: 'hostID'})
|
||||
if (info.validatedLedger) {
|
||||
@@ -61,18 +61,23 @@ function getServerInfo(connection: Connection): Promise<GetServerInfoResponse> {
|
||||
})
|
||||
}
|
||||
|
||||
function computeFeeFromServerInfo(cushion: number,
|
||||
serverInfo: GetServerInfoResponse
|
||||
): string {
|
||||
return (new BigNumber(serverInfo.validatedLedger.baseFeeXRP)).
|
||||
times(serverInfo.loadFactor).
|
||||
times(cushion).toString()
|
||||
}
|
||||
async function getFee(
|
||||
this: RippleAPI,
|
||||
cushion?: number
|
||||
): Promise<string> {
|
||||
if (cushion === undefined) {
|
||||
cushion = this._feeCushion
|
||||
}
|
||||
if (cushion === undefined) {
|
||||
cushion = 1.2
|
||||
}
|
||||
|
||||
function getFee(connection: Connection, cushion: number): Promise<string> {
|
||||
return getServerInfo(connection).then(serverInfo => {
|
||||
return computeFeeFromServerInfo(cushion, serverInfo)
|
||||
})
|
||||
const serverInfo = (await this.request('server_info')).info
|
||||
const baseFeeXrp = new BigNumber(serverInfo.validated_ledger.base_fee_xrp)
|
||||
const fee = baseFeeXrp.times(serverInfo.load_factor).times(cushion)
|
||||
|
||||
// Cap fee to `this._maxFeeXRP`
|
||||
return BigNumber.min(fee, this._maxFeeXRP).toString(10)
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import {AccountRoot, SignerList} from '../objects'
|
||||
import {
|
||||
AccountRootLedgerEntry,
|
||||
SignerListLedgerEntry,
|
||||
QueueData
|
||||
} from '../objects'
|
||||
|
||||
export interface AccountInfoRequest {
|
||||
account: string,
|
||||
@@ -10,27 +14,10 @@ export interface AccountInfoRequest {
|
||||
}
|
||||
|
||||
export interface AccountInfoResponse {
|
||||
account_data: AccountRoot,
|
||||
signer_lists?: SignerList[],
|
||||
account_data: AccountRootLedgerEntry,
|
||||
signer_lists?: SignerListLedgerEntry[],
|
||||
ledger_current_index?: number,
|
||||
ledger_index?: number,
|
||||
queue_data?: QueueData,
|
||||
validated?: boolean
|
||||
}
|
||||
|
||||
export interface QueueData {
|
||||
txn_count: number,
|
||||
auth_change_queued?: boolean,
|
||||
lowest_sequence?: number,
|
||||
highest_sequence?: number,
|
||||
max_spend_drops_total?: string,
|
||||
transactions?: TransactionData[]
|
||||
}
|
||||
|
||||
export interface TransactionData {
|
||||
auth_change?: boolean,
|
||||
fee?: string,
|
||||
fee_level?: string,
|
||||
max_spend_drops?: string,
|
||||
seq?: number
|
||||
}
|
||||
|
||||
72
src/common/types/commands/account_objects.ts
Normal file
72
src/common/types/commands/account_objects.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {CheckLedgerEntry} from '../objects'
|
||||
|
||||
export interface GetAccountObjectsOptions {
|
||||
type?: string | (
|
||||
'check' |
|
||||
'escrow' |
|
||||
'offer' |
|
||||
'payment_channel' |
|
||||
'signer_list' |
|
||||
'state'
|
||||
),
|
||||
ledgerHash?: string,
|
||||
ledgerIndex?: number | ('validated' | 'closed' | 'current'),
|
||||
limit?: number,
|
||||
marker?: string
|
||||
}
|
||||
|
||||
export interface AccountObjectsRequest {
|
||||
account: string,
|
||||
|
||||
// (Optional) Filter results to include only this type of ledger object.
|
||||
type?: string | (
|
||||
'check' |
|
||||
'escrow' |
|
||||
'offer' |
|
||||
'payment_channel' |
|
||||
'signer_list' |
|
||||
'state'
|
||||
),
|
||||
|
||||
// (Optional) A 20-byte hex string for the ledger version to use.
|
||||
ledger_hash?: string,
|
||||
|
||||
// (Optional) The sequence number of the ledger to use,
|
||||
// or a shortcut string to choose a ledger automatically.
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current'),
|
||||
|
||||
limit?: number,
|
||||
|
||||
marker?: string
|
||||
}
|
||||
|
||||
export interface AccountObjectsResponse {
|
||||
account: string,
|
||||
|
||||
// Array of objects owned by this account.
|
||||
account_objects: CheckLedgerEntry | object,
|
||||
|
||||
// (May be omitted) The identifying hash of the ledger
|
||||
// that was used to generate this response.
|
||||
ledger_hash?: string,
|
||||
|
||||
// (May be omitted) The sequence number of the ledger version
|
||||
// that was used to generate this response.
|
||||
ledger_index?: number,
|
||||
|
||||
// (May be omitted) The sequence number of the current in-progress ledger
|
||||
// version that was used to generate this response.
|
||||
ledger_current_index?: number,
|
||||
|
||||
// The limit that was used in this request, if any.
|
||||
limit?: number,
|
||||
|
||||
// Server-defined value indicating the response is paginated. Pass this
|
||||
// to the next call to resume where this call left off. Omitted when there
|
||||
// are no additional pages after this one.
|
||||
marker?: string,
|
||||
|
||||
// If true, this information comes from a ledger version
|
||||
// that has been validated by consensus.
|
||||
validated?: boolean
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
TakerRequestAmount,
|
||||
OfferCreateTransaction,
|
||||
RippledAmount
|
||||
RippledAmount,
|
||||
OfferCreateTransaction
|
||||
} from '../objects'
|
||||
|
||||
export interface BookOffersRequest {
|
||||
@@ -15,15 +15,15 @@ export interface BookOffersRequest {
|
||||
}
|
||||
|
||||
export interface BookOffersResponse {
|
||||
offers: OrderBookOffer[],
|
||||
offers: BookOffer[],
|
||||
ledger_hash?: string,
|
||||
ledger_current_index?: number,
|
||||
ledger_index?: number,
|
||||
marker?: any
|
||||
}
|
||||
|
||||
export interface OrderBookOffer extends OfferCreateTransaction {
|
||||
quality?: number
|
||||
export interface BookOffer extends OfferCreateTransaction {
|
||||
quality?: string
|
||||
owner_funds?: string,
|
||||
taker_gets_funded?: RippledAmount,
|
||||
taker_pays_funded?: RippledAmount
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {Amount} from '../objects'
|
||||
|
||||
|
||||
export interface GatewayBalancesRequest {
|
||||
account: string,
|
||||
strict?: boolean,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export * from './account_info'
|
||||
export * from './account_lines'
|
||||
export * from './account_objects'
|
||||
export * from './account_offers'
|
||||
export * from './book_offers'
|
||||
export * from './gateway_balances'
|
||||
export * from './ledger'
|
||||
export * from './ledger_entry'
|
||||
export * from './server_info'
|
||||
|
||||
20
src/common/types/commands/ledger.ts
Normal file
20
src/common/types/commands/ledger.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {Ledger, QueueData} from '../objects'
|
||||
|
||||
export interface LedgerRequest {
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
full?: boolean
|
||||
accounts?: boolean
|
||||
transactions?: boolean
|
||||
expand?: boolean
|
||||
owner_funds?: boolean
|
||||
binary?: boolean
|
||||
queue?: boolean
|
||||
}
|
||||
|
||||
export interface LedgerResponse {
|
||||
ledger_index: number
|
||||
ledger_hash: string
|
||||
ledger: Ledger
|
||||
queue_data?: QueueData
|
||||
}
|
||||
31
src/common/types/commands/ledger_entry.ts
Normal file
31
src/common/types/commands/ledger_entry.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {LedgerEntry} from '../objects'
|
||||
|
||||
export interface LedgerEntryRequest {
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
index?: string,
|
||||
account_root?: string,
|
||||
directory?: string | {
|
||||
sub_index?: number,
|
||||
dir_root: string
|
||||
} | {
|
||||
sub_index?: number,
|
||||
owner: string
|
||||
},
|
||||
offer?: string | {
|
||||
account: string,
|
||||
seq: number
|
||||
},
|
||||
ripple_state?: {
|
||||
accounts: [string, string],
|
||||
currency: string
|
||||
},
|
||||
binary?: boolean
|
||||
}
|
||||
|
||||
export interface LedgerEntryResponse {
|
||||
index: string,
|
||||
ledger_index: number,
|
||||
node_binary?: string,
|
||||
node?: LedgerEntry,
|
||||
}
|
||||
51
src/common/types/commands/server_info.ts
Normal file
51
src/common/types/commands/server_info.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
export interface ServerInfoRequest {
|
||||
id?: number
|
||||
}
|
||||
|
||||
export interface ServerInfoResponse {
|
||||
info: {
|
||||
amendment_blocked?: boolean,
|
||||
build_version: string,
|
||||
closed_ledger?: LedgerInfo,
|
||||
complete_ledgers: string,
|
||||
hostid: string,
|
||||
io_latency_ms: number,
|
||||
last_close: {
|
||||
converge_time_s: number,
|
||||
proposers: number
|
||||
},
|
||||
load?: {
|
||||
job_types: {
|
||||
job_type: string,
|
||||
per_second: number,
|
||||
in_progress: number
|
||||
}[],
|
||||
threads: number
|
||||
},
|
||||
load_factor: number,
|
||||
load_factor_local?: number,
|
||||
load_factor_net?: number,
|
||||
load_factor_cluster?: number,
|
||||
load_factor_fee_escalation?: number,
|
||||
load_factor_fee_queue?: number,
|
||||
load_factor_server?: number,
|
||||
peers: number,
|
||||
pubkey_node: string,
|
||||
pubkey_validator: string,
|
||||
server_state: string,
|
||||
state_accounting: any,
|
||||
uptime: number,
|
||||
validated_ledger?: LedgerInfo,
|
||||
validation_quorum: number,
|
||||
validator_list_expires: string
|
||||
},
|
||||
}
|
||||
|
||||
export interface LedgerInfo {
|
||||
age: number,
|
||||
base_fee_xrp: number,
|
||||
hash: string,
|
||||
reserve_base_xrp: number,
|
||||
reserve_inc_xrp: number,
|
||||
seq: number,
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
export interface AccountRoot {
|
||||
LedgerEntryType: string,
|
||||
Account: string,
|
||||
Flags: number,
|
||||
Sequence: number,
|
||||
Balance: string,
|
||||
OwnerCount: number,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
AccountTxnID?: string,
|
||||
RegularKey?: string,
|
||||
EmailHash?: string,
|
||||
MessageKey?: string
|
||||
TickSize?: number,
|
||||
TransferRate?: number,
|
||||
Domain?: string
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
export * from './accounts'
|
||||
export * from './adjustments'
|
||||
export * from './amounts'
|
||||
export * from './ledger'
|
||||
export * from './ledger_entries'
|
||||
export * from './memos'
|
||||
export * from './orders'
|
||||
export * from './queue_data'
|
||||
export * from './settings'
|
||||
export * from './signers'
|
||||
export * from './transactions'
|
||||
export * from './trustlines'
|
||||
|
||||
22
src/common/types/objects/ledger.ts
Normal file
22
src/common/types/objects/ledger.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export interface Ledger {
|
||||
account_hash: string,
|
||||
close_time: number,
|
||||
close_time_human: string,
|
||||
close_time_resolution: number,
|
||||
closed: boolean,
|
||||
ledger_hash: string,
|
||||
ledger_index: string,
|
||||
parent_hash: string,
|
||||
total_coins: string,
|
||||
transaction_hash: string,
|
||||
transactions: string[] | object[],
|
||||
// @deprecated
|
||||
seqNum?: string,
|
||||
// @deprecated
|
||||
totalCoins?: string,
|
||||
// @deprecated
|
||||
hash?: string,
|
||||
close_flags?: number,
|
||||
parent_close_time?: number,
|
||||
accountState?: any[]
|
||||
}
|
||||
83
src/common/types/objects/ledger_entries.ts
Normal file
83
src/common/types/objects/ledger_entries.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import {SignerEntry} from './index'
|
||||
|
||||
export interface AccountRootLedgerEntry {
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
Account: string,
|
||||
Balance: string,
|
||||
Flags: number,
|
||||
OwnerCount: number,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
Sequence: number,
|
||||
AccountTxnID?: string,
|
||||
Domain?: string,
|
||||
EmailHash?: string,
|
||||
MessageKey?: string
|
||||
RegularKey?: string,
|
||||
TickSize?: number,
|
||||
TransferRate?: number,
|
||||
WalletLocator?: string, // DEPRECATED
|
||||
WalletSize?: number // DEPRECATED
|
||||
}
|
||||
|
||||
export interface AmendmentsLedgerEntry {
|
||||
LedgerEntryType: 'Amendments',
|
||||
Amendments?: string[],
|
||||
Majorities?: any[],
|
||||
Flags: 0
|
||||
}
|
||||
|
||||
export interface CheckLedgerEntry {
|
||||
LedgerEntryType: 'Check',
|
||||
Account: string,
|
||||
Destination, string,
|
||||
Flags: 0,
|
||||
OwnerNode: string,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
SendMax: string | object,
|
||||
Sequence: number,
|
||||
DestinationNode: string,
|
||||
DestinationTag: number,
|
||||
Expiration: number,
|
||||
InvoiceID: string,
|
||||
SourceTag: number
|
||||
}
|
||||
|
||||
export interface PayChannelLedgerEntry {
|
||||
LedgerEntryType: 'PayChannel',
|
||||
Sequence: number,
|
||||
Account: string,
|
||||
Amount: string,
|
||||
Balance: string,
|
||||
PublicKey: string,
|
||||
Destination: string,
|
||||
SettleDelay: number,
|
||||
Expiration?: number,
|
||||
CancelAfter?: number,
|
||||
SourceTag?: number,
|
||||
DestinationTag?: number,
|
||||
OwnerNode: string,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
index: string
|
||||
}
|
||||
|
||||
export interface SignerListLedgerEntry {
|
||||
LedgerEntryType: 'SignerList',
|
||||
OwnerNode: string,
|
||||
SignerQuorum: number,
|
||||
SignerEntries: SignerEntry[],
|
||||
SignerListID: number,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
|
||||
// TODO: Add the other ledger entry types, then remove the `any` fallback
|
||||
// see https://ripple.com/build/ledger-format/#ledger-object-types
|
||||
export type LedgerEntry =
|
||||
AccountRootLedgerEntry |
|
||||
AmendmentsLedgerEntry |
|
||||
PayChannelLedgerEntry |
|
||||
SignerListLedgerEntry |
|
||||
any
|
||||
17
src/common/types/objects/orders.ts
Normal file
17
src/common/types/objects/orders.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {Amount} from './amounts'
|
||||
import {Memo} from './memos'
|
||||
|
||||
export type FormattedOrderSpecification = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
expirationTime?: string,
|
||||
orderToReplace?: number,
|
||||
memos?: Memo[],
|
||||
// If enabled, the offer will not consume offers that exactly match it, and
|
||||
// instead becomes an Offer node in the ledger. It will still consume offers
|
||||
// that cross it.
|
||||
passive?: boolean
|
||||
}
|
||||
16
src/common/types/objects/queue_data.ts
Normal file
16
src/common/types/objects/queue_data.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export interface QueueTransaction {
|
||||
auth_change: boolean,
|
||||
fee: string,
|
||||
fee_level: string,
|
||||
max_spend_drops: string,
|
||||
seq: number
|
||||
}
|
||||
|
||||
export interface QueueData {
|
||||
txn_count: number,
|
||||
auth_change_queued?: boolean,
|
||||
lowest_sequence?: number,
|
||||
highest_sequence?: number,
|
||||
max_spend_drops_total?: string,
|
||||
transactions?: QueueTransaction[]
|
||||
}
|
||||
30
src/common/types/objects/settings.ts
Normal file
30
src/common/types/objects/settings.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import {Memo} from './memos'
|
||||
|
||||
export type WeightedSigner = {
|
||||
address: string,
|
||||
weight: number
|
||||
}
|
||||
|
||||
export type Signers = {
|
||||
threshold?: number,
|
||||
weights: WeightedSigner[]
|
||||
}
|
||||
|
||||
export type FormattedSettings = {
|
||||
passwordSpent?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
requireAuthorization?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
noFreeze?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
defaultRipple?: boolean,
|
||||
emailHash?: string|null,
|
||||
messageKey?: string,
|
||||
domain?: string,
|
||||
transferRate?: number|null,
|
||||
regularKey?: string,
|
||||
signers?: Signers,
|
||||
memos?: Memo[]
|
||||
}
|
||||
@@ -1,13 +1,3 @@
|
||||
export interface SignerList {
|
||||
LedgerEntryType: string,
|
||||
OwnerNode: string,
|
||||
SignerQuorum: number,
|
||||
SignerEntries: SignerEntry[],
|
||||
SignerListID: number,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
|
||||
export interface SignerEntry {
|
||||
Account: string,
|
||||
SignerWeight: number
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as _ from 'lodash'
|
||||
import BigNumber from 'bignumber.js'
|
||||
const {deriveKeypair} = require('ripple-keypairs')
|
||||
|
||||
import {deriveKeypair} from 'ripple-keypairs'
|
||||
import {Amount, RippledAmount} from './types/objects'
|
||||
import {ValidationError} from './errors'
|
||||
|
||||
function isValidSecret(secret: string): boolean {
|
||||
try {
|
||||
@@ -13,18 +13,86 @@ function isValidSecret(secret: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function dropsToXrp(drops: string): string {
|
||||
return (new BigNumber(drops)).dividedBy(1000000.0).toString()
|
||||
function dropsToXrp(drops: string | BigNumber): string {
|
||||
if (typeof drops === 'string') {
|
||||
if (!drops.match(/^-?[0-9]*\.?[0-9]*$/)) {
|
||||
throw new ValidationError(`dropsToXrp: invalid value '${drops}',` +
|
||||
` should be a number matching (^-?[0-9]*\.?[0-9]*$).`)
|
||||
} else if (drops === '.') {
|
||||
throw new ValidationError(`dropsToXrp: invalid value '${drops}',` +
|
||||
` should be a BigNumber or string-encoded number.`)
|
||||
}
|
||||
}
|
||||
|
||||
// Converting to BigNumber and then back to string should remove any
|
||||
// decimal point followed by zeros, e.g. '1.00'.
|
||||
// Important: specify base 10 to avoid exponential notation, e.g. '1e-7'.
|
||||
drops = (new BigNumber(drops)).toString(10)
|
||||
|
||||
// drops are only whole units
|
||||
if (drops.includes('.')) {
|
||||
throw new ValidationError(`dropsToXrp: value '${drops}' has` +
|
||||
` too many decimal places.`)
|
||||
}
|
||||
|
||||
// This should never happen; the value has already been
|
||||
// validated above. This just ensures BigNumber did not do
|
||||
// something unexpected.
|
||||
if (!drops.match(/^-?[0-9]+$/)) {
|
||||
throw new ValidationError(`dropsToXrp: failed sanity check -` +
|
||||
` value '${drops}',` +
|
||||
` does not match (^-?[0-9]+$).`)
|
||||
}
|
||||
|
||||
return (new BigNumber(drops)).dividedBy(1000000.0).toString(10)
|
||||
}
|
||||
|
||||
function xrpToDrops(xrp: string): string {
|
||||
return (new BigNumber(xrp)).times(1000000.0).floor().toString()
|
||||
function xrpToDrops(xrp: string | BigNumber): string {
|
||||
if (typeof xrp === 'string') {
|
||||
if (!xrp.match(/^-?[0-9]*\.?[0-9]*$/)) {
|
||||
throw new ValidationError(`xrpToDrops: invalid value '${xrp}',` +
|
||||
` should be a number matching (^-?[0-9]*\.?[0-9]*$).`)
|
||||
} else if (xrp === '.') {
|
||||
throw new ValidationError(`xrpToDrops: invalid value '${xrp}',` +
|
||||
` should be a BigNumber or string-encoded number.`)
|
||||
}
|
||||
}
|
||||
|
||||
// Important: specify base 10 to avoid exponential notation, e.g. '1e-7'.
|
||||
xrp = (new BigNumber(xrp)).toString(10)
|
||||
|
||||
// This should never happen; the value has already been
|
||||
// validated above. This just ensures BigNumber did not do
|
||||
// something unexpected.
|
||||
if (!xrp.match(/^-?[0-9.]+$/)) {
|
||||
throw new ValidationError(`xrpToDrops: failed sanity check -` +
|
||||
` value '${xrp}',` +
|
||||
` does not match (^-?[0-9.]+$).`)
|
||||
}
|
||||
|
||||
const components = xrp.split('.')
|
||||
if (components.length > 2) {
|
||||
throw new ValidationError(`xrpToDrops: failed sanity check -` +
|
||||
` value '${xrp}' has` +
|
||||
` too many decimal points.`)
|
||||
}
|
||||
|
||||
const fraction = components[1] || '0'
|
||||
if (fraction.length > 6) {
|
||||
throw new ValidationError(`xrpToDrops: value '${xrp}' has` +
|
||||
` too many decimal places.`)
|
||||
}
|
||||
|
||||
return (new BigNumber(xrp)).times(1000000.0).floor().toString(10)
|
||||
}
|
||||
|
||||
function toRippledAmount(amount: Amount): RippledAmount {
|
||||
if (amount.currency === 'XRP') {
|
||||
return xrpToDrops(amount.value)
|
||||
}
|
||||
if (amount.currency === 'drops') {
|
||||
return amount.value
|
||||
}
|
||||
return {
|
||||
currency: amount.currency,
|
||||
issuer: amount.counterparty ? amount.counterparty :
|
||||
|
||||
@@ -35,7 +35,7 @@ export default async function getAccountInfo(
|
||||
// 1. Validate
|
||||
validate.getAccountInfo({address, options})
|
||||
// 2. Make Request
|
||||
const response = await this._request('account_info', {
|
||||
const response = await this.request('account_info', {
|
||||
account: address,
|
||||
ledger_index: options.ledgerVersion || 'validated'
|
||||
})
|
||||
|
||||
27
src/ledger/accountobjects.ts
Normal file
27
src/ledger/accountobjects.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import {removeUndefined} from '../common'
|
||||
import {RippleAPI} from '../api'
|
||||
import {
|
||||
GetAccountObjectsOptions,
|
||||
AccountObjectsResponse
|
||||
} from '../common/types/commands/account_objects'
|
||||
|
||||
export default async function getAccountObjects(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: GetAccountObjectsOptions = {}
|
||||
): Promise<AccountObjectsResponse> {
|
||||
// Don't validate the options so that new types can be passed
|
||||
// through to rippled. rippled validates requests.
|
||||
|
||||
// Make Request
|
||||
const response = await this.request('account_objects', removeUndefined({
|
||||
account: address,
|
||||
type: options.type,
|
||||
ledger_hash: options.ledgerHash,
|
||||
ledger_index: options.ledgerIndex,
|
||||
limit: options.limit,
|
||||
marker: options.marker
|
||||
}))
|
||||
// Return Response
|
||||
return response
|
||||
}
|
||||
@@ -54,7 +54,7 @@ async function getBalanceSheet(
|
||||
validate.getBalanceSheet({address, options})
|
||||
options = await ensureLedgerVersion.call(this, options)
|
||||
// 2. Make Request
|
||||
const response = await this._request('gateway_balances', {
|
||||
const response = await this.request('gateway_balances', {
|
||||
account: address,
|
||||
strict: true,
|
||||
hotwallet: options.excludeAddresses,
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import {validate} from '../common'
|
||||
import parseLedger from './parse/ledger'
|
||||
import {GetLedger} from './types'
|
||||
import {FormattedLedger, parseLedger} from './parse/ledger'
|
||||
import {RippleAPI} from '../api'
|
||||
|
||||
export type LedgerOptions = {
|
||||
export type GetLedgerOptions = {
|
||||
ledgerVersion?: number,
|
||||
includeAllData?: boolean,
|
||||
includeTransactions?: boolean,
|
||||
includeState?: boolean
|
||||
}
|
||||
|
||||
|
||||
function getLedger(options: LedgerOptions = {}): Promise<GetLedger> {
|
||||
async function getLedger(
|
||||
this: RippleAPI, options: GetLedgerOptions = {}
|
||||
): Promise<FormattedLedger> {
|
||||
// 1. Validate
|
||||
validate.getLedger({options})
|
||||
|
||||
const request = {
|
||||
command: 'ledger',
|
||||
// 2. Make Request
|
||||
const response = await this.request('ledger', {
|
||||
ledger_index: options.ledgerVersion || 'validated',
|
||||
expand: options.includeAllData,
|
||||
transactions: options.includeTransactions,
|
||||
accounts: options.includeState
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(response =>
|
||||
parseLedger(response.ledger))
|
||||
})
|
||||
// 3. Return Formatted Response
|
||||
return parseLedger(response.ledger)
|
||||
}
|
||||
|
||||
|
||||
export default getLedger
|
||||
|
||||
@@ -1,51 +1,28 @@
|
||||
import * as _ from 'lodash'
|
||||
import * as utils from './utils'
|
||||
import parseOrderbookOrder from './parse/orderbook-order'
|
||||
import {
|
||||
parseOrderbookOrder,
|
||||
FormattedOrderbookOrder
|
||||
} from './parse/orderbook-order'
|
||||
import {validate} from '../common'
|
||||
import {OrderSpecification} from './types'
|
||||
import {Amount, Issue} from '../common/types/objects'
|
||||
import {BookOffer} from '../common/types/commands'
|
||||
import {RippleAPI} from '../api'
|
||||
import {OfferCreateTransaction} from '../common/types/objects'
|
||||
|
||||
export type OrdersOptions = {
|
||||
limit?: number,
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type Orderbook = {
|
||||
base: Issue,
|
||||
counter: Issue
|
||||
}
|
||||
|
||||
export type OrderbookItem = {
|
||||
specification: OrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
makerExchangeRate: string
|
||||
},
|
||||
state?: {
|
||||
fundedAmount: Amount,
|
||||
priceOfFundedAmount: Amount
|
||||
}
|
||||
}
|
||||
|
||||
export type OrderbookOrders = Array<OrderbookItem>
|
||||
|
||||
export type GetOrderbook = {
|
||||
bids: OrderbookOrders,
|
||||
asks: OrderbookOrders
|
||||
export type FormattedOrderbook = {
|
||||
bids: FormattedOrderbookOrder[],
|
||||
asks: FormattedOrderbookOrder[]
|
||||
}
|
||||
|
||||
function isSameIssue(a: Amount, b: Amount) {
|
||||
return a.currency === b.currency && a.counterparty === b.counterparty
|
||||
}
|
||||
|
||||
function directionFilter(direction: string, order: OrderbookItem) {
|
||||
function directionFilter(direction: string, order: FormattedOrderbookOrder) {
|
||||
return order.specification.direction === direction
|
||||
}
|
||||
|
||||
function flipOrder(order: OrderbookItem) {
|
||||
function flipOrder(order: FormattedOrderbookOrder) {
|
||||
const specification = order.specification
|
||||
const flippedSpecification = {
|
||||
quantity: specification.totalPrice,
|
||||
@@ -56,13 +33,13 @@ function flipOrder(order: OrderbookItem) {
|
||||
return _.merge({}, order, {specification: newSpecification})
|
||||
}
|
||||
|
||||
function alignOrder(base: Amount, order: OrderbookItem) {
|
||||
function alignOrder(base: Amount, order: FormattedOrderbookOrder) {
|
||||
const quantity = order.specification.quantity
|
||||
return isSameIssue(quantity, base) ? order : flipOrder(order)
|
||||
}
|
||||
|
||||
function formatBidsAndAsks(
|
||||
orderbook: Orderbook, offers: OfferCreateTransaction[]) {
|
||||
orderbook: OrderbookInfo, offers: BookOffer[]) {
|
||||
// the "base" currency is the currency that you are buying or selling
|
||||
// the "counter" is the currency that the "base" is priced in
|
||||
// a "bid"/"ask" is an order to buy/sell the base, respectively
|
||||
@@ -83,7 +60,7 @@ function formatBidsAndAsks(
|
||||
// account is to specify a "perspective", which affects which unfunded offers
|
||||
// are returned
|
||||
async function makeRequest(
|
||||
api: RippleAPI, taker: string, options: OrdersOptions,
|
||||
api: RippleAPI, taker: string, options: GetOrderbookOptions,
|
||||
takerGets: Issue, takerPays: Issue
|
||||
) {
|
||||
const orderData = utils.renameCounterpartyToIssuerInOrder({
|
||||
@@ -96,15 +73,26 @@ async function makeRequest(
|
||||
ledger_index: options.ledgerVersion || 'validated',
|
||||
limit: options.limit,
|
||||
taker
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export type GetOrderbookOptions = {
|
||||
limit?: number,
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type OrderbookInfo = {
|
||||
base: Issue,
|
||||
counter: Issue
|
||||
}
|
||||
|
||||
export default async function getOrderbook(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
orderbook: Orderbook,
|
||||
options: OrdersOptions = {}
|
||||
): Promise<GetOrderbook> {
|
||||
orderbook: OrderbookInfo,
|
||||
options: GetOrderbookOptions = {}
|
||||
): Promise<FormattedOrderbook> {
|
||||
// 1. Validate
|
||||
validate.getOrderbook({address, orderbook, options})
|
||||
// 2. Make Request
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as _ from 'lodash'
|
||||
import {validate} from '../common'
|
||||
import parseAccountOrder from './parse/account-order'
|
||||
import {Order} from './types'
|
||||
import {FormattedAccountOrder, parseAccountOrder} from './parse/account-order'
|
||||
import {RippleAPI} from '../api'
|
||||
import {AccountOffersResponse} from '../common/types/commands/account_offers'
|
||||
import {AccountOffersResponse} from '../common/types/commands'
|
||||
|
||||
export type GetOrdersOptions = {
|
||||
limit?: number,
|
||||
@@ -12,8 +11,8 @@ export type GetOrdersOptions = {
|
||||
|
||||
function formatResponse(
|
||||
address: string, responses: AccountOffersResponse[]
|
||||
): Order[] {
|
||||
let orders: Order[] = []
|
||||
): FormattedAccountOrder[] {
|
||||
let orders: FormattedAccountOrder[] = []
|
||||
for (const response of responses) {
|
||||
const offers = response.offers.map(offer => {
|
||||
return parseAccountOrder(address, offer)
|
||||
@@ -25,7 +24,7 @@ function formatResponse(
|
||||
|
||||
export default async function getOrders(
|
||||
this: RippleAPI, address: string, options: GetOrdersOptions = {}
|
||||
): Promise<Order[]> {
|
||||
): Promise<FormattedAccountOrder[]> {
|
||||
// 1. Validate
|
||||
validate.getOrders({address, options})
|
||||
// 2. Make Request
|
||||
|
||||
@@ -3,7 +3,16 @@ import parseAmount from './amount'
|
||||
import {parseTimestamp, adjustQualityForXRP} from './utils'
|
||||
import {removeUndefined} from '../../common'
|
||||
import {orderFlags} from './flags'
|
||||
import {Order} from '../types'
|
||||
import {FormattedOrderSpecification} from '../../common/types/objects'
|
||||
|
||||
export type FormattedAccountOrder = {
|
||||
specification: FormattedOrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
makerExchangeRate: string
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this function once rippled provides quality directly
|
||||
function computeQuality(takerGets, takerPays) {
|
||||
@@ -13,7 +22,9 @@ function computeQuality(takerGets, takerPays) {
|
||||
|
||||
// rippled 'account_offers' returns a different format for orders than 'tx'
|
||||
// the flags are also different
|
||||
function parseAccountOrder(address: string, order: any): Order {
|
||||
export function parseAccountOrder(
|
||||
address: string, order: any
|
||||
): FormattedAccountOrder {
|
||||
const direction = (order.flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(order.taker_gets)
|
||||
const takerPaysAmount = parseAmount(order.taker_pays)
|
||||
@@ -43,5 +54,3 @@ function parseAccountOrder(address: string, order: any): Order {
|
||||
|
||||
return {specification, properties}
|
||||
}
|
||||
|
||||
export default parseAccountOrder
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
import * as _ from 'lodash'
|
||||
import {removeUndefined, rippleTimeToISO8601} from '../../common'
|
||||
import parseTransaction from './transaction'
|
||||
import {GetLedger} from '../types'
|
||||
import {Ledger} from '../../common/types/objects'
|
||||
|
||||
export type FormattedLedger = {
|
||||
// TODO: properties in type don't match response object. Fix!
|
||||
// accepted: boolean,
|
||||
// closed: boolean,
|
||||
stateHash: string,
|
||||
closeTime: string,
|
||||
closeTimeResolution: number,
|
||||
closeFlags: number,
|
||||
ledgerHash: string,
|
||||
ledgerVersion: number,
|
||||
parentLedgerHash: string,
|
||||
parentCloseTime: string,
|
||||
totalDrops: string,
|
||||
transactionHash: string,
|
||||
transactions?: Array<Object>,
|
||||
rawTransactions?: string,
|
||||
transactionHashes?: Array<string>,
|
||||
rawState?: string,
|
||||
stateHashes?: Array<string>
|
||||
}
|
||||
|
||||
function parseTransactionWrapper(ledgerVersion, tx) {
|
||||
const transaction = _.assign({}, _.omit(tx, 'metaData'), {
|
||||
@@ -39,7 +60,7 @@ function parseState(state) {
|
||||
return {rawState: JSON.stringify(state)}
|
||||
}
|
||||
|
||||
function parseLedger(ledger: any): GetLedger {
|
||||
export function parseLedger(ledger: Ledger): FormattedLedger {
|
||||
const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10)
|
||||
return removeUndefined(Object.assign({
|
||||
stateHash: ledger.account_hash,
|
||||
@@ -57,5 +78,3 @@ function parseLedger(ledger: any): GetLedger {
|
||||
parseState(ledger.accountState)
|
||||
))
|
||||
}
|
||||
|
||||
export default parseLedger
|
||||
|
||||
@@ -2,9 +2,14 @@ import * as assert from 'assert'
|
||||
import {parseTimestamp} from './utils'
|
||||
import parseAmount from './amount'
|
||||
import {removeUndefined, txFlags} from '../../common'
|
||||
import {
|
||||
FormattedOrderSpecification,
|
||||
OfferCreateTransaction
|
||||
} from '../../common/types/objects/index'
|
||||
|
||||
const flags = txFlags.OfferCreate
|
||||
|
||||
function parseOrder(tx: any): Object {
|
||||
function parseOrder(tx: OfferCreateTransaction): FormattedOrderSpecification {
|
||||
assert(tx.TransactionType === 'OfferCreate')
|
||||
|
||||
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell'
|
||||
|
||||
@@ -4,41 +4,57 @@ import {removeUndefined} from '../../common'
|
||||
|
||||
import {orderFlags} from './flags'
|
||||
import parseAmount from './amount'
|
||||
import {BookOffer} from '../../common/types/commands'
|
||||
import {Amount, FormattedOrderSpecification} from '../../common/types/objects'
|
||||
|
||||
function parseOrderbookOrder(order: any): Object {
|
||||
const direction = (order.Flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(order.TakerGets)
|
||||
const takerPaysAmount = parseAmount(order.TakerPays)
|
||||
export type FormattedOrderbookOrder = {
|
||||
specification: FormattedOrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
makerExchangeRate: string
|
||||
},
|
||||
state?: {
|
||||
fundedAmount: Amount,
|
||||
priceOfFundedAmount: Amount
|
||||
},
|
||||
data: BookOffer
|
||||
}
|
||||
|
||||
export function parseOrderbookOrder(
|
||||
data: BookOffer
|
||||
): FormattedOrderbookOrder {
|
||||
const direction = (data.Flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(data.TakerGets)
|
||||
const takerPaysAmount = parseAmount(data.TakerPays)
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount
|
||||
|
||||
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
||||
// so we can omit those flags here
|
||||
const specification = removeUndefined({
|
||||
const specification: FormattedOrderSpecification = removeUndefined({
|
||||
direction: direction,
|
||||
quantity: quantity,
|
||||
totalPrice: totalPrice,
|
||||
passive: ((order.Flags & orderFlags.Passive) !== 0) || undefined,
|
||||
expirationTime: parseTimestamp(order.Expiration)
|
||||
passive: ((data.Flags & orderFlags.Passive) !== 0) || undefined,
|
||||
expirationTime: parseTimestamp(data.Expiration)
|
||||
})
|
||||
|
||||
const properties = {
|
||||
maker: order.Account,
|
||||
sequence: order.Sequence,
|
||||
makerExchangeRate: adjustQualityForXRP(order.quality,
|
||||
maker: data.Account,
|
||||
sequence: data.Sequence,
|
||||
makerExchangeRate: adjustQualityForXRP(data.quality,
|
||||
takerGetsAmount.currency, takerPaysAmount.currency)
|
||||
}
|
||||
|
||||
const takerGetsFunded = order.taker_gets_funded ?
|
||||
parseAmount(order.taker_gets_funded) : undefined
|
||||
const takerPaysFunded = order.taker_pays_funded ?
|
||||
parseAmount(order.taker_pays_funded) : undefined
|
||||
const takerGetsFunded = data.taker_gets_funded ?
|
||||
parseAmount(data.taker_gets_funded) : undefined
|
||||
const takerPaysFunded = data.taker_pays_funded ?
|
||||
parseAmount(data.taker_pays_funded) : undefined
|
||||
const available = removeUndefined({
|
||||
fundedAmount: takerGetsFunded,
|
||||
priceOfFundedAmount: takerPaysFunded
|
||||
})
|
||||
const state = _.isEmpty(available) ? undefined : available
|
||||
return removeUndefined({specification, properties, state})
|
||||
return removeUndefined({specification, properties, state, data})
|
||||
}
|
||||
|
||||
export default parseOrderbookOrder
|
||||
|
||||
@@ -1,35 +1,8 @@
|
||||
import {parseTimestamp} from './utils'
|
||||
import {removeUndefined, dropsToXrp} from '../../common'
|
||||
import {PayChannelLedgerEntry} from '../../common/types/objects'
|
||||
|
||||
|
||||
export type PaymentChannel = {
|
||||
Sequence: number,
|
||||
Account: string,
|
||||
Amount: string,
|
||||
Balance: string,
|
||||
PublicKey: string,
|
||||
Destination: string,
|
||||
SettleDelay: number,
|
||||
Expiration?: number,
|
||||
CancelAfter?: number,
|
||||
SourceTag?: number,
|
||||
DestinationTag?: number,
|
||||
OwnerNode: string,
|
||||
LedgerEntryType: string,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
index: string
|
||||
}
|
||||
|
||||
export type LedgerEntryResponse = {
|
||||
node: PaymentChannel,
|
||||
ledger_current_index?: number,
|
||||
ledger_hash?: string,
|
||||
ledger_index: number,
|
||||
validated: boolean
|
||||
}
|
||||
|
||||
export type PaymentChannelResponse = {
|
||||
export type FormattedPaymentChannel = {
|
||||
account: string,
|
||||
balance: string,
|
||||
publicKey: string,
|
||||
@@ -43,7 +16,9 @@ export type PaymentChannelResponse = {
|
||||
previousAffectingTransactionLedgerVersion: number
|
||||
}
|
||||
|
||||
function parsePaymentChannel(data: PaymentChannel): PaymentChannelResponse {
|
||||
export function parsePaymentChannel(
|
||||
data: PayChannelLedgerEntry
|
||||
): FormattedPaymentChannel {
|
||||
return removeUndefined({
|
||||
account: data.Account,
|
||||
amount: dropsToXrp(data.Amount),
|
||||
@@ -59,5 +34,3 @@ function parsePaymentChannel(data: PaymentChannel): PaymentChannelResponse {
|
||||
previousAffectingTransactionLedgerVersion: data.PreviousTxnLgrSeq
|
||||
})
|
||||
}
|
||||
|
||||
export default parsePaymentChannel
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
import parsePaymentChannel, {
|
||||
LedgerEntryResponse, PaymentChannel
|
||||
import {
|
||||
parsePaymentChannel,
|
||||
FormattedPaymentChannel
|
||||
} from './parse/payment-channel'
|
||||
import {validate, errors} from '../common'
|
||||
import {RippleAPI} from '../api'
|
||||
import {LedgerEntryResponse} from '../common/types/commands'
|
||||
const NotFoundError = errors.NotFoundError
|
||||
|
||||
function formatResponse(response: LedgerEntryResponse) {
|
||||
if (response.node !== undefined &&
|
||||
response.node.LedgerEntryType === 'PayChannel') {
|
||||
return parsePaymentChannel(response.node)
|
||||
} else {
|
||||
function formatResponse(
|
||||
response: LedgerEntryResponse
|
||||
): FormattedPaymentChannel {
|
||||
if (response.node === undefined ||
|
||||
response.node.LedgerEntryType !== 'PayChannel') {
|
||||
throw new NotFoundError('Payment channel ledger entry not found')
|
||||
}
|
||||
return parsePaymentChannel(response.node)
|
||||
}
|
||||
|
||||
function getPaymentChannel(id: string): Promise<PaymentChannel> {
|
||||
async function getPaymentChannel(
|
||||
this: RippleAPI, id: string
|
||||
): Promise<FormattedPaymentChannel> {
|
||||
// 1. Validate
|
||||
validate.getPaymentChannel({id})
|
||||
|
||||
const request = {
|
||||
command: 'ledger_entry',
|
||||
// 2. Make Request
|
||||
const response = await this.request('ledger_entry', {
|
||||
index: id,
|
||||
binary: false,
|
||||
ledger_index: 'validated'
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(formatResponse)
|
||||
})
|
||||
// 3. Return Formatted Response
|
||||
return formatResponse(response)
|
||||
}
|
||||
|
||||
export default getPaymentChannel
|
||||
|
||||
@@ -1,31 +1,15 @@
|
||||
import * as _ from 'lodash'
|
||||
import parseFields from './parse/fields'
|
||||
import {validate, constants} from '../common'
|
||||
import {FormattedSettings} from '../common/types/objects'
|
||||
import {AccountInfoResponse} from '../common/types/commands'
|
||||
import {RippleAPI} from '../api'
|
||||
const AccountFlags = constants.AccountFlags
|
||||
|
||||
export type SettingsOptions = {
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type GetSettings = {
|
||||
passwordSpent?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
requireAuthorization?: boolean,
|
||||
depositAuthorization?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
noFreeze?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
defaultRipple?: boolean,
|
||||
emailHash?: string|null,
|
||||
messageKey?: string,
|
||||
domain?: string,
|
||||
transferRate?: number|null,
|
||||
regularKey?: string
|
||||
}
|
||||
|
||||
|
||||
function parseFlags(value) {
|
||||
const settings = {}
|
||||
for (const flagName in AccountFlags) {
|
||||
@@ -36,25 +20,26 @@ function parseFlags(value) {
|
||||
return settings
|
||||
}
|
||||
|
||||
function formatSettings(response) {
|
||||
function formatSettings(response: AccountInfoResponse) {
|
||||
const data = response.account_data
|
||||
const parsedFlags = parseFlags(data.Flags)
|
||||
const parsedFields = parseFields(data)
|
||||
return _.assign({}, parsedFlags, parsedFields)
|
||||
}
|
||||
|
||||
function getSettings(address: string, options: SettingsOptions = {}
|
||||
): Promise<GetSettings> {
|
||||
async function getSettings(
|
||||
this: RippleAPI, address: string, options: SettingsOptions = {}
|
||||
): Promise<FormattedSettings> {
|
||||
// 1. Validate
|
||||
validate.getSettings({address, options})
|
||||
|
||||
const request = {
|
||||
command: 'account_info',
|
||||
// 2. Make Request
|
||||
const response = await this.request('account_info', {
|
||||
account: address,
|
||||
ledger_index: options.ledgerVersion || 'validated',
|
||||
signer_lists: true
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(formatSettings)
|
||||
})
|
||||
// 3. Return Formatted Response
|
||||
return formatSettings(response)
|
||||
}
|
||||
|
||||
export default getSettings
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
|
||||
import {Amount, Memo} from '../common/types/objects'
|
||||
|
||||
export type Outcome = {
|
||||
result: string,
|
||||
ledgerVersion: number,
|
||||
indexInLedger: number,
|
||||
fee: string,
|
||||
balanceChanges: {
|
||||
[key: string]: [{
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
}]
|
||||
},
|
||||
orderbookChanges: Object,
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
export type Adjustment = {
|
||||
address: string,
|
||||
amount: {
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
},
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type Trustline = {
|
||||
currency: string,
|
||||
counterparty: string,
|
||||
limit: string,
|
||||
qualityIn?: number,
|
||||
qualityOut?: number,
|
||||
ripplingDisabled?: boolean,
|
||||
authorized?: boolean,
|
||||
frozen?: boolean
|
||||
}
|
||||
|
||||
export type Settings = {
|
||||
passwordSpent?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
requireAuthorization?: boolean,
|
||||
depositAuthorization?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
noFreeze?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
defaultRipple?: boolean,
|
||||
emailHash?: string,
|
||||
messageKey?: string,
|
||||
domain?: string,
|
||||
transferRate?: number,
|
||||
regularKey?: string
|
||||
}
|
||||
|
||||
export type OrderCancellation = {
|
||||
orderSequence: number
|
||||
}
|
||||
|
||||
export type Payment = {
|
||||
source: Adjustment,
|
||||
destination: Adjustment,
|
||||
paths?: string,
|
||||
memos?: Array<Memo>,
|
||||
invoiceID?: string,
|
||||
allowPartialPayment?: boolean,
|
||||
noDirectRipple?: boolean,
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
export type PaymentTransaction = {
|
||||
type: string,
|
||||
specification: Payment,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
passive?: boolean,
|
||||
expirationTime?: string,
|
||||
orderToReplace?: number,
|
||||
memos?: Memo[]
|
||||
}
|
||||
|
||||
export type OrderTransaction = {
|
||||
type: string,
|
||||
specification: Order,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type OrderCancellationTransaction = {
|
||||
type: string,
|
||||
specification: OrderCancellation,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type TrustlineTransaction = {
|
||||
type: string,
|
||||
specification: Trustline,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type SettingsTransaction = {
|
||||
type: string,
|
||||
specification: Settings,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type TransactionOptions = {
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
|
||||
export type TransactionType = PaymentTransaction | OrderTransaction |
|
||||
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction
|
||||
|
||||
export type TransactionResponse = TransactionType & {
|
||||
hash: string,
|
||||
ledger_index: number,
|
||||
meta: any,
|
||||
validated?: boolean
|
||||
}
|
||||
|
||||
@@ -3,12 +3,22 @@ import * as utils from './utils'
|
||||
import parseTransaction from './parse/transaction'
|
||||
import {validate, errors} from '../common'
|
||||
import {Connection} from '../common'
|
||||
import {
|
||||
TransactionType, TransactionResponse, TransactionOptions
|
||||
} from './transaction-types'
|
||||
import {FormattedTransactionType} from '../transaction/types'
|
||||
|
||||
export type TransactionOptions = {
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number
|
||||
}
|
||||
type TransactionResponse = FormattedTransactionType & {
|
||||
hash: string,
|
||||
ledger_index: number,
|
||||
meta: any,
|
||||
validated?: boolean
|
||||
}
|
||||
|
||||
|
||||
function attachTransactionDate(connection: Connection, tx: any
|
||||
): Promise<TransactionType> {
|
||||
): Promise<FormattedTransactionType> {
|
||||
if (tx.date) {
|
||||
return Promise.resolve(tx)
|
||||
}
|
||||
@@ -71,7 +81,7 @@ function convertError(connection: Connection, options: TransactionOptions,
|
||||
}
|
||||
|
||||
function formatResponse(options: TransactionOptions, tx: TransactionResponse
|
||||
): TransactionType {
|
||||
): FormattedTransactionType {
|
||||
if (tx.validated !== true || !isTransactionInRange(tx, options)) {
|
||||
throw new errors.NotFoundError('Transaction not found')
|
||||
}
|
||||
@@ -79,7 +89,7 @@ function formatResponse(options: TransactionOptions, tx: TransactionResponse
|
||||
}
|
||||
|
||||
function getTransaction(id: string, options: TransactionOptions = {}
|
||||
): Promise<TransactionType> {
|
||||
): Promise<FormattedTransactionType> {
|
||||
validate.getTransaction({id, options})
|
||||
|
||||
const request = {
|
||||
|
||||
@@ -4,9 +4,8 @@ const {computeTransactionHash} = require('ripple-hashes')
|
||||
import * as utils from './utils'
|
||||
import parseTransaction from './parse/transaction'
|
||||
import getTransaction from './transaction'
|
||||
import {validate, errors} from '../common'
|
||||
import {Connection} from '../common'
|
||||
import {TransactionType} from './transaction-types'
|
||||
import {validate, errors, Connection} from '../common'
|
||||
import {FormattedTransactionType} from '../transaction/types'
|
||||
|
||||
|
||||
export type TransactionsOptions = {
|
||||
@@ -20,10 +19,10 @@ export type TransactionsOptions = {
|
||||
counterparty?: string,
|
||||
types?: Array<string>,
|
||||
binary?: boolean,
|
||||
startTx?: TransactionType
|
||||
startTx?: FormattedTransactionType
|
||||
}
|
||||
|
||||
export type GetTransactionsResponse = Array<TransactionType>
|
||||
export type GetTransactionsResponse = Array<FormattedTransactionType>
|
||||
|
||||
function parseBinaryTransaction(transaction) {
|
||||
const tx = binary.decode(transaction.tx_blob)
|
||||
@@ -43,7 +42,7 @@ function parseAccountTxTransaction(tx) {
|
||||
{meta: _tx.meta, validated: _tx.validated}))
|
||||
}
|
||||
|
||||
function counterpartyFilter(filters, tx: TransactionType) {
|
||||
function counterpartyFilter(filters, tx: FormattedTransactionType) {
|
||||
if (tx.address === filters.counterparty) {
|
||||
return true
|
||||
}
|
||||
@@ -57,7 +56,7 @@ function counterpartyFilter(filters, tx: TransactionType) {
|
||||
}
|
||||
|
||||
function transactionFilter(address: string, filters: TransactionsOptions,
|
||||
tx: TransactionType
|
||||
tx: FormattedTransactionType
|
||||
) {
|
||||
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
||||
return false
|
||||
@@ -77,7 +76,9 @@ function transactionFilter(address: string, filters: TransactionsOptions,
|
||||
return true
|
||||
}
|
||||
|
||||
function orderFilter(options: TransactionsOptions, tx: TransactionType) {
|
||||
function orderFilter(
|
||||
options: TransactionsOptions, tx: FormattedTransactionType
|
||||
) {
|
||||
return !options.startTx || (options.earliestFirst ?
|
||||
utils.compareTransactions(tx, options.startTx) > 0 :
|
||||
utils.compareTransactions(tx, options.startTx) < 0)
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
import {Amount} from '../common/types/objects'
|
||||
|
||||
export type OrderSpecification = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
// If enabled, the offer will not consume offers that exactly match it, and
|
||||
// instead becomes an Offer node in the ledger. It will still consume offers
|
||||
// that cross it.
|
||||
passive?: boolean
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
specification: OrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
makerExchangeRate: string
|
||||
}
|
||||
}
|
||||
|
||||
export type GetLedger = {
|
||||
// TODO: properties in type don't match response object. Fix!
|
||||
// accepted: boolean,
|
||||
// closed: boolean,
|
||||
stateHash: string,
|
||||
closeTime: string,
|
||||
closeTimeResolution: number,
|
||||
closeFlags: number,
|
||||
ledgerHash: string,
|
||||
ledgerVersion: number,
|
||||
parentLedgerHash: string,
|
||||
parentCloseTime: string,
|
||||
totalDrops: string,
|
||||
transactionHash: string,
|
||||
transactions?: Array<Object>,
|
||||
rawTransactions?: string,
|
||||
transactionHashes?: Array<string>,
|
||||
rawState?: string,
|
||||
stateHashes?: Array<string>
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import * as _ from 'lodash'
|
||||
import * as assert from 'assert'
|
||||
import * as common from '../common'
|
||||
import {Connection} from '../common'
|
||||
import {TransactionType} from './transaction-types'
|
||||
import {FormattedTransactionType} from '../transaction/types'
|
||||
import {Issue} from '../common/types/objects'
|
||||
|
||||
export type RecursiveData = {
|
||||
@@ -78,7 +78,8 @@ function signum(num) {
|
||||
* them based on TransactionIndex
|
||||
* See: https://ripple.com/build/transactions/
|
||||
*/
|
||||
function compareTransactions(first: TransactionType, second: TransactionType
|
||||
function compareTransactions(
|
||||
first: FormattedTransactionType, second: FormattedTransactionType
|
||||
): number {
|
||||
if (!first.outcome || !second.outcome) {
|
||||
return 0
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as common from '../common'
|
||||
import {GetServerInfoResponse} from '../common/serverinfo'
|
||||
|
||||
function isConnected(): boolean {
|
||||
return this.connection.isConnected()
|
||||
@@ -17,15 +16,6 @@ function disconnect(): Promise<void> {
|
||||
return this.connection.disconnect()
|
||||
}
|
||||
|
||||
function getServerInfo(): Promise<GetServerInfoResponse> {
|
||||
return common.serverInfo.getServerInfo(this.connection)
|
||||
}
|
||||
|
||||
function getFee(): Promise<string> {
|
||||
const cushion = this._feeCushion || 1.2
|
||||
return common.serverInfo.getFee(this.connection, cushion)
|
||||
}
|
||||
|
||||
function formatLedgerClose(ledgerClose: any): Object {
|
||||
return {
|
||||
baseFeeXRP: common.dropsToXrp(ledgerClose.fee_base),
|
||||
@@ -43,8 +33,6 @@ export {
|
||||
connect,
|
||||
disconnect,
|
||||
isConnected,
|
||||
getServerInfo,
|
||||
getFee,
|
||||
getLedgerVersion,
|
||||
formatLedgerClose
|
||||
}
|
||||
|
||||
@@ -2,16 +2,18 @@ import * as _ from 'lodash'
|
||||
import * as utils from './utils'
|
||||
const offerFlags = utils.common.txFlags.OfferCreate
|
||||
import {validate, iso8601ToRippleTime} from '../common'
|
||||
import {Instructions, Prepare} from './types'
|
||||
import {Order} from '../ledger/transaction-types'
|
||||
import {Instructions, Prepare, OfferCreateTransaction} from './types'
|
||||
import {FormattedOrderSpecification} from '../common/types/objects/index'
|
||||
|
||||
function createOrderTransaction(account: string, order: Order): Object {
|
||||
function createOrderTransaction(
|
||||
account: string, order: FormattedOrderSpecification
|
||||
): OfferCreateTransaction {
|
||||
const takerPays = utils.common.toRippledAmount(order.direction === 'buy' ?
|
||||
order.quantity : order.totalPrice)
|
||||
const takerGets = utils.common.toRippledAmount(order.direction === 'buy' ?
|
||||
order.totalPrice : order.quantity)
|
||||
|
||||
const txJSON: any = {
|
||||
const txJSON: Partial<OfferCreateTransaction> = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: account,
|
||||
TakerGets: takerGets,
|
||||
@@ -39,10 +41,10 @@ function createOrderTransaction(account: string, order: Order): Object {
|
||||
if (order.memos !== undefined) {
|
||||
txJSON.Memos = _.map(order.memos, utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
return txJSON as OfferCreateTransaction
|
||||
}
|
||||
|
||||
function prepareOrder(address: string, order: Order,
|
||||
function prepareOrder(address: string, order: FormattedOrderSpecification,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
validate.prepareOrder({address, order, instructions})
|
||||
|
||||
@@ -9,9 +9,9 @@ import {Amount, Adjustment, MaxAdjustment,
|
||||
MinAdjustment, Memo} from '../common/types/objects'
|
||||
|
||||
|
||||
export type Payment = {
|
||||
source: Adjustment & MaxAdjustment,
|
||||
destination: Adjustment & MinAdjustment,
|
||||
export interface Payment {
|
||||
source: Adjustment | MaxAdjustment,
|
||||
destination: Adjustment | MinAdjustment,
|
||||
paths?: string,
|
||||
memos?: Array<Memo>,
|
||||
// A 256-bit hash that can be used to identify a particular payment
|
||||
@@ -30,11 +30,22 @@ import {Amount, Adjustment, MaxAdjustment,
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
function isMaxAdjustment(
|
||||
source: Adjustment | MaxAdjustment): source is MaxAdjustment {
|
||||
return (source as MaxAdjustment).maxAmount !== undefined
|
||||
}
|
||||
|
||||
function isMinAdjustment(
|
||||
destination: Adjustment | MinAdjustment): destination is MinAdjustment {
|
||||
return (destination as MinAdjustment).minAmount !== undefined
|
||||
}
|
||||
|
||||
function isXRPToXRPPayment(payment: Payment): boolean {
|
||||
const sourceCurrency = _.get(payment, 'source.maxAmount.currency',
|
||||
_.get(payment, 'source.amount.currency'))
|
||||
const destinationCurrency = _.get(payment, 'destination.amount.currency',
|
||||
_.get(payment, 'destination.minAmount.currency'))
|
||||
const {source, destination} = payment
|
||||
const sourceCurrency = isMaxAdjustment(source)
|
||||
? source.maxAmount.currency : source.amount.currency
|
||||
const destinationCurrency = isMinAdjustment(destination)
|
||||
? destination.minAmount.currency : destination.amount.currency
|
||||
return sourceCurrency === 'XRP' && destinationCurrency === 'XRP'
|
||||
}
|
||||
|
||||
@@ -74,21 +85,29 @@ function createPaymentTransaction(address: string, paymentArgument: Payment
|
||||
throw new ValidationError('address must match payment.source.address')
|
||||
}
|
||||
|
||||
if ((payment.source.maxAmount && payment.destination.minAmount) ||
|
||||
(payment.source.amount && payment.destination.amount)) {
|
||||
if (
|
||||
(isMaxAdjustment(payment.source) && isMinAdjustment(payment.destination))
|
||||
||
|
||||
(!isMaxAdjustment(payment.source) && !isMinAdjustment(payment.destination))
|
||||
) {
|
||||
throw new ValidationError('payment must specify either (source.maxAmount '
|
||||
+ 'and destination.amount) or (source.amount and destination.minAmount)')
|
||||
}
|
||||
|
||||
const destinationAmount = isMinAdjustment(payment.destination)
|
||||
? payment.destination.minAmount : payment.destination.amount
|
||||
const sourceAmount = isMaxAdjustment(payment.source)
|
||||
? payment.source.maxAmount : payment.source.amount
|
||||
|
||||
// when using destination.minAmount, rippled still requires that we set
|
||||
// a destination amount in addition to DeliverMin. the destination amount
|
||||
// is interpreted as the maximum amount to send. we want to be sure to
|
||||
// send the whole source amount, so we set the destination amount to the
|
||||
// maximum possible amount. otherwise it's possible that the destination
|
||||
// cap could be hit before the source cap.
|
||||
const amount = payment.destination.minAmount && !isXRPToXRPPayment(payment) ?
|
||||
createMaximalAmount(payment.destination.minAmount) :
|
||||
(payment.destination.amount || payment.destination.minAmount)
|
||||
const amount =
|
||||
(isMinAdjustment(payment.destination) && !isXRPToXRPPayment(payment))
|
||||
? createMaximalAmount(destinationAmount) : destinationAmount
|
||||
|
||||
const txJSON: any = {
|
||||
TransactionType: 'Payment',
|
||||
@@ -121,16 +140,14 @@ function createPaymentTransaction(address: string, paymentArgument: Payment
|
||||
// temREDUNDANT_SEND_MAX removed in:
|
||||
// https://github.com/ripple/rippled/commit/
|
||||
// c522ffa6db2648f1d8a987843e7feabf1a0b7de8/
|
||||
if (payment.allowPartialPayment === true
|
||||
|| payment.destination.minAmount !== undefined) {
|
||||
if (payment.allowPartialPayment || isMinAdjustment(payment.destination)) {
|
||||
txJSON.Flags |= paymentFlags.PartialPayment
|
||||
}
|
||||
|
||||
txJSON.SendMax = toRippledAmount(
|
||||
payment.source.maxAmount || payment.source.amount)
|
||||
txJSON.SendMax = toRippledAmount(sourceAmount)
|
||||
|
||||
if (payment.destination.minAmount !== undefined) {
|
||||
txJSON.DeliverMin = toRippledAmount(payment.destination.minAmount)
|
||||
if (isMinAdjustment(payment.destination)) {
|
||||
txJSON.DeliverMin = toRippledAmount(destinationAmount)
|
||||
}
|
||||
|
||||
if (payment.paths !== undefined) {
|
||||
|
||||
@@ -6,36 +6,12 @@ const validate = utils.common.validate
|
||||
const AccountFlagIndices = utils.common.constants.AccountFlagIndices
|
||||
const AccountFields = utils.common.constants.AccountFields
|
||||
import {Instructions, Prepare} from './types'
|
||||
import {Memo} from '../common/types/objects'
|
||||
|
||||
export type WeightedSigner = {address: string, weight: number}
|
||||
export type SettingsSigners = {
|
||||
threshold?: number,
|
||||
weights: WeightedSigner[]
|
||||
}
|
||||
export type Settings = {
|
||||
passwordSpent?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
requireAuthorization?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
noFreeze?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
defaultRipple?: boolean,
|
||||
emailHash?: string,
|
||||
messageKey?: string,
|
||||
domain?: string,
|
||||
transferRate?: number,
|
||||
regularKey?: string,
|
||||
signers?: SettingsSigners,
|
||||
memos?: Memo[]
|
||||
}
|
||||
import {FormattedSettings, WeightedSigner} from '../common/types/objects'
|
||||
|
||||
// Emptry string passed to setting will clear it
|
||||
const CLEAR_SETTING = null
|
||||
|
||||
function setTransactionFlags(txJSON: any, values: Settings) {
|
||||
function setTransactionFlags(txJSON: any, values: FormattedSettings) {
|
||||
const keys = Object.keys(values)
|
||||
assert(keys.length === 1, 'ERROR: can only set one setting per transaction')
|
||||
const flagName = keys[0]
|
||||
@@ -50,7 +26,7 @@ function setTransactionFlags(txJSON: any, values: Settings) {
|
||||
}
|
||||
}
|
||||
|
||||
function setTransactionFields(txJSON: Object, input: Settings) {
|
||||
function setTransactionFields(txJSON: Object, input: FormattedSettings) {
|
||||
const fieldSchema = AccountFields
|
||||
for (const fieldName in fieldSchema) {
|
||||
const field = fieldSchema[fieldName]
|
||||
@@ -101,7 +77,7 @@ function formatSignerEntry(signer: WeightedSigner): Object {
|
||||
}
|
||||
|
||||
function createSettingsTransactionWithoutMemos(
|
||||
account: string, settings: Settings
|
||||
account: string, settings: FormattedSettings
|
||||
): any {
|
||||
if (settings.regularKey !== undefined) {
|
||||
const removeRegularKey = {
|
||||
@@ -137,7 +113,7 @@ function createSettingsTransactionWithoutMemos(
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function createSettingsTransaction(account: string, settings: Settings
|
||||
function createSettingsTransaction(account: string, settings: FormattedSettings
|
||||
): Object {
|
||||
const txJSON = createSettingsTransactionWithoutMemos(account, settings)
|
||||
if (settings.memos !== undefined) {
|
||||
@@ -146,7 +122,7 @@ function createSettingsTransaction(account: string, settings: Settings
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function prepareSettings(address: string, settings: Settings,
|
||||
function prepareSettings(address: string, settings: FormattedSettings,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
validate.prepareSettings({address, settings, instructions})
|
||||
|
||||
@@ -2,27 +2,45 @@ import * as utils from './utils'
|
||||
import keypairs = require('ripple-keypairs')
|
||||
import binary = require('ripple-binary-codec')
|
||||
import {computeBinaryTransactionHash} from 'ripple-hashes'
|
||||
import {SignOptions, KeyPair} from './types'
|
||||
import {BigNumber} from 'bignumber.js'
|
||||
import {xrpToDrops} from '../common'
|
||||
import {RippleAPI} from '../api'
|
||||
const validate = utils.common.validate
|
||||
|
||||
function computeSignature(tx: Object, privateKey: string, signAs?: string) {
|
||||
const signingData = signAs ?
|
||||
binary.encodeForMultisigning(tx, signAs) : binary.encodeForSigning(tx)
|
||||
const signingData = signAs
|
||||
? binary.encodeForMultisigning(tx, signAs)
|
||||
: binary.encodeForSigning(tx)
|
||||
return keypairs.sign(signingData, privateKey)
|
||||
}
|
||||
|
||||
function sign(txJSON: string, secret: string, options: {signAs?: string} = {}
|
||||
): {signedTransaction: string; id: string} {
|
||||
validate.sign({txJSON, secret})
|
||||
// we can't validate that the secret matches the account because
|
||||
// the secret could correspond to the regular key
|
||||
function signWithKeypair(
|
||||
api: RippleAPI,
|
||||
txJSON: string,
|
||||
keypair: KeyPair,
|
||||
options: SignOptions = {
|
||||
signAs: ''
|
||||
}
|
||||
): { signedTransaction: string; id: string } {
|
||||
validate.sign({txJSON, keypair})
|
||||
|
||||
const tx = JSON.parse(txJSON)
|
||||
if (tx.TxnSignature || tx.Signers) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
'txJSON must not contain "TxnSignature" or "Signers" properties')
|
||||
'txJSON must not contain "TxnSignature" or "Signers" properties'
|
||||
)
|
||||
}
|
||||
|
||||
const fee = new BigNumber(tx.Fee)
|
||||
const maxFeeDrops = xrpToDrops(api._maxFeeXRP)
|
||||
if (fee.greaterThan(maxFeeDrops)) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
`"Fee" should not exceed "${maxFeeDrops}". ` +
|
||||
'To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor.'
|
||||
)
|
||||
}
|
||||
|
||||
const keypair = keypairs.deriveKeypair(secret)
|
||||
tx.SigningPubKey = options.signAs ? '' : keypair.publicKey
|
||||
|
||||
if (options.signAs) {
|
||||
@@ -43,4 +61,30 @@ function sign(txJSON: string, secret: string, options: {signAs?: string} = {}
|
||||
}
|
||||
}
|
||||
|
||||
function sign(
|
||||
this: RippleAPI,
|
||||
txJSON: string,
|
||||
secret?: any,
|
||||
options?: SignOptions,
|
||||
keypair?: KeyPair
|
||||
): { signedTransaction: string; id: string } {
|
||||
if (typeof secret === 'string') {
|
||||
// we can't validate that the secret matches the account because
|
||||
// the secret could correspond to the regular key
|
||||
validate.sign({txJSON, secret})
|
||||
return signWithKeypair(
|
||||
this,
|
||||
txJSON,
|
||||
keypairs.deriveKeypair(secret),
|
||||
options
|
||||
)
|
||||
} else {
|
||||
return signWithKeypair(
|
||||
this,
|
||||
txJSON,
|
||||
keypair ? keypair : secret,
|
||||
options)
|
||||
}
|
||||
}
|
||||
|
||||
export default sign
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
|
||||
import {
|
||||
FormattedOrderSpecification,
|
||||
FormattedTrustline,
|
||||
Adjustment,
|
||||
RippledAmount,
|
||||
Memo,
|
||||
FormattedSettings
|
||||
} from '../common/types/objects'
|
||||
import {ApiMemo} from './utils'
|
||||
|
||||
export type Instructions = {
|
||||
sequence?: number,
|
||||
fee?: string,
|
||||
// @deprecated
|
||||
maxFee?: string,
|
||||
maxLedgerVersion?: number,
|
||||
maxLedgerVersionOffset?: number,
|
||||
@@ -25,3 +36,109 @@ export type Submit = {
|
||||
txBlob?: string,
|
||||
txJson?: Object
|
||||
}
|
||||
|
||||
export interface OfferCreateTransaction {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: string,
|
||||
Fee: string,
|
||||
Flags: number,
|
||||
LastLedgerSequence: number,
|
||||
Sequence: number,
|
||||
TakerGets: RippledAmount,
|
||||
TakerPays: RippledAmount,
|
||||
Expiration?: number,
|
||||
OfferSequence?: number,
|
||||
Memos: {Memo: ApiMemo}[]
|
||||
}
|
||||
|
||||
export type KeyPair = {
|
||||
publicKey: string,
|
||||
privateKey: string
|
||||
}
|
||||
|
||||
export type SignOptions = {
|
||||
signAs: string
|
||||
}
|
||||
|
||||
export type Outcome = {
|
||||
result: string,
|
||||
ledgerVersion: number,
|
||||
indexInLedger: number,
|
||||
fee: string,
|
||||
balanceChanges: {
|
||||
[key: string]: [{
|
||||
currency: string,
|
||||
counterparty?: string,
|
||||
value: string
|
||||
}]
|
||||
},
|
||||
orderbookChanges: Object,
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
export type FormattedOrderCancellation = {
|
||||
orderSequence: number
|
||||
}
|
||||
|
||||
export type FormattedPayment = {
|
||||
source: Adjustment,
|
||||
destination: Adjustment,
|
||||
paths?: string,
|
||||
memos?: Array<Memo>,
|
||||
invoiceID?: string,
|
||||
allowPartialPayment?: boolean,
|
||||
noDirectRipple?: boolean,
|
||||
limitQuality?: boolean
|
||||
}
|
||||
|
||||
export type FormattedPaymentTransaction = {
|
||||
type: string,
|
||||
specification: FormattedPayment,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type FormattedOrderTransaction = {
|
||||
type: string,
|
||||
specification: FormattedOrderSpecification,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type FormattedOrderCancellationTransaction = {
|
||||
type: string,
|
||||
specification: FormattedOrderCancellation,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type FormattedTrustlineTransaction = {
|
||||
type: string,
|
||||
specification: FormattedTrustline,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type FormattedSettingsTransaction = {
|
||||
type: string,
|
||||
specification: FormattedSettings,
|
||||
outcome: Outcome,
|
||||
id: string,
|
||||
address: string,
|
||||
sequence: number
|
||||
}
|
||||
|
||||
export type FormattedTransactionType =
|
||||
FormattedPaymentTransaction |
|
||||
FormattedOrderTransaction |
|
||||
FormattedOrderCancellationTransaction |
|
||||
FormattedTrustlineTransaction |
|
||||
FormattedSettingsTransaction
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Memo} from '../common/types/objects'
|
||||
const txFlags = common.txFlags
|
||||
import {Instructions, Prepare} from './types'
|
||||
import {RippleAPI} from '../api'
|
||||
import {ValidationError} from '../common/errors'
|
||||
|
||||
export type ApiMemo = {
|
||||
MemoData?: string,
|
||||
@@ -63,11 +64,18 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
|
||||
const multiplier = instructions.signersCount === undefined ? 1 :
|
||||
instructions.signersCount + 1
|
||||
if (instructions.fee !== undefined) {
|
||||
const fee = new BigNumber(instructions.fee)
|
||||
if (fee.greaterThan(api._maxFeeXRP)) {
|
||||
const errorMessage = `Fee of ${fee.toString(10)} XRP exceeds ` +
|
||||
`max of ${api._maxFeeXRP} XRP. To use this fee, increase ` +
|
||||
'`maxFeeXRP` in the RippleAPI constructor.'
|
||||
throw new ValidationError(errorMessage)
|
||||
}
|
||||
txJSON.Fee = scaleValue(common.xrpToDrops(instructions.fee), multiplier)
|
||||
return Promise.resolve(txJSON)
|
||||
}
|
||||
const cushion = api._feeCushion
|
||||
return common.serverInfo.getFee(api.connection, cushion).then(fee => {
|
||||
return api.getFee(cushion).then(fee => {
|
||||
return api.connection.getFeeRef().then(feeRef => {
|
||||
const extraFee =
|
||||
(txJSON.TransactionType !== 'EscrowFinish' ||
|
||||
@@ -75,13 +83,12 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
|
||||
(cushion * feeRef * (32 + Math.floor(
|
||||
new Buffer(txJSON.Fulfillment, 'hex').length / 16)))
|
||||
const feeDrops = common.xrpToDrops(fee)
|
||||
if (instructions.maxFee !== undefined) {
|
||||
const maxFeeDrops = common.xrpToDrops(instructions.maxFee)
|
||||
const normalFee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
txJSON.Fee = BigNumber.min(normalFee, maxFeeDrops).toString()
|
||||
} else {
|
||||
txJSON.Fee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
}
|
||||
const maxFeeXRP = instructions.maxFee ?
|
||||
BigNumber.min(api._maxFeeXRP, instructions.maxFee) : api._maxFeeXRP
|
||||
const maxFeeDrops = common.xrpToDrops(maxFeeXRP)
|
||||
const normalFee = scaleValue(feeDrops, multiplier, extraFee)
|
||||
txJSON.Fee = BigNumber.min(normalFee, maxFeeDrops).toString(10)
|
||||
|
||||
return txJSON
|
||||
})
|
||||
})
|
||||
|
||||
522
test/api-test.js
522
test/api-test.js
@@ -15,6 +15,7 @@ const utils = RippleAPI._PRIVATE.ledgerUtils;
|
||||
const ledgerClosed = require('./fixtures/rippled/ledger-close-newer');
|
||||
const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
|
||||
const binary = require('ripple-binary-codec');
|
||||
const BigNumber = require('bignumber.js')
|
||||
assert.options.strict = true;
|
||||
|
||||
// how long before each test case times out
|
||||
@@ -51,6 +52,273 @@ describe('RippleAPI', function () {
|
||||
assert.strictEqual(error.inspect(), '[RippleError(mess, { data: 1 })]');
|
||||
});
|
||||
|
||||
describe('xrpToDrops', function () {
|
||||
it('works with a typical amount', function () {
|
||||
const drops = this.api.xrpToDrops('2')
|
||||
assert.strictEqual(drops, '2000000', '2 XRP equals 2 million drops')
|
||||
})
|
||||
|
||||
it('works with fractions', function () {
|
||||
let drops = this.api.xrpToDrops('3.456789')
|
||||
assert.strictEqual(drops, '3456789', '3.456789 XRP equals 3,456,789 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('3.400000')
|
||||
assert.strictEqual(drops, '3400000', '3.400000 XRP equals 3,400,000 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('0.000001')
|
||||
assert.strictEqual(drops, '1', '0.000001 XRP equals 1 drop')
|
||||
|
||||
drops = this.api.xrpToDrops('0.0000010')
|
||||
assert.strictEqual(drops, '1', '0.0000010 XRP equals 1 drop')
|
||||
})
|
||||
|
||||
it('works with zero', function () {
|
||||
let drops = this.api.xrpToDrops('0')
|
||||
assert.strictEqual(drops, '0', '0 XRP equals 0 drops')
|
||||
|
||||
// negative zero is equivalent to zero
|
||||
drops = this.api.xrpToDrops('-0')
|
||||
assert.strictEqual(drops, '0', '-0 XRP equals 0 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('0.000000')
|
||||
assert.strictEqual(drops, '0', '0.000000 XRP equals 0 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('0.0000000')
|
||||
assert.strictEqual(drops, '0', '0.0000000 XRP equals 0 drops')
|
||||
})
|
||||
|
||||
it('works with a negative value', function () {
|
||||
const drops = this.api.xrpToDrops('-2')
|
||||
assert.strictEqual(drops, '-2000000', '-2 XRP equals -2 million drops')
|
||||
})
|
||||
|
||||
it('works with a value ending with a decimal point', function () {
|
||||
let drops = this.api.xrpToDrops('2.')
|
||||
assert.strictEqual(drops, '2000000', '2. XRP equals 2000000 drops')
|
||||
|
||||
drops = this.api.xrpToDrops('-2.')
|
||||
assert.strictEqual(drops, '-2000000', '-2. XRP equals -2000000 drops')
|
||||
})
|
||||
|
||||
it('works with BigNumber objects', function () {
|
||||
let drops = this.api.xrpToDrops(new BigNumber(2))
|
||||
assert.strictEqual(drops, '2000000', '(BigNumber) 2 XRP equals 2 million drops')
|
||||
|
||||
drops = this.api.xrpToDrops(new BigNumber(-2))
|
||||
assert.strictEqual(drops, '-2000000', '(BigNumber) -2 XRP equals -2 million drops')
|
||||
})
|
||||
|
||||
it('works with a number', function() {
|
||||
// This is not recommended. Use strings or BigNumber objects to avoid precision errors.
|
||||
|
||||
let drops = this.api.xrpToDrops(2)
|
||||
assert.strictEqual(drops, '2000000', '(number) 2 XRP equals 2 million drops')
|
||||
|
||||
drops = this.api.xrpToDrops(-2)
|
||||
assert.strictEqual(drops, '-2000000', '(number) -2 XRP equals -2 million drops')
|
||||
})
|
||||
|
||||
it('throws with an amount with too many decimal places', function () {
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('1.1234567')
|
||||
}, /has too many decimal places/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('0.0000001')
|
||||
}, /has too many decimal places/)
|
||||
})
|
||||
|
||||
it('throws with an invalid value', function () {
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('FOO')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('1e-7')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('2,0')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('.')
|
||||
}, /xrpToDrops\: invalid value '\.', should be a BigNumber or string-encoded number\./)
|
||||
})
|
||||
|
||||
it('throws with an amount more than one decimal point', function () {
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('1.0.0')
|
||||
}, /xrpToDrops:\ invalid\ value\ '1\.0\.0'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.xrpToDrops('...')
|
||||
}, /xrpToDrops:\ invalid\ value\ '\.\.\.'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
})
|
||||
})
|
||||
|
||||
describe('dropsToXrp', function () {
|
||||
it('works with a typical amount', function () {
|
||||
const xrp = this.api.dropsToXrp('2000000')
|
||||
assert.strictEqual(xrp, '2', '2 million drops equals 2 XRP')
|
||||
})
|
||||
|
||||
it('works with fractions', function () {
|
||||
let xrp = this.api.dropsToXrp('3456789')
|
||||
assert.strictEqual(xrp, '3.456789', '3,456,789 drops equals 3.456789 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('3400000')
|
||||
assert.strictEqual(xrp, '3.4', '3,400,000 drops equals 3.4 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('1')
|
||||
assert.strictEqual(xrp, '0.000001', '1 drop equals 0.000001 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('1.0')
|
||||
assert.strictEqual(xrp, '0.000001', '1.0 drops equals 0.000001 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('1.00')
|
||||
assert.strictEqual(xrp, '0.000001', '1.00 drops equals 0.000001 XRP')
|
||||
})
|
||||
|
||||
it('works with zero', function () {
|
||||
let xrp = this.api.dropsToXrp('0')
|
||||
assert.strictEqual(xrp, '0', '0 drops equals 0 XRP')
|
||||
|
||||
// negative zero is equivalent to zero
|
||||
xrp = this.api.dropsToXrp('-0')
|
||||
assert.strictEqual(xrp, '0', '-0 drops equals 0 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('0.00')
|
||||
assert.strictEqual(xrp, '0', '0.00 drops equals 0 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('000000000')
|
||||
assert.strictEqual(xrp, '0', '000000000 drops equals 0 XRP')
|
||||
})
|
||||
|
||||
it('works with a negative value', function () {
|
||||
const xrp = this.api.dropsToXrp('-2000000')
|
||||
assert.strictEqual(xrp, '-2', '-2 million drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('works with a value ending with a decimal point', function () {
|
||||
let xrp = this.api.dropsToXrp('2000000.')
|
||||
assert.strictEqual(xrp, '2', '2000000. drops equals 2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp('-2000000.')
|
||||
assert.strictEqual(xrp, '-2', '-2000000. drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('works with BigNumber objects', function () {
|
||||
let xrp = this.api.dropsToXrp(new BigNumber(2000000))
|
||||
assert.strictEqual(xrp, '2', '(BigNumber) 2 million drops equals 2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(new BigNumber(-2000000))
|
||||
assert.strictEqual(xrp, '-2', '(BigNumber) -2 million drops equals -2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(new BigNumber(2345678))
|
||||
assert.strictEqual(xrp, '2.345678', '(BigNumber) 2,345,678 drops equals 2.345678 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(new BigNumber(-2345678))
|
||||
assert.strictEqual(xrp, '-2.345678', '(BigNumber) -2,345,678 drops equals -2.345678 XRP')
|
||||
})
|
||||
|
||||
it('works with a number', function() {
|
||||
// This is not recommended. Use strings or BigNumber objects to avoid precision errors.
|
||||
|
||||
let xrp = this.api.dropsToXrp(2000000)
|
||||
assert.strictEqual(xrp, '2', '(number) 2 million drops equals 2 XRP')
|
||||
|
||||
xrp = this.api.dropsToXrp(-2000000)
|
||||
assert.strictEqual(xrp, '-2', '(number) -2 million drops equals -2 XRP')
|
||||
})
|
||||
|
||||
it('throws with an amount with too many decimal places', function () {
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('1.2')
|
||||
}, /has too many decimal places/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('0.10')
|
||||
}, /has too many decimal places/)
|
||||
})
|
||||
|
||||
it('throws with an invalid value', function () {
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('FOO')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('1e-7')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('2,0')
|
||||
}, /invalid value/)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('.')
|
||||
}, /dropsToXrp\: invalid value '\.', should be a BigNumber or string-encoded number\./)
|
||||
})
|
||||
|
||||
it('throws with an amount more than one decimal point', function () {
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('1.0.0')
|
||||
}, /dropsToXrp:\ invalid\ value\ '1\.0\.0'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.dropsToXrp('...')
|
||||
}, /dropsToXrp:\ invalid\ value\ '\.\.\.'\,\ should\ be\ a\ number\ matching\ \(\^\-\?\[0\-9\]\*\.\?\[0\-9\]\*\$\)\./)
|
||||
})
|
||||
})
|
||||
describe('pagination', function () {
|
||||
|
||||
describe('hasNextPage', function () {
|
||||
|
||||
it('returns true when there is another page', function () {
|
||||
return this.api.request('ledger_data').then(response => {
|
||||
assert(this.api.hasNextPage(response));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('returns false when there are no more pages', function () {
|
||||
return this.api.request('ledger_data').then(response => {
|
||||
return this.api.requestNextPage('ledger_data', {}, response);
|
||||
}).then(response => {
|
||||
assert(!this.api.hasNextPage(response));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('requestNextPage', function () {
|
||||
|
||||
it('requests the next page', function () {
|
||||
return this.api.request('ledger_data').then(response => {
|
||||
return this.api.requestNextPage('ledger_data', {}, response);
|
||||
}).then(response => {
|
||||
assert.equal(response.state[0].index, '000B714B790C3C79FEE00D17C4DEB436B375466F29679447BA64F265FD63D731')
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects when there are no more pages', function () {
|
||||
return this.api.request('ledger_data').then(response => {
|
||||
return this.api.requestNextPage('ledger_data', {}, response);
|
||||
}).then(response => {
|
||||
assert(!this.api.hasNextPage(response))
|
||||
return this.api.requestNextPage('ledger_data', {}, response);
|
||||
}).then(() => {
|
||||
assert(false, 'Should reject');
|
||||
}).catch(error => {
|
||||
assert(error instanceof Error);
|
||||
assert.equal(error.message, 'response does not have a next page')
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('preparePayment', function () {
|
||||
|
||||
it('normal', function () {
|
||||
@@ -124,6 +392,37 @@ describe('RippleAPI', function () {
|
||||
instructions).then(_.partial(checkResult,
|
||||
responses.preparePayment.minAmount, 'prepare'));
|
||||
});
|
||||
|
||||
it('preparePayment - throws when fee exceeds 2 XRP', function () {
|
||||
const localInstructions = _.defaults({
|
||||
fee: '2.1'
|
||||
}, instructions);
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions)
|
||||
}, /Fee of 2\.1 XRP exceeds max of 2 XRP\. To use this fee, increase `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('preparePayment - allows fee exceeding 2 XRP when maxFeeXRP is higher', function () {
|
||||
this.api._maxFeeXRP = '2.2'
|
||||
const localInstructions = _.defaults({
|
||||
fee: '2.1'
|
||||
}, instructions);
|
||||
|
||||
const expectedResponse = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"2100000\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "2.1",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
});
|
||||
|
||||
it('prepareOrder - buy order', function () {
|
||||
@@ -503,6 +802,114 @@ describe('RippleAPI', function () {
|
||||
assert.deepEqual(signature, responses.sign.signAs);
|
||||
});
|
||||
|
||||
it('sign - withKeypair', function () {
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A',
|
||||
publicKey:
|
||||
'02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
|
||||
};
|
||||
const result = this.api.sign(requests.sign.normal.txJSON, keypair);
|
||||
assert.deepEqual(result, responses.sign.normal);
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - withKeypair already signed', function () {
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A',
|
||||
publicKey:
|
||||
'02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8'
|
||||
};
|
||||
const result = this.api.sign(requests.sign.normal.txJSON, keypair);
|
||||
assert.throws(() => {
|
||||
const tx = JSON.stringify(binary.decode(result.signedTransaction));
|
||||
this.api.sign(tx, keypair);
|
||||
}, /txJSON must not contain "TxnSignature" or "Signers" properties/);
|
||||
});
|
||||
|
||||
it('sign - withKeypair EscrowExecution', function () {
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'001ACAAEDECE405B2A958212629E16F2EB46B153EEE94CDD350FDEFF52795525B7',
|
||||
publicKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020'
|
||||
};
|
||||
const result = this.api.sign(requests.sign.escrow.txJSON, keypair);
|
||||
assert.deepEqual(result, responses.sign.escrow);
|
||||
schemaValidator.schemaValidate('sign', result);
|
||||
});
|
||||
|
||||
it('sign - withKeypair signAs', function () {
|
||||
const txJSON = requests.sign.signAs;
|
||||
const keypair = {
|
||||
privateKey:
|
||||
'001ACAAEDECE405B2A958212629E16F2EB46B153EEE94CDD350FDEFF52795525B7',
|
||||
publicKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020'
|
||||
};
|
||||
const signature = this.api.sign(JSON.stringify(txJSON), keypair, {
|
||||
signAs: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
|
||||
});
|
||||
assert.deepEqual(signature, responses.sign.signAs);
|
||||
});
|
||||
|
||||
it('sign - throws when Fee exceeds maxFeeXRP (in drops)', function () {
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"2010000\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "2.01",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "2000000"\. To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('sign - throws when Fee exceeds maxFeeXRP (in drops) - custom maxFeeXRP', function () {
|
||||
this.api._maxFeeXRP = '1.9'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"2010000\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "2.01",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
this.api.sign(request.txJSON, secret)
|
||||
}, /Fee" should not exceed "1900000"\. To use a higher fee, set `maxFeeXRP` in the RippleAPI constructor\./)
|
||||
});
|
||||
|
||||
it('sign - permits fee exceeding 2000000 drops when maxFeeXRP is higher than 2 XRP', function () {
|
||||
this.api._maxFeeXRP = '2.1'
|
||||
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
|
||||
const request = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"2010000\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
|
||||
"instructions": {
|
||||
"fee": "2.01",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
const result = this.api.sign(request.txJSON, secret)
|
||||
|
||||
const expectedResponse = {
|
||||
signedTransaction: "12000322800000002400000017201B008695536840000000001EAB90732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8744630440220384FBB48EEE7B0E58BD89294A609F9407C51FBE8FA08A4B305B22E9A7489D66602200152315EFE752DA381E74493419871550D206AC6503841DA5F8C30E35D9E3892770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304",
|
||||
id: "A1586D6AF7B0821E7075E12A0132D9EB50BC1874A0749441201497F7561795FB"
|
||||
}
|
||||
|
||||
assert.deepEqual(result, expectedResponse)
|
||||
schemaValidator.schemaValidate('sign', result)
|
||||
});
|
||||
|
||||
it('submit', function () {
|
||||
return this.api.submit(responses.sign.normal.signedTransaction).then(
|
||||
_.partial(checkResult, responses.submit, 'submit'));
|
||||
@@ -1124,9 +1531,11 @@ describe('RippleAPI', function () {
|
||||
});
|
||||
|
||||
it('getSettings - invalid options', function () {
|
||||
assert.throws(() => {
|
||||
this.api.getSettings(address, { invalid: 'options' });
|
||||
}, this.api.errors.ValidationError);
|
||||
return this.api.getSettings(address, { invalid: 'options' }).then(() => {
|
||||
assert(false, 'Should throw ValidationError');
|
||||
}).catch(error => {
|
||||
assert(error instanceof this.api.errors.ValidationError);
|
||||
});
|
||||
});
|
||||
|
||||
it('getAccountInfo', function () {
|
||||
@@ -1147,6 +1556,33 @@ describe('RippleAPI', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('getAccountObjects', function () {
|
||||
return this.api.getAccountObjects(address).then(response =>
|
||||
checkResult(responses.getAccountObjects, 'AccountObjectsResponse', response));
|
||||
});
|
||||
|
||||
it('getAccountObjects - invalid options', function () {
|
||||
// Intentionally no local validation of these options
|
||||
return this.api.getAccountObjects(address, {invalid: 'options'}).then(response =>
|
||||
checkResult(responses.getAccountObjects, 'AccountObjectsResponse', response));
|
||||
});
|
||||
|
||||
it('request account_objects', function () {
|
||||
return this.api.request('account_objects', {
|
||||
account: address
|
||||
}).then(response =>
|
||||
checkResult(responses.getAccountObjects, 'AccountObjectsResponse', response));
|
||||
});
|
||||
|
||||
it('request account_objects - invalid options', function () {
|
||||
// Intentionally no local validation of these options
|
||||
return this.api.request('account_objects', {
|
||||
account: address,
|
||||
invalid: 'options'
|
||||
}).then(response =>
|
||||
checkResult(responses.getAccountObjects, 'AccountObjectsResponse', response));
|
||||
});
|
||||
|
||||
it('getOrders', function () {
|
||||
return this.api.getOrders(address).then(
|
||||
_.partial(checkResult, responses.getOrders, 'getOrders'));
|
||||
@@ -1314,6 +1750,76 @@ describe('RippleAPI', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('getFee - high load_factor', function () {
|
||||
this.api.connection._send(JSON.stringify({
|
||||
command: 'config',
|
||||
data: { highLoadFactor: true }
|
||||
}));
|
||||
|
||||
return this.api.getFee().then(fee => {
|
||||
assert.strictEqual(fee, '2');
|
||||
});
|
||||
});
|
||||
|
||||
it('fee - default maxFee of 2 XRP', function () {
|
||||
this.api._feeCushion = 1000000;
|
||||
|
||||
const expectedResponse = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"2000000\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "2",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, instructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('fee - capped to maxFeeXRP when maxFee exceeds maxFeeXRP', function () {
|
||||
this.api._feeCushion = 1000000
|
||||
this.api._maxFeeXRP = '3'
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '4'
|
||||
}, instructions);
|
||||
|
||||
const expectedResponse = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"3000000\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "3",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('fee - capped to maxFee', function () {
|
||||
this.api._feeCushion = 1000000
|
||||
this.api._maxFeeXRP = '5'
|
||||
const localInstructions = _.defaults({
|
||||
maxFee: '4'
|
||||
}, instructions);
|
||||
|
||||
const expectedResponse = {
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"SendMax\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"4000000\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "4",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
|
||||
return this.api.preparePayment(
|
||||
address, requests.preparePayment.normal, localInstructions).then(
|
||||
_.partial(checkResult, expectedResponse, 'prepare'));
|
||||
});
|
||||
|
||||
it('disconnect & isConnected', function () {
|
||||
assert.strictEqual(this.api.isConnected(), true);
|
||||
return this.api.disconnect().then(() => {
|
||||
@@ -1447,12 +1953,12 @@ describe('RippleAPI', function () {
|
||||
_.partial(checkResult, responses.getLedger.header, 'getLedger'));
|
||||
});
|
||||
|
||||
// New in > 0.21.0
|
||||
// future ledger versions are allowed, and passed to rippled as-is.
|
||||
it('getLedger - future ledger version', function () {
|
||||
return this.api.getLedger({ ledgerVersion: 14661789 }).then(() => {
|
||||
assert(false, 'Should throw LedgerVersionError');
|
||||
}).catch(error => {
|
||||
assert(error instanceof this.api.errors.LedgerVersionError);
|
||||
});
|
||||
return this.api.getLedger({ ledgerVersion: 14661789 }).then(response => {
|
||||
assert(response)
|
||||
})
|
||||
});
|
||||
|
||||
it('getLedger - with state as hashes', function () {
|
||||
|
||||
@@ -381,7 +381,7 @@ describe('Connection', function() {
|
||||
}));
|
||||
});
|
||||
|
||||
it('propagate error message', function(done) {
|
||||
it('propagates error message', function(done) {
|
||||
this.api.on('error', (errorCode, errorMessage, data) => {
|
||||
assert.strictEqual(errorCode, 'slowDown');
|
||||
assert.strictEqual(errorMessage, 'slow down');
|
||||
@@ -393,11 +393,24 @@ describe('Connection', function() {
|
||||
}));
|
||||
});
|
||||
|
||||
it('propagates RippledError data', function(done) {
|
||||
this.api.request('subscribe', {streams: 'validations'}).catch(error => {
|
||||
assert.strictEqual(error.name, 'RippledError')
|
||||
assert.strictEqual(error.message, 'invalidParams')
|
||||
assert.strictEqual(error.data.error_code, 31)
|
||||
assert.strictEqual(error.data.error_message, 'Invalid parameters.')
|
||||
assert.deepEqual(error.data.request, { command: 'subscribe', id: 0, streams: 'validations' })
|
||||
assert.strictEqual(error.data.status, 'error')
|
||||
assert.strictEqual(error.data.type, 'response')
|
||||
done()
|
||||
})
|
||||
});
|
||||
|
||||
it('unrecognized message type', function(done) {
|
||||
this.api.on('error', (errorCode, errorMessage, message) => {
|
||||
assert.strictEqual(errorCode, 'badMessage');
|
||||
assert.strictEqual(errorMessage, 'unrecognized message type: unknown');
|
||||
assert.strictEqual(message, '{"type":"unknown"}');
|
||||
// This enables us to automatically support any
|
||||
// new messages added by rippled in the future.
|
||||
this.api.connection.on('unknown', (event) => {
|
||||
assert.deepEqual(event, {type: 'unknown'})
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -414,8 +427,8 @@ describe('Connection', function() {
|
||||
});
|
||||
|
||||
it('should throw RippledNotInitializedError if server does not have ' +
|
||||
'validated ledgers',
|
||||
function() {
|
||||
'validated ledgers', function() {
|
||||
|
||||
this.timeout(3000);
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
@@ -439,13 +452,13 @@ describe('Connection', function() {
|
||||
this.api.on('error', error => {
|
||||
done(error || new Error('Should not emit error.'));
|
||||
});
|
||||
let disconncedCount = 0;
|
||||
let disconnectedCount = 0;
|
||||
this.api.on('connected', () => {
|
||||
done(disconncedCount !== 1 ?
|
||||
done(disconnectedCount !== 1 ?
|
||||
new Error('Wrong number of disconnects') : undefined);
|
||||
});
|
||||
this.api.on('disconnected', () => {
|
||||
disconncedCount++;
|
||||
disconnectedCount++;
|
||||
});
|
||||
|
||||
this.api.connection._send(JSON.stringify({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"amount": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
},
|
||||
"checkID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"sendMax": {
|
||||
"currency": "XRP",
|
||||
"value": "1"
|
||||
"currency": "drops",
|
||||
"value": "1000000"
|
||||
}
|
||||
}
|
||||
|
||||
6
test/fixtures/requests/prepare-order.json
vendored
6
test/fixtures/requests/prepare-order.json
vendored
@@ -6,9 +6,9 @@
|
||||
"value": "10.1"
|
||||
},
|
||||
"totalPrice": {
|
||||
"currency": "XRP",
|
||||
"value": "2"
|
||||
"currency": "drops",
|
||||
"value": "2000000"
|
||||
},
|
||||
"passive": true,
|
||||
"passive": false,
|
||||
"fillOrKill": true
|
||||
}
|
||||
|
||||
269
test/fixtures/responses/get-account-objects.json
vendored
Normal file
269
test/fixtures/responses/get-account-objects.json
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
{
|
||||
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"account_objects": [
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "ASP",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 65536,
|
||||
"HighLimit": {
|
||||
"currency": "ASP",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "ASP",
|
||||
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
|
||||
"value": "10"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"BF7555B0F018E3C5E2A3FF9437A1A5092F32903BE246202F988181B9CED0D862",
|
||||
"PreviousTxnLgrSeq": 1438879,
|
||||
"index":
|
||||
"2243B0B630EA6F7330B654EFA53E27A7609D9484E535AB11B7F946DF3D247CE9"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "XAU",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 3342336,
|
||||
"HighLimit": {
|
||||
"currency": "XAU",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "XAU",
|
||||
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"79B26D7D34B950AC2C2F91A299A6888FABB376DD76CFF79D56E805BF439F6942",
|
||||
"PreviousTxnLgrSeq": 5982530,
|
||||
"index":
|
||||
"9ED4406351B7A511A012A9B5E7FE4059FA2F7650621379C0013492C315E25B97"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "5"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"6FE8C824364FB1195BCFEDCB368DFEE3980F7F78D3BF4DC4174BB4C86CF8C5CE",
|
||||
"PreviousTxnLgrSeq": 10555014,
|
||||
"index":
|
||||
"2DECFAC23B77D5AEA6116C15F5C6D4669EBAEE9E7EE050A40FE2B1E47B6A9419"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "MXN",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "481.992867407479"
|
||||
},
|
||||
"Flags": 65536,
|
||||
"HighLimit": {
|
||||
"currency": "MXN",
|
||||
"issuer": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "MXN",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1000"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"A467BACE5F183CDE1F075F72435FE86BAD8626ED1048EDEFF7562A4CC76FD1C5",
|
||||
"PreviousTxnLgrSeq": 3316170,
|
||||
"index":
|
||||
"EC8B9B6B364AF6CB6393A423FDD2DDBA96375EC772E6B50A3581E53BFBDFDD9A"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "EUR",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0.793598266778297"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "EUR",
|
||||
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "EUR",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"E9345D44433EA368CFE1E00D84809C8E695C87FED18859248E13662D46A0EC46",
|
||||
"PreviousTxnLgrSeq": 5447146,
|
||||
"index":
|
||||
"4513749B30F4AF8DA11F077C448128D6486BF12854B760E4E5808714588AA915"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "CNY",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "3"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000008",
|
||||
"PreviousTxnID":
|
||||
"2FDDC81F4394695B01A47913BEC4281AC9A283CC8F903C14ADEA970F60E57FCF",
|
||||
"PreviousTxnLgrSeq": 5949673,
|
||||
"index":
|
||||
"578C327DA8944BDE2E10C9BA36AFA2F43E06C8D1E8819FB225D266CBBCFDE5CE"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "DYM",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1.336889190631542"
|
||||
},
|
||||
"Flags": 65536,
|
||||
"HighLimit": {
|
||||
"currency": "DYM",
|
||||
"issuer": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "DYM",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "3"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"6DA2BD02DFB83FA4DAFC2651860B60071156171E9C021D9E0372A61A477FFBB1",
|
||||
"PreviousTxnLgrSeq": 8818732,
|
||||
"index":
|
||||
"5A2A5FF12E71AEE57564E624117BBA68DEF78CD564EF6259F92A011693E027C7"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "CHF",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.3488146605801446"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "CHF",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "CHF",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000008C",
|
||||
"PreviousTxnID":
|
||||
"722394372525A13D1EAAB005642F50F05A93CF63F7F472E0F91CDD6D38EB5869",
|
||||
"PreviousTxnLgrSeq": 2687590,
|
||||
"index":
|
||||
"F2DBAD20072527F6AD02CE7F5A450DBC72BE2ABB91741A8A3ADD30D5AD7A99FB"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "3"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000043",
|
||||
"PreviousTxnID":
|
||||
"03EDF724397D2DEE70E49D512AECD619E9EA536BE6CFD48ED167AE2596055C9A",
|
||||
"PreviousTxnLgrSeq": 8317037,
|
||||
"index":
|
||||
"767C12AF647CDF5FEB9019B37018748A79C50EDAF87E8D4C7F39F78AA7CA9765"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-16.00534471983042"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "5000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000004A",
|
||||
"PreviousTxnID":
|
||||
"CFFF5CFE623C9543308C6529782B6A6532207D819795AAFE85555DB8BF390FE7",
|
||||
"PreviousTxnLgrSeq": 14365854,
|
||||
"index":
|
||||
"826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09"
|
||||
}
|
||||
],
|
||||
"ledger_hash":
|
||||
"053DF17D2289D1C4971C22F235BC1FCA7D4B3AE966F842E5819D0749E0B8ECD3",
|
||||
"ledger_index": 14378733,
|
||||
"validated": true
|
||||
}
|
||||
@@ -17,6 +17,26 @@
|
||||
"maker": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"sequence": 5,
|
||||
"makerExchangeRate": "3.970260734451929e-8"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"BookDirectory": "A118405CF7C2C89AB0CC084417187B86870DC14325C861A0470E1AEE5CBE20D9",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "9DD36CC7338FEB9E501A33EAAA4C00DBE4ED3A692704C62DDBD1848EE1F6E762",
|
||||
"PreviousTxnLgrSeq": 11,
|
||||
"Sequence": 5,
|
||||
"TakerGets": "254391353000000",
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
|
||||
"value": "10.1"
|
||||
},
|
||||
"index": "BF656DABDD84E6128A45039F8D557C9477D4DA31F5B00868F2191F0A11FE3798",
|
||||
"owner_funds": "99999998959999928",
|
||||
"quality": "3970260734451929e-29"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -38,6 +58,25 @@
|
||||
"maker": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"sequence": 6,
|
||||
"makerExchangeRate": "0.0000780093458738806"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||
"BookDirectory": "A118405CF7C2C89AB0CC084417187B86870DC14325C861A0561BB6E89EFF509C",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "CFB5786459E568DFC504E7319C515658DED657A7F4EFB5957B33E5E3BD9A1353",
|
||||
"PreviousTxnLgrSeq": 13,
|
||||
"Sequence": 6,
|
||||
"TakerPays": "134000000",
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
|
||||
"value": "10453252347.1"
|
||||
},
|
||||
"index": "C72CDC1BA4DA529B062871F22C6D175A4D97D4F1160D0D7E646E60699278B5B5",
|
||||
"quality": "78.0093458738806"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
542
test/fixtures/responses/get-orderbook.json
vendored
542
test/fixtures/responses/get-orderbook.json
vendored
@@ -18,6 +18,30 @@
|
||||
"maker": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
||||
"sequence": 386940,
|
||||
"makerExchangeRate": "326.5003614141928"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570B9980E49C7DE8",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000008",
|
||||
"PreviousTxnID": "92DBA0BE18B331AC61FB277211477A255D3B5EA9C5FE689171DE689FB45FE18A",
|
||||
"PreviousTxnLgrSeq": 10714030,
|
||||
"Sequence": 386940,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.2849323720855092"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "93.030522464522"
|
||||
},
|
||||
"index": "8092033091034D94219BC1131AF7A6B469D790D81831CB479AB6F67A32BE4E13",
|
||||
"owner_funds": "31.77682120227525",
|
||||
"quality": "326.5003614141928"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -38,6 +62,30 @@
|
||||
"maker": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1",
|
||||
"sequence": 207855,
|
||||
"makerExchangeRate": "330.6364334177034"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570BBF1EEFA2FB0A",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "C6BDA152363E3CFE18688A6830B49F3DB2B05976110B5908EA4EB66D93DEEB1F",
|
||||
"PreviousTxnLgrSeq": 10714031,
|
||||
"Sequence": 207855,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.00302447007930511"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1"
|
||||
},
|
||||
"index": "8DB3520FF9CB16A0EA955056C49115F8CFB03A587D0A4AFC844F1D220EFCE0B9",
|
||||
"owner_funds": "0.0670537912615556",
|
||||
"quality": "330.6364334177034"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -59,6 +107,31 @@
|
||||
"maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
|
||||
"sequence": 110103,
|
||||
"makerExchangeRate": "331.1338298016111"
|
||||
},
|
||||
"data": {
|
||||
"Account": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570BC3A506FC016F",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472785283,
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000008F0",
|
||||
"PreviousTxnID": "77E763F1D02F58965CD1AD94F557B37A582FAC7760B71F391B856959836C2F7B",
|
||||
"PreviousTxnLgrSeq": 10713576,
|
||||
"Sequence": 110103,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.3"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.34014894048333"
|
||||
},
|
||||
"index": "9ECDFD31B28643FD3A54658398C5715D6DAD574F83F04529CB24765770F9084D",
|
||||
"owner_funds": "4.021116654525635",
|
||||
"quality": "331.1338298016111"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -91,6 +164,40 @@
|
||||
"value": "268.2219496064341",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Account": "rPyYxUGK8L4dgEvjPs3aRc1B1jEiLr3Hx5",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570BCB85BCA78000",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "D22993C68C94ACE3F2FCE4A334EBEA98CC46DCA92886C12B5E5B4780B5E17D4E",
|
||||
"PreviousTxnLgrSeq": 10711938,
|
||||
"Sequence": 392,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.8095"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "268.754"
|
||||
},
|
||||
"index": "18B136E08EF50F0DEE8521EA22D16A950CD8B6DDF5F6E07C35F7FDDBBB09718D",
|
||||
"owner_funds": "0.8095132334507441",
|
||||
"quality": "332",
|
||||
"taker_gets_funded": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.8078974385735969"
|
||||
},
|
||||
"taker_pays_funded": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "268.2219496064341"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -112,6 +219,30 @@
|
||||
"maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
|
||||
"sequence": 110105,
|
||||
"makerExchangeRate": "337.7996295968016"
|
||||
},
|
||||
"data": {
|
||||
"Account": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570C00450D461510",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472785284,
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000008F0",
|
||||
"PreviousTxnID": "1F4D9D859D9AABA888C0708A572B38919A3AEF2C8C1F5A13F58F44C92E5FF3FB",
|
||||
"PreviousTxnLgrSeq": 10713576,
|
||||
"Sequence": 110105,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.4499999999999999"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "152.0098333185607"
|
||||
},
|
||||
"index": "9F380E0B39E2AF8AA9608C3E39A5A8628E6D0F44385C6D12BE06F4FEC8D83351",
|
||||
"quality": "337.7996295968016"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -132,6 +263,30 @@
|
||||
"maker": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83",
|
||||
"sequence": 110061,
|
||||
"makerExchangeRate": "347.2306949944844"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570C560B764D760C",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000001",
|
||||
"PreviousTxnID": "9A0B6B76F0D86614F965A2FFCC8859D8607F4E424351D4CFE2FBE24510F93F25",
|
||||
"PreviousTxnLgrSeq": 10708382,
|
||||
"Sequence": 110061,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.003768001830745216"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1.308365894430151"
|
||||
},
|
||||
"index": "B971769686CE1B9139502770158A4E7C011CFF8E865E5AAE5428E23AAA0E146D",
|
||||
"owner_funds": "0.2229210189326514",
|
||||
"quality": "347.2306949944844"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -153,6 +308,31 @@
|
||||
"maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"sequence": 35788,
|
||||
"makerExchangeRate": "352.7092203179974"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570C87DF25DC4FC6",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472783298,
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000003D2",
|
||||
"PreviousTxnID": "E5F9A10F29A4BB3634D5A84FC96931E17267B58E0D2D5ADE24FFB751E52ADB9E",
|
||||
"PreviousTxnLgrSeq": 10713533,
|
||||
"Sequence": 35788,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.5"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "176.3546101589987"
|
||||
},
|
||||
"index": "D2CB71038AD0ECAF4B5FF0A953AD1257225D0071E6F3AF9ADE67F05590B45C6E",
|
||||
"owner_funds": "6.617688680663627",
|
||||
"quality": "352.7092203179974"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -185,6 +365,40 @@
|
||||
"value": "179.1217564870259",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Account": "rN6jbxx4H6NxcnmkzBxQnbCWLECNKrgSSf",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570CC0B8E0E2C000",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "2E16ACFEAC2306E3B3483D445787F3496FACF9504F7A5E909620C1A73E2EDE54",
|
||||
"PreviousTxnLgrSeq": 10558020,
|
||||
"Sequence": 491,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.5"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "179.48"
|
||||
},
|
||||
"index": "DA853913C8013C9471957349EDAEE4DF4846833B8CCB92008E2A8994E37BEF0D",
|
||||
"owner_funds": "0.5",
|
||||
"quality": "358.96",
|
||||
"taker_gets_funded": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.499001996007984"
|
||||
},
|
||||
"taker_pays_funded": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "179.1217564870259"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -206,6 +420,30 @@
|
||||
"maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"sequence": 35789,
|
||||
"makerExchangeRate": "360.9637829743709"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570CD2F24C9C145D",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472783299,
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000003D2",
|
||||
"PreviousTxnID": "B1B12E47043B4260223A2C4240D19E93526B55B1DB38DEED335DACE7C04FEB23",
|
||||
"PreviousTxnLgrSeq": 10713534,
|
||||
"Sequence": 35789,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.8"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "288.7710263794967"
|
||||
},
|
||||
"index": "B89AD580E908F7337CCBB47A0BAAC6417EF13AC3465E34E8B7DD3BED016EA833",
|
||||
"quality": "360.9637829743709"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -238,6 +476,40 @@
|
||||
"value": "82.50309772176658",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Account": "rUeCeioKJkbYhv4mRGuAbZpPcqkMCoYq6N",
|
||||
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570D0069F50EA028",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000012",
|
||||
"PreviousTxnID": "F0E8ABF07F83DF0B5EF5B417E8E29A45A5503BA8F26FBC86447CC6B1FAD6A1C4",
|
||||
"PreviousTxnLgrSeq": 10447672,
|
||||
"Sequence": 5255,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.5"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "182.9814890090516"
|
||||
},
|
||||
"index": "D652DCE4B19C6CB43912651D3A975371D3B2A16A034EDF07BC11BF721AEF94A4",
|
||||
"owner_funds": "0.225891986027944",
|
||||
"quality": "365.9629780181032",
|
||||
"taker_gets_funded": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.2254411038203033"
|
||||
},
|
||||
"taker_pays_funded": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "82.50309772176658"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -260,6 +532,30 @@
|
||||
"maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
|
||||
"sequence": 434,
|
||||
"makerExchangeRate": "0.003120027456241615"
|
||||
},
|
||||
"data": {
|
||||
"Account": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B15A60037FFCF",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "544932DC56D72E845AF2B738821FE07865E32EC196270678AB0D947F54E9F49F",
|
||||
"PreviousTxnLgrSeq": 10679000,
|
||||
"Sequence": 434,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "3205.1"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "10"
|
||||
},
|
||||
"index": "CE457115A4ADCC8CB351B3E35A0851E48DE16605C23E305017A9B697B156DE5A",
|
||||
"owner_funds": "41952.95917199965",
|
||||
"quality": "0.003120027456241615"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -280,6 +576,30 @@
|
||||
"maker": "rDYCRhpahKEhCFV25xScg67Bwf4W9sTYAm",
|
||||
"sequence": 233,
|
||||
"makerExchangeRate": "0.003125"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDYCRhpahKEhCFV25xScg67Bwf4W9sTYAm",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B1A2BC2EC5000",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "F68F9658AB3D462FEB027E6C380F054BC6D2514B43EC3C6AD46EE19C59BF1CC3",
|
||||
"PreviousTxnLgrSeq": 10704238,
|
||||
"Sequence": 233,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1599.063669386278"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "4.99707396683212"
|
||||
},
|
||||
"index": "BF14FBB305159DBCAEA91B7E848408F5B559A91B160EBCB6D244958A6A16EA6B",
|
||||
"owner_funds": "3169.910902910102",
|
||||
"quality": "0.003125"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -313,6 +633,41 @@
|
||||
"value": "0",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Account": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B2BF1C2F4D4C9",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472785284,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000008F0",
|
||||
"PreviousTxnID": "446410E1CD718AC01929DD16B558FCF6B3A7B8BF208C420E67A280C089C5C59B",
|
||||
"PreviousTxnLgrSeq": 10713576,
|
||||
"Sequence": 110104,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "143.1050962074379"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.4499999999999999"
|
||||
},
|
||||
"index": "67924B0EAA15784CC00CCD5FDD655EE2D6D2AE40341776B5F14E52341E7FC73E",
|
||||
"owner_funds": "0",
|
||||
"quality": "0.003144542101755081",
|
||||
"taker_gets_funded": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"taker_pays_funded": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -346,6 +701,41 @@
|
||||
"value": "0",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B2CD7A2BFBB75",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472772651,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000003CD",
|
||||
"PreviousTxnID": "D49164AB68DDA3AEC9DFCC69A35685C4F532B5C231D3C1D25FEA7D5D0224FB84",
|
||||
"PreviousTxnLgrSeq": 10711128,
|
||||
"Sequence": 35625,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "254.329207354604"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.8"
|
||||
},
|
||||
"index": "567BF2825173E3FB28FC94E436B6EB30D9A415FC2335E6D25CDE1BE47B25D120",
|
||||
"owner_funds": "0",
|
||||
"quality": "0.003145529403882357",
|
||||
"taker_gets_funded": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"taker_pays_funded": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -366,6 +756,30 @@
|
||||
"maker": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
||||
"sequence": 387756,
|
||||
"makerExchangeRate": "0.003155743848271834"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B3621DF140FDA",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000008",
|
||||
"PreviousTxnID": "2E371E2B287C8A9FBB3424E4204B17AD9FA1BAA9F3B33C7D2261E3B038AFF083",
|
||||
"PreviousTxnLgrSeq": 10716291,
|
||||
"Sequence": 387756,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "390.4979"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1.23231134568807"
|
||||
},
|
||||
"index": "8CA23E55BF9F46AC7E803D3DB40FD03225EFCA66650D4CF0CBDD28A7CCDC8400",
|
||||
"owner_funds": "5704.824764087842",
|
||||
"quality": "0.003155743848271834"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -386,6 +800,30 @@
|
||||
"maker": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1",
|
||||
"sequence": 208927,
|
||||
"makerExchangeRate": "0.003160328237957649"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B3A4D41FF4211",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "91763FA7089C63CC4D5D14CBA6A5A5BF7ECE949B0D34F00FD35E733AF9F05AF1",
|
||||
"PreviousTxnLgrSeq": 10716292,
|
||||
"Sequence": 208927,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.003160328237957649"
|
||||
},
|
||||
"index": "7206866E39D9843623EE79E570242753DEE3C597F3856AEFB4631DD5AD8B0557",
|
||||
"owner_funds": "45.55665106096075",
|
||||
"quality": "0.003160328237957649"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -406,6 +844,29 @@
|
||||
"maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
|
||||
"sequence": 429,
|
||||
"makerExchangeRate": "0.003174603174603175"
|
||||
},
|
||||
"data": {
|
||||
"Account": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B4748E68669A7",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "3B3CF6FF1A336335E78513CF77AFD3A784ACDD7B1B4D3F1F16E22957A060BFAE",
|
||||
"PreviousTxnLgrSeq": 10639969,
|
||||
"Sequence": 429,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "4725"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "15"
|
||||
},
|
||||
"index": "42894809370C7E6B23498EF8E22AD4B05F02B94F08E6983357A51EA96A95FF7F",
|
||||
"quality": "0.003174603174603175"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -426,6 +887,30 @@
|
||||
"maker": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83",
|
||||
"sequence": 110099,
|
||||
"makerExchangeRate": "0.003193013959408667"
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B58077ED03C1B",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000001",
|
||||
"PreviousTxnID": "98F3F2D02D3BB0AEAC09EECCF2F24BBE5E1AB2C71C40D7BD0A5199E12541B6E2",
|
||||
"PreviousTxnLgrSeq": 10715839,
|
||||
"Sequence": 110099,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1.24252537879871"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.003967400879423823"
|
||||
},
|
||||
"index": "F4404D6547149419D3607F81D7080979FBB3AFE2661F9A933E2F6C07AC1D1F6D",
|
||||
"owner_funds": "73.52163803897041",
|
||||
"quality": "0.003193013959408667"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -459,6 +944,40 @@
|
||||
"value": "0",
|
||||
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B72A555B981A3",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 472772652,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000003CD",
|
||||
"PreviousTxnID": "146C8DBB047BAAFAE5B8C8DECCCDACD9DFCD7A464E5AB273230FF975E9B83CF7",
|
||||
"PreviousTxnLgrSeq": 10711128,
|
||||
"Sequence": 35627,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "496.5429474010489"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "1.6"
|
||||
},
|
||||
"index": "50CAA04E81D0009115B61C132FC9887FA9E5336E0CB8A2E7D3280ADBF6ABC043",
|
||||
"quality": "0.003222279177208227",
|
||||
"taker_gets_funded": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"taker_pays_funded": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -479,6 +998,29 @@
|
||||
"maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
|
||||
"sequence": 431,
|
||||
"makerExchangeRate": "0.003222687721559781"
|
||||
},
|
||||
"data": {
|
||||
"Account": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
|
||||
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B730474DD96E5",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "624F9ADA85EC3BE845EAC075B47E01E4F89288EAF27823C715777B3DFFB21F24",
|
||||
"PreviousTxnLgrSeq": 10639989,
|
||||
"Sequence": 431,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "3103"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "10"
|
||||
},
|
||||
"index": "8A319A496288228AD9CAD74375E32FA81805C56A9AD84798A26756A8B3F9EE23",
|
||||
"quality": "0.003222687721559781"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
1
test/fixtures/responses/index.js
vendored
1
test/fixtures/responses/index.js
vendored
@@ -7,6 +7,7 @@ function buildList(options) {
|
||||
module.exports = {
|
||||
generateAddress: require('./generate-address.json'),
|
||||
getAccountInfo: require('./get-account-info.json'),
|
||||
getAccountObjects: require('./get-account-objects.json'),
|
||||
getBalances: require('./get-balances.json'),
|
||||
getBalanceSheet: require('./get-balance-sheet.json'),
|
||||
getOrderbook: {
|
||||
|
||||
23
test/fixtures/responses/ledger.json
vendored
Normal file
23
test/fixtures/responses/ledger.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"ledger": {
|
||||
"accepted": true,
|
||||
"account_hash": "F9E9653EA76EA0AEA58AC98A8E19EDCEC8299C2940519A190674FFAED3639A1F",
|
||||
"close_flags": 0,
|
||||
"close_time": 577999430,
|
||||
"close_time_human": "2018-Apr-25 19:23:50",
|
||||
"close_time_resolution": 10,
|
||||
"closed": true,
|
||||
"hash": "450E5CB0A39495839DA9CD9A0FED74BD71CBB929423A907ADC00F14FC7E7F920",
|
||||
"ledger_hash": "450E5CB0A39495839DA9CD9A0FED74BD71CBB929423A907ADC00F14FC7E7F920",
|
||||
"ledger_index": "38217406",
|
||||
"parent_close_time": 577999422,
|
||||
"parent_hash": "B8B364C63EB9E13FDB89CB729FEF833089B8438CBEB8FC41744CB667209221B3",
|
||||
"seqNum": "38217406",
|
||||
"totalCoins": "99992286058637091",
|
||||
"total_coins": "99992286058637091",
|
||||
"transaction_hash": "5BDD3D2780C28FB2C91C3404BD8ED04786B764B1E18CF319888EDE2C09834726"
|
||||
},
|
||||
"ledger_hash": "450E5CB0A39495839DA9CD9A0FED74BD71CBB929423A907ADC00F14FC7E7F920",
|
||||
"ledger_index": 38217406,
|
||||
"validated": true
|
||||
}
|
||||
2
test/fixtures/responses/prepare-order.json
vendored
2
test/fixtures/responses/prepare-order.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"Flags\":2147745792,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
|
||||
274
test/fixtures/rippled/account-objects-normal.json
vendored
Normal file
274
test/fixtures/rippled/account-objects-normal.json
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
{
|
||||
"id": 1,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"account_objects": [
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "ASP",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 65536,
|
||||
"HighLimit": {
|
||||
"currency": "ASP",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "ASP",
|
||||
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
|
||||
"value": "10"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"BF7555B0F018E3C5E2A3FF9437A1A5092F32903BE246202F988181B9CED0D862",
|
||||
"PreviousTxnLgrSeq": 1438879,
|
||||
"index":
|
||||
"2243B0B630EA6F7330B654EFA53E27A7609D9484E535AB11B7F946DF3D247CE9"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "XAU",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 3342336,
|
||||
"HighLimit": {
|
||||
"currency": "XAU",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "XAU",
|
||||
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"79B26D7D34B950AC2C2F91A299A6888FABB376DD76CFF79D56E805BF439F6942",
|
||||
"PreviousTxnLgrSeq": 5982530,
|
||||
"index":
|
||||
"9ED4406351B7A511A012A9B5E7FE4059FA2F7650621379C0013492C315E25B97"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "5"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"6FE8C824364FB1195BCFEDCB368DFEE3980F7F78D3BF4DC4174BB4C86CF8C5CE",
|
||||
"PreviousTxnLgrSeq": 10555014,
|
||||
"index":
|
||||
"2DECFAC23B77D5AEA6116C15F5C6D4669EBAEE9E7EE050A40FE2B1E47B6A9419"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "MXN",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "481.992867407479"
|
||||
},
|
||||
"Flags": 65536,
|
||||
"HighLimit": {
|
||||
"currency": "MXN",
|
||||
"issuer": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "MXN",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1000"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"A467BACE5F183CDE1F075F72435FE86BAD8626ED1048EDEFF7562A4CC76FD1C5",
|
||||
"PreviousTxnLgrSeq": 3316170,
|
||||
"index":
|
||||
"EC8B9B6B364AF6CB6393A423FDD2DDBA96375EC772E6B50A3581E53BFBDFDD9A"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "EUR",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0.793598266778297"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "EUR",
|
||||
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "EUR",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"E9345D44433EA368CFE1E00D84809C8E695C87FED18859248E13662D46A0EC46",
|
||||
"PreviousTxnLgrSeq": 5447146,
|
||||
"index":
|
||||
"4513749B30F4AF8DA11F077C448128D6486BF12854B760E4E5808714588AA915"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "CNY",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "3"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000008",
|
||||
"PreviousTxnID":
|
||||
"2FDDC81F4394695B01A47913BEC4281AC9A283CC8F903C14ADEA970F60E57FCF",
|
||||
"PreviousTxnLgrSeq": 5949673,
|
||||
"index":
|
||||
"578C327DA8944BDE2E10C9BA36AFA2F43E06C8D1E8819FB225D266CBBCFDE5CE"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "DYM",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1.336889190631542"
|
||||
},
|
||||
"Flags": 65536,
|
||||
"HighLimit": {
|
||||
"currency": "DYM",
|
||||
"issuer": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "DYM",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "3"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"6DA2BD02DFB83FA4DAFC2651860B60071156171E9C021D9E0372A61A477FFBB1",
|
||||
"PreviousTxnLgrSeq": 8818732,
|
||||
"index":
|
||||
"5A2A5FF12E71AEE57564E624117BBA68DEF78CD564EF6259F92A011693E027C7"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "CHF",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.3488146605801446"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "CHF",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "CHF",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000008C",
|
||||
"PreviousTxnID":
|
||||
"722394372525A13D1EAAB005642F50F05A93CF63F7F472E0F91CDD6D38EB5869",
|
||||
"PreviousTxnLgrSeq": 2687590,
|
||||
"index":
|
||||
"F2DBAD20072527F6AD02CE7F5A450DBC72BE2ABB91741A8A3ADD30D5AD7A99FB"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "3"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000043",
|
||||
"PreviousTxnID":
|
||||
"03EDF724397D2DEE70E49D512AECD619E9EA536BE6CFD48ED167AE2596055C9A",
|
||||
"PreviousTxnLgrSeq": 8317037,
|
||||
"index":
|
||||
"767C12AF647CDF5FEB9019B37018748A79C50EDAF87E8D4C7F39F78AA7CA9765"
|
||||
},
|
||||
{
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-16.00534471983042"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "5000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000004A",
|
||||
"PreviousTxnID":
|
||||
"CFFF5CFE623C9543308C6529782B6A6532207D819795AAFE85555DB8BF390FE7",
|
||||
"PreviousTxnLgrSeq": 14365854,
|
||||
"index":
|
||||
"826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09"
|
||||
}
|
||||
],
|
||||
"ledger_hash":
|
||||
"053DF17D2289D1C4971C22F235BC1FCA7D4B3AE966F842E5819D0749E0B8ECD3",
|
||||
"ledger_index": 14378733,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
7
test/fixtures/rippled/account-objects.js
vendored
Normal file
7
test/fixtures/rippled/account-objects.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const accountObjectsNormal = require('./account-objects-normal')
|
||||
|
||||
module.exports = function(request, options = {}) {
|
||||
return JSON.stringify(Object.assign({}, accountObjectsNormal, {id: request.id}))
|
||||
}
|
||||
9
test/fixtures/rippled/index.js
vendored
9
test/fixtures/rippled/index.js
vendored
@@ -16,7 +16,12 @@ module.exports = {
|
||||
},
|
||||
empty: require('./empty'),
|
||||
subscribe: require('./subscribe'),
|
||||
subscribe_error: require('./subscribe_error'),
|
||||
unsubscribe: require('./unsubscribe'),
|
||||
account_objects: {
|
||||
normal: require('./account-objects'),
|
||||
// notfound: require('./account-objects-not-found')
|
||||
},
|
||||
account_info: {
|
||||
normal: require('./account-info'),
|
||||
notfound: require('./account-info-not-found')
|
||||
@@ -33,6 +38,10 @@ module.exports = {
|
||||
usd_xrp: require('./book-offers-usd-xrp'),
|
||||
xrp_usd: require('./book-offers-xrp-usd')
|
||||
},
|
||||
ledger_data: {
|
||||
first_page: require('./ledger-data-first-page'),
|
||||
last_page: require('./ledger-data-last-page')
|
||||
},
|
||||
ledger_entry: {
|
||||
error: require('./ledger-entry-error')
|
||||
},
|
||||
|
||||
40
test/fixtures/rippled/ledger-data-first-page.json
vendored
Normal file
40
test/fixtures/rippled/ledger-data-first-page.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"ledger_hash":
|
||||
"102A6E70FFB18C18E97BB56E3047B0E45EA1BCC90BFCCB8CBB0D07BF0E2AB449",
|
||||
"ledger_index": 38202000,
|
||||
"marker":
|
||||
"000B714B790C3C79FEE00D17C4DEB436B375466F29679447BA64F265FD63D730",
|
||||
"state": [
|
||||
{
|
||||
"Flags": 0,
|
||||
"Indexes": [
|
||||
"B32769DB3BE790E959A96CF37A62414479E3EB20A5AEC7156B2BF8FD816DBFF8"
|
||||
],
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"Owner": "rwt5iiE1mRbBgNhH6spU4nKgHcE7xK9joN",
|
||||
"RootIndex":
|
||||
"0005C961C890079D3C4CC8317F9735D388C3CE3D9BCDC152D3C9A7C08F508D1B",
|
||||
"index":
|
||||
"0005C961C890079D3C4CC8317F9735D388C3CE3D9BCDC152D3C9A7C08F508D1B"
|
||||
},
|
||||
{
|
||||
"Account": "rpzpyUjdWKmz7yyMvirk3abcaNvSPmDpJn",
|
||||
"Balance": "91508000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"OwnerCount": 0,
|
||||
"PreviousTxnID":
|
||||
"F62A5A5EC92DE4E52663B9C7B44A2B76DAB1371737C83A5A81127CBDA84DFE9E",
|
||||
"PreviousTxnLgrSeq": 35672898,
|
||||
"Sequence": 1,
|
||||
"index":
|
||||
"000B6A1287DB6174F61B1BF987E630CF41DA2A2131CFEB6C5C8143A8F539E9D1"
|
||||
}
|
||||
],
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
47
test/fixtures/rippled/ledger-data-last-page.json
vendored
Normal file
47
test/fixtures/rippled/ledger-data-last-page.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"ledger_hash":
|
||||
"102A6E70FFB18C18E97BB56E3047B0E45EA1BCC90BFCCB8CBB0D07BF0E2AB449",
|
||||
"ledger_index": 38202000,
|
||||
"state": [
|
||||
{
|
||||
"Account": "rN3rdDNhQidDuzTFU1ArXWr89B4JG9xZ99",
|
||||
"Balance": "249222644",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"OwnerCount": 0,
|
||||
"PreviousTxnID":
|
||||
"9A6EEBB6055E2C768BCA3B89B458A5D14A931449443053D9A1A9256F79D590DC",
|
||||
"PreviousTxnLgrSeq": 35891744,
|
||||
"Sequence": 1,
|
||||
"index":
|
||||
"000B714B790C3C79FEE00D17C4DEB436B375466F29679447BA64F265FD63D731"
|
||||
},
|
||||
{
|
||||
"Account": "rLNNqGs2jJKQcg2CuoACuwkJ1ssga9LTYT",
|
||||
"BookDirectory":
|
||||
"6FA9AF02AF19345DC187747EF07CDABECA37CB6DCFFB045E5A08D0CF885B163B",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID":
|
||||
"5D3E557E7C08FA90EF9EE144165855B3823BD24319F28BDD81E23C3573398C44",
|
||||
"PreviousTxnLgrSeq": 38040457,
|
||||
"Sequence": 9,
|
||||
"TakerGets": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rPT74sUcTBTQhkHVD54WGncoqXEAMYbmH7",
|
||||
"value": "322.4"
|
||||
},
|
||||
"TakerPays": "80000000",
|
||||
"index":
|
||||
"0011C33FA959278D478E7A3811D7DBB9E43E1768E12538CD54B028E5E7DA96E5"
|
||||
}
|
||||
],
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
13
test/fixtures/rippled/subscribe_error.json
vendored
Normal file
13
test/fixtures/rippled/subscribe_error.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"id": 0,
|
||||
"status": "error",
|
||||
"type": "response",
|
||||
"error": "invalidParams",
|
||||
"error_code": 31,
|
||||
"error_message": "Invalid parameters.",
|
||||
"request": {
|
||||
"command": "subscribe",
|
||||
"id": 0,
|
||||
"streams": "validations"
|
||||
}
|
||||
}
|
||||
@@ -167,6 +167,15 @@ describe('http server integration tests', function() {
|
||||
result => assert.deepEqual(result.result, apiResponses.sign.normal)
|
||||
);
|
||||
|
||||
createTest(
|
||||
'sign',
|
||||
[{txJSON: apiRequests.sign.normal.txJSON},
|
||||
{keypair: {
|
||||
privateKey: '00ACCD3309DB14D1A4FC9B1DAE608031F4408C85C73EE05E035B7DC8B25840107A',
|
||||
publicKey: '02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8' }}],
|
||||
result => assert.deepEqual(result.result, apiResponses.sign.normal)
|
||||
);
|
||||
|
||||
createTest(
|
||||
'generateAddress',
|
||||
[{options: {entropy: random()}}],
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user