Compare commits

...

26 Commits
1.1.0 ... 1.2.1

Author SHA1 Message Date
Elliot Lee
8278dc5b5b Release 1.2.1 2019-03-23 15:50:26 -07:00
Elliot Lee
c90d486454 Update ripple-binary-codec to 0.2.1 to support tecKILLED 2019-03-23 15:12:22 -07:00
Elliot Lee
35f9b7ec8d Release 1.2.0 2019-03-19 01:28:42 -07:00
Elliot Lee
69e621af86 Remove coveralls from devDependencies 2019-03-19 01:21:36 -07:00
Elliot Lee
0e92e696d4 Remove unused http-server from devDependencies 2019-03-18 16:51:08 -07:00
Elliot Lee
0b1445bfe9 Remove sauce runner 2019-03-18 16:14:21 -07:00
Elliot Lee
db2d7ba1f5 Update mocha to 6.0.2 2019-03-18 16:09:26 -07:00
Elliot Lee
d82703f41b prepareTransaction should not overwrite Sequence (#990)
* Cleans up some code and fixes some type errors

* Clarify how null settings work

* Document updated RippledError

* Updates per review by @mDuo13
2019-03-18 15:55:42 -07:00
Elliot Lee
8213861ab7 Update HISTORY.md 2019-03-13 14:34:31 -07:00
Kincaid O'Neil
a842c380cf fix: add amount to FormattedPaymentChannel type (#989)
* fix: add amount to FormattedPaymentChannel type

* fix: ignore package-lock.json
2019-03-12 16:58:30 -07:00
Elliot Lee
5bf6f1849a Fix typos in docs 2019-03-12 15:27:19 -07:00
Elliot Lee
bfe4877f73 Merge remote-tracking branch 'origin/master' into develop 2019-03-12 15:12:58 -07:00
Elliot Lee
63dcddf6f4 [Docs] Update transaction responses link
List of transaction responses
2019-03-11 12:14:41 -07:00
Rome Reginelli
68735ddb35 Docs: Fix prepareTransaction method specification (#986) 2019-02-11 23:39:41 -08:00
Elliot Lee
1fd9ca7ef2 Use Buffer.from and clean up a few things (#985) 2019-02-07 00:29:59 -08:00
Elliot Lee
2445004333 Change prepare* methods to reject Promise on error (#984)
* Reject Promise on error, update docs, and add tests:
  * preparePayment
  * prepareTrustline
  * prepareOrder
  * prepareOrderCancellation
  * prepareSettings
  * prepareEscrowCreation
  * prepareEscrowExecution
  * prepareCheckCreate
  * prepareCheckCash
  * prepareCheckCancel
  * preparePaymentChannelCreate
  * preparePaymentChannelFund
  * preparePaymentChannelClaim

Note that we can't update mocha to ^5.2.0 because it causes testing to hang indefinitely; this needs to be investigated.
2019-01-29 15:22:18 -08:00
Elliot Lee
dc148bf954 Update HISTORY.md 2018-12-12 17:38:34 -08:00
Elliot Lee
f3c34bd75a Release 1.1.2 2018-12-12 14:55:15 -08:00
Alexandru Chiriac
5419e67dbc GetLedger by hash option (#980)
* update ledger input schema
* include ledgerHash option
2018-12-12 11:02:50 -08:00
Alexandru Chiriac
8d37da0952 Update Submit Response (#978)
* update submit output schema
* update submit response object
2018-12-04 15:35:07 -08:00
Elliot Lee
a8075d98df Add list of applications using ripple-lib (#976) 2018-11-29 16:39:48 -08:00
Elliot Lee
fcc205b85a Release 1.1.1 2018-11-27 15:17:42 -08:00
Elliot Lee
0f5056221f Fix getOrderbook (#970)
* Fix `getOrderbook` (Fix #766)
* Add `formatBidsAndAsks` as a recommended alternative to `getOrderbook`
* Add `renameCounterpartyToIssuer`
2018-11-26 15:25:15 -08:00
Elliot Lee
8384ace746 Add return type for generateAddress (#968)
For TypeScript apps
2018-11-20 15:35:34 -08:00
Elliot Lee
040cabece0 Add comments for accountRootFlags (#962) 2018-11-16 22:34:41 -08:00
Elliot Lee
319a8d6ab2 Fix book-offers test fixture by swapping bids/asks (#966) 2018-10-31 22:48:27 -07:00
75 changed files with 20636 additions and 1702 deletions

4
.gitignore vendored
View File

@@ -1,5 +1,9 @@
# .gitignore
# Ignore package locks other than Yarn.
package-lock.json
npm-shrinkwrap.json
# Ignore vim swap files.
*.swp

119
APPLICATIONS.md Normal file
View File

@@ -0,0 +1,119 @@
# Applications using ripple-lib (RippleAPI)
A curated list of some of the projects and apps that leverage `ripple-lib` in some way.
**Have one to add?** Please edit this file and open a PR!
## Notice (disclaimer)
These sites are independent of Ripple and have not been authorized, endorsed, sponsored or otherwise approved by Ripple or its affiliates.
Warning: Use at your own risk.
## Data and visualizations
- **[Wipple - XRP Intelligence](https://wipple.devnull.network/)**
Monitor the XRP Network in real time and explore historical statistics.
- **[XRP Charts](https://xrpcharts.ripple.com/)** (xrpcharts.ripple.com)
XRP Charts provides information based on public data, including trade volume, top markets, metrics, transactions, and more.
- **[Ripple Live](https://gatehub.net/live)** (gatehub.net/live)
Visualize XRP network transactions.
- **[XRPL Dev. Dashboard](https://xrp.fans/)** (xrp.fans)
Debugging dashboard for `rippled-ws-client-pool`, transaction and query explorer, and transaction signing and submission tool.
- **[XRP Value](http://xrpvalue.com/)**
Real-time XRP price, trades, and orderbook data from the XRP Ledger.
- **[Bithomp - XRPL validators](https://bithomp.com/validators)**
List of XRPL validators, nodes, and testnet validators.
## Send and request payments
- **[XRP Tip Bot](https://www.xrptipbot.com/)**
A bot that enables users on reddit, Twitter and Discord to send XRP to each other through reddit comments and Twitter tweets.
- **[XRP Text](https://xrptext.com/)**
Send XRP using SMS text messages.
- **[XRParrot](https://xrparrot.com/)** (uses `ripple-address-codec`)
Easy EUR (SEPA) to XRP transfer (currency conversion).
- **[XRP Payment](https://xrpayments.co/)** (xrpayments.co)
Tool for generating a XRP payment request URI in a QR code, with currency converter.
## Wallets and wallet tools
- **[Toast Wallet](https://toastwallet.com/)**
A free, open source XRP Wallet for iOS, Android, Windows, Mac and Linux.
- **[Toastify Ledger](https://github.com/WietseWind/toastify-ledger)** (uses `ripple-keypairs`)
Add a Regular Key to a mnemonic XRP Wallet (e.g. Ledger Nano S) to use the account with a Family Seed (secret).
- **[Bithomp-submit](https://github.com/Bithomp/bithomp-submit)** (GitHub)
A tool to submit an offline-signed XRPL transaction.
- **[Kyte](https://kyteapp.co/)** (kyteapp.co) ([Source](https://github.com/WietseWind/Zerp-Wallet)) (Deprecated)
Web-based XRP wallet.
- **[XRP Vanity Address Generator](https://github.com/WietseWind/xrp-vanity-generator)** (Node.js)
A vanity address is a wallet address containing a few characters you like at the beginning or the end of the wallet address.
- **[XRP Account Mnemonic Recovery](https://github.com/WietseWind/xrp-mnemonic-recovery)** (uses `ripple-keypairs`)
Recover a 24 word mnemonic if one word is wrong or one word is missing.
## Development tools
- **[XRP Test Net Faucet](https://developers.ripple.com/xrp-test-net-faucet.html)**
Get some test funds for development on the test network. The faucet was built using `ripple-lib`.
## Code samples and libraries
- **[ilp-plugin-xrp-paychan](https://github.com/interledgerjs/ilp-plugin-xrp-paychan)**
Send ILP payments using XRP and payment channels (PayChan).
- **[RunKit: WietseWind](https://runkit.com/wietsewind/)**
XRP Ledger code samples for Node.js.
- **[GitHub Gist: WietseWind](https://gist.github.com/WietseWind)**
XRP Ledger code samples for Node.js and the web (mostly).
- **[rippled-ws-client-sign](https://github.com/WietseWind/rippled-ws-client-sign)**
Sign transactions, with support for MultiSign.
- **[ILP-enabled power switch](https://xrpcommunity.blog/raspberry-pi-interledger-xp-powerswitch-howto/)** ([video](https://www.youtube.com/watch?v=c-eS0HQUuJg)) (uses [`moneyd-uplink-xrp`](https://github.com/interledgerjs/moneyd-uplink-xrp))
For about $30 in parts (Raspberry Pi, 3.3V Relay board and a few wires) you can build your own power switch that will switch on if a streaming ILP payment comes in. When the payment stream stops, the power turns off.
## Related apps that do not appear to use ripple-lib
- **[XRP Stats](https://ledger.exposed/)** (ledger.exposed)
Rich list, live ledger stats and XRP distribution. Visualize escrows and flow of funds.
- **[XRP Vanity](https://xrpvanity.com/)** (xrpvanity.com)
Custom XRP addresses for sale, delivered by SetRegularKey.

View File

@@ -1,5 +1,189 @@
# ripple-lib Release History
## 1.2.1 (2019-03-23)
* Update `ripple-binary-codec` to 0.2.1 to support `tecKILLED`
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
531c2a8f4bf6d6b5bd4afe6a40b6a68a77179a343902cfa4210d7e35b5697af0 ripple-1.2.1-debug.js
201ee99922b16b7e32afb5317ef4bb9facc23b20c272bb5c4ed7010f5d996cab ripple-1.2.1-min.js
c1b984581299bf00e0e3c8ac4e62eadfc9b190bd78a2458a76e59ceb56046148 ripple-1.2.1.js
```
## 1.2.0 (2019-03-19)
This release:
* changes the way you handle errors for the `prepare*` methods.
* improves the `message` field of `RippledError`s.
* allows `Sequence` to be set in the transaction JSON provided to
`prepareTransaction`.
For details, continue reading:
### [BREAKING CHANGE] `prepare*` methods reject the Promise on error
The `prepare*` methods now always reject the Promise when an error occurs, instead of throwing.
Previously, the methods would synchronously throw on validation errors, despite being asynchronous methods that return Promises.
In other words, to handle errors in the past, you would need to use a try/catch block:
```
// OBSOLETE - no need for try/catch anymore
try {
api.preparePayment(address, payment, instructions).then(prepared => {
res.send(prepared.txJSON);
}).catch(error => {
// Handle asynchronous error
});
} catch (error) {
// Handle synchronous error
}
```
Now, you can rely on the Promise's `catch` handler, which is called with the error when the Promise is rejected:
```
api.preparePayment(address, payment, instructions).then(prepared => {
res.send(prepared.txJSON);
}).catch(error => {
// Handle error
});
```
This applies to:
* preparePayment
* prepareTrustline
* prepareOrder
* prepareOrderCancellation
* prepareSettings
* prepareEscrowCreation
* prepareEscrowExecution
* prepareCheckCreate
* prepareCheckCash
* prepareCheckCancel
* preparePaymentChannelCreate
* preparePaymentChannelClaim
* preparePaymentChannelFund
### Improved `RippledError` `message`
Previously, `RippledErrors` (errors from rippled) used rippled's `error` field as the `message`.
Now, the `error_message` field is used as the `message`.
This helps to surface the specific cause of an error.
For example, before:
```
[RippledError(invalidParams, { error: 'invalidParams',
error_code: 31,
error_message: 'Missing field \'account\'.',
id: 3,
request: { command: 'account_info', id: 3 },
status: 'error',
type: 'response' })]
```
After:
```
[RippledError(Missing field 'account'., { error: 'invalidParams',
error_code: 31,
error_message: 'Missing field \'account\'.',
id: 3,
request: { command: 'account_info', id: 3 },
status: 'error',
type: 'response' })]
```
In this case, you can see at a glance that `account` is the missing field.
The `error` field is still available in `errorObject.data.error`.
When `error_message` is not set (as with e.g. error 'entryNotFound'), the `error` field is used as the `message`.
### [BUG FIX] `prepareTransaction` does not overwrite the `Sequence` field
The `prepareTransaction` method now allows `Sequence` to be set in the Transaction JSON object, instead of overwriting it with the account's expected sequence based on the state of the ledger.
Previously, you had to use the `sequence` field in the `instructions` object to manually set a transaction's sequence number.
### New in rippled 1.2.1
As this is the first release of ripple-lib following the release of rippled 1.2.1, we would like to highlight the following API improvements:
1. The [`delivered_amount` field](https://developers.ripple.com/partial-payments.html#the-delivered-amount-field) has been added to the `ledger` method, and to transaction subscriptions.
api.getLedger({includeTransactions: true, includeAllData: true, ledgerVersion: 17718771}).then(...)
You can also call `ledger` directly:
request('ledger', {...}).then(...)
2. [Support for Ed25519 seeds encoded using ripple-lib](https://github.com/ripple/rippled/pull/2734)
You have access to these improvements when you use a rippled server running version 1.2.1 or later. At the time of writing, we recommend using rippled version **1.2.2** or later.
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
13021fe3efbdd59faf68597b0b18204b39847b285cca82f84c737e3d19922cc2 ripple-1.2.0-debug.js
0070225e731afd8c2c0a0976111ebf326c19a96ee1549368de9f016abdd53d2f ripple-1.2.0-min.js
d440268397c03ad5137a3294e53a07b959ef93cd23b1990d6f82621c4776ba9f ripple-1.2.0.js
```
## 1.1.2 (2018-12-12)
+ Update `submit` response (#978)
+ Includes the full object returned by rippled, while keeping the existing
fields for backward compatibility
+ Add `getLedger` option for ledger hash (#980)
+ Use the `ledgerHash` option to get a specific ledger by hash
Thanks to @alexchiriac for the contributions in this release.
When using `ripple-lib` with `rippled`, we recommend using `rippled` version
1.1.2 or later.
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
e6cc52395d0c3e205263777ba2e528e50f4d1f84bb4b16763a3bf7f5fcc290f5 ripple-1.1.2-debug.js
82df879bc2970e0e4fd161975a99448b4859b0cde751d8ea34e9f51d672090b9 ripple-1.1.2-min.js
12f56330dc71bba8ac3004025cbc9698413a0c619df302dda105b31228a67319 ripple-1.1.2.js
```
## 1.1.1 (2018-11-27)
+ Fix `getOrderbook` offer sorting (#970)
+ **BREAKING CHANGE:** The ordering of offers returned by `getOrderbook` has
been changed so that offers with the best quality are sorted first
+ Add new helper methods for working with the `rippled` APIs:
+ `formatBidsAndAsks`: Takes offers and returns a formatted order book object
with bids and asks
+ `renameCounterpartyToIssuer`: Takes an object and renames the `counterparty`
field to `issuer`
+ TypeScript: Add return type for `generateAddress` (#968)
When using `ripple-lib` with `rippled`, we recommend using `rippled` version 1.1.1 or
later.
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
e151900e49bb5482b02bef5b0b1542ea586076363b072ae616f6d4d2f7f5b8a1 ripple-1.1.1-debug.js
6aee3757b29de285f361e20862261090033c07a13fd09f4a3cc4c097b6e84b55 ripple-1.1.1-min.js
bea4a889fb9ee4092324c6667490ea66469bdde869ddc1aaddf5e9d12b0cf091 ripple-1.1.1.js
```
## 1.1.0 (2018-10-31)
+ Add support for Node.js v10 LTS (#964)

View File

@@ -7,8 +7,8 @@ A JavaScript API for interacting with the XRP Ledger
### Features
+ Connect to a `rippled` server from Node.js or a web browser
+ Issue [rippled API](https://ripple.com/build/rippled-apis/) requests
+ Listen to events on the XRP Ledger (transaction, ledger, etc.)
+ Helpers for creating requests and parsing responses for the [rippled API](https://developers.ripple.com/rippled-api.html)
+ Listen to events on the XRP Ledger (transactions, ledger, validations, etc.)
+ Sign and submit transactions to the XRP Ledger
+ Type definitions for TypeScript
@@ -30,6 +30,8 @@ $ 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).
**What is ripple-lib used for?** Here's a [list of applications](APPLICATIONS.md) that use `ripple-lib`. Open a PR to add your app or project to the list!
### Mailing Lists
We have a low-traffic mailing list for announcements of new ripple-lib releases. (About 1 email per week)
@@ -56,7 +58,7 @@ $ yarn build
Gulp will [output](./Gulpfile.js) the resulting JS files in `./build/`.
For more details, see the `scripts` in `package.json`.
For details, see the `scripts` in `package.json`.
## Running Tests
@@ -64,12 +66,12 @@ For more details, see the `scripts` in `package.json`.
2. `cd` into the repository and install dependencies with `yarn install`
3. `yarn test`
Also, run `yarn lint` to lint the code with `tslint`.
## Generating Documentation
The continuous integration tests require that the documentation stays up-to-date. If you make changes to the JSON schemas, fixtures, or documentation sources, you must update the documentation by running `yarn run docgen`.
`npm` may be used instead of `yarn` in the commands above.
## More Information
+ [Ripple Developer Center](https://ripple.com/build/)

View File

@@ -38,6 +38,9 @@
- [request](#request)
- [hasNextPage](#hasnextpage)
- [requestNextPage](#requestnextpage)
- [Static Methods](#static-methods)
- [renameCounterpartyToIssuer](#renamecounterpartytoissuer)
- [formatBidsAndAsks](#formatbidsandasks)
- [API Methods](#api-methods)
- [connect](#connect)
- [disconnect](#disconnect)
@@ -290,7 +293,7 @@ Type | Description
[escrowCancellation](#escrow-cancellation) | An `escrowCancellation` transaction unlocks the funds in an escrow and sends them back to the creator of the escrow, but it will only work after the escrow expires.
[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.
[checkCancel](#check-cancel) | A `checkCancel` transaction cancels an unredeemed Check, removing it from the ledger without sending any money.
[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.
@@ -336,7 +339,7 @@ maxLedgerVersionOffset | integer | *Optional* Offset from current validated ledg
sequence | [sequence](#account-sequence-number) | *Optional* The initiating account's sequence number for this transaction.
signersCount | integer | *Optional* Number of signers that will be signing this transaction.
We 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.
We recommend that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeed 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
@@ -950,6 +953,326 @@ return api.request(command, params).then(response => {
}).catch(console.error);
```
# Static Methods
## renameCounterpartyToIssuer
`renameCounterpartyToIssuer(issue: {currency: string, counterparty: address}): {currency: string, issuer: address}`
Returns an object with the `counterparty` field renamed to `issuer`. This is useful because RippleAPI generally uses the name `counterparty` while the rippled API generally uses the name `issuer`.
This is a static method on the `RippleAPI` class.
### Parameters
This method takes one parameter, an object with a `counterparty` field.
### Return Value
This method returns a new object similar to the source object, but with `issuer` instead of `counterparty`.
### Example
```javascript
const orderbookInfo = {
"base": {
"currency": "USD",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counter": {
"currency": "BTC",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
};
console.log(RippleAPI.renameCounterpartyToIssuer(orderbookInfo.base))
console.log(RippleAPI.renameCounterpartyToIssuer(orderbookInfo.counter))
```
```
{ currency: 'USD', issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B' }
{ currency: 'BTC', issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B' }
```
## formatBidsAndAsks
`formatBidsAndAsks(orderbookInfo: {base: Issue, counter: Issue}, offers: BookOffer[]): orderbook`
Returns formatted bids and asks, which make up an orderbook.
This is a static method on the `RippleAPI` class.
### Parameters
This method takes two parameters.
1. An `OrderbookInfo` object: `{ base: Issue, counter: Issue }`.
2. An array of `BookOffer` objects.
### Return Value
This method returns an object with two properties: `bids` and `asks`, each of which is an array of bids (buy orders) or asks (sell orders), respectively. (Note: the structures of `bids` and `asks` are identical.)
Object structure:
Name | Type | Description
---- | ---- | -----------
bids | array | The buy orders in the order book.
bids[] | object | An order in the order book.
*bids[].* specification | [order](#order) | An order specification that would create an order equivalent to the current state of this order.
*bids[].* properties | object | Properties of the order not in the specification.
*bids[].properties.* maker | [address](#address) | The address of the account that submitted the order.
*bids[].properties.* sequence | [sequence](#account-sequence-number) | The account sequence number of the transaction that created this order.
*bids[].properties.* makerExchangeRate | [value](#value) | The exchange rate from the point of view of the account that submitted the order (also known as "quality").
*bids[].data.* \* | object |
*bids[].* state | object | *Optional* The state of the order.
*bids[].state.* fundedAmount | [amount](#amount) | How much of the amount the maker would have to pay that the maker currently holds.
*bids[].state.* priceOfFundedAmount | [amount](#amount) | How much the `fundedAmount` would convert to through the exchange rate of this order.
asks | array | The sell orders in the order book.
asks[] | object | An order in the order book.
*asks[].* specification | [order](#order) | An order specification that would create an order equivalent to the current state of this order.
*asks[].* properties | object | Properties of the order not in the specification.
*asks[].properties.* maker | [address](#address) | The address of the account that submitted the order.
*asks[].properties.* sequence | [sequence](#account-sequence-number) | The account sequence number of the transaction that created this order.
*asks[].properties.* makerExchangeRate | [value](#value) | The exchange rate from the point of view of the account that submitted the order (also known as "quality").
*asks[].data.* \* | object |
*asks[].* state | object | *Optional* The state of the order.
*asks[].state.* fundedAmount | [amount](#amount) | How much of the amount the maker would have to pay that the maker currently holds.
*asks[].state.* priceOfFundedAmount | [amount](#amount) | How much the `fundedAmount` would convert to through the exchange rate of this order.
**Raw order data:** 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
const orderbookInfo = {
"base": {
"currency": "USD",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counter": {
"currency": "BTC",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
};
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return Promise.all(
[
this.api.request('book_offers', {
taker_gets: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.base),
taker_pays: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.counter),
ledger_index: 'validated',
limit: 20,
taker: address
}),
this.api.request('book_offers', {
taker_gets: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.counter),
taker_pays: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.base),
ledger_index: 'validated',
limit: 20,
taker: address
})
]
).then((directOfferResults, reverseOfferResults) => {
const directOffers = (directOfferResults ? directOfferResults : []).reduce((acc, res) => acc.concat(res.offers), [])
const reverseOffers = (reverseOfferResults ? reverseOfferResults : []).reduce((acc, res) => acc.concat(res.offers), [])
const orderbook = RippleAPI.formatBidsAndAsks(orderbookInfo, [...directOffers, ...reverseOffers]);
console.log(JSON.stringify(orderbook, null, 2));
});
```
```
{
"bids": [
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "0.71800168",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00016708342",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"sequence": 262660,
"makerExchangeRate": "4297.264683713081"
},
"data": {
"Account": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98580F4456E6FA8239",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "000000000000001D",
"PreviousTxnID": "16D75506C6317723FC03543130B5E0AAB13E8AD22514C1DB098BE05771C90447",
"PreviousTxnLgrSeq": 43127860,
"Sequence": 262660,
"TakerGets": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00016708342"
},
"TakerPays": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.71800168"
},
"index": "DE877FB94EF892A4BCC58DB8CDE063D97AB5133201905DE6C8650B5DEA19E11B",
"owner_funds": "0.03358376764081196",
"quality": "4297.264683713081"
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "1.6770875",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00038681218",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"sequence": 231459,
"makerExchangeRate": "4335.663628792661"
},
"data": {
"Account": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98580F67435A75B355",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000001",
"PreviousTxnID": "F049EAFDDDA7B99970F77533743D95C9E12A16FE6C56215A0B09C32C4D23163F",
"PreviousTxnLgrSeq": 43127094,
"Sequence": 231459,
"TakerGets": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00038681218"
},
"TakerPays": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "1.6770875"
},
"index": "3B314A51BD57601CA1509834DF9462037BF4B05AFCC1E1EFD334DB4E2D7B2AA6",
"owner_funds": "0.03906802968738533",
"quality": "4335.663628792661"
}
},
// ... trimmed for brevity ...
],
"asks": [
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.71085738",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00016876265",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"sequence": 262664,
"makerExchangeRate": "0.0002374071856720401"
},
"data": {
"Account": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A451086F34ADB0EA11",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "000000000000001D",
"PreviousTxnID": "54CE0B2783AF973718FAFA35E864A3C172BE488EBBB6F2852611C6DAC8893BDF",
"PreviousTxnLgrSeq": 43127875,
"Sequence": 262664,
"TakerGets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.71085738"
},
"TakerPays": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00016876265"
},
"index": "2D4ED103D6B3FEFA21BC385C53B63359F5678E5AA5429DDE6E1D8FE8B41CD6A8",
"owner_funds": "142.8821425048244",
"quality": "0.0002374071856720401"
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "1.6438778",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00039462656",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"sequence": 231483,
"makerExchangeRate": "0.0002400583303698121"
},
"data": {
"Account": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4510887515B1216C9",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000001",
"PreviousTxnID": "6FA370F52C45F6149482156FF7B4226713AECE991FB7D053F74172CB0B8F24E9",
"PreviousTxnLgrSeq": 43127158,
"Sequence": 231483,
"TakerGets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "1.6438778"
},
"TakerPays": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00039462656"
},
"index": "735F9661AD006BA0776859BE371D445555FC0815604603AC056469C16AC84AE3",
"owner_funds": "166.0316626329364",
"quality": "0.0002400583303698121"
}
},
// ... trimmed for brevity ...
]
}
```
# API Methods
## connect
@@ -1171,7 +1494,7 @@ sequence | [sequence](#account-sequence-number) | The account sequence number of
type | [transactionType](#transaction-types) | The type of the transaction.
specification | object | A specification that would produce the same outcome as this transaction. *Exception:* For payment transactions, this omits the `destination.amount` field, to prevent misunderstanding. The structure of the specification depends on the value of the `type` field (see [Transaction Types](#transaction-types) for details). *Note:* This is **not** necessarily the same as the original specification.
outcome | object | The outcome of the transaction (what effects it had).
*outcome.* result | string | Result code returned by rippled. See [Transaction Results](https://ripple.com/build/transactions/#full-transaction-response-list) for a complete list.
*outcome.* result | string | Result code returned by rippled. See [Transaction Results](https://developers.ripple.com/transaction-results.html) for a complete list.
*outcome.* fee | [value](#value) | The XRP fee that was charged for the transaction.
*outcome.balanceChanges.* \* | array\<[balance](#amount)\> | Key is the XRP Ledger address; value is an array of signed amounts representing changes of balances for that address.
*outcome.orderbookChanges.* \* | array | Key is the maker's XRP Ledger address; value is an array of changes
@@ -2442,6 +2765,10 @@ return api.getOrders(address).then(orders =>
Returns open orders for the specified account. Open orders are orders that have not yet been fully executed and are still in the order book.
**Breaking change:** In ripple-lib 1.1.0 and earlier, orders returned by this method were not sorted correctly. Orders are now sorted correctly, from best to worst.
**See also:** An alternative way to get orderbooks is with `request` and [`formatBidsAndAsks`](#formatbidsandasks).
### Parameters
Name | Type | Description
@@ -2484,9 +2811,7 @@ asks[] | object | An order in the order book.
*asks[].state.* fundedAmount | [amount](#amount) | How much of the amount the maker would have to pay that the maker currently holds.
*asks[].state.* priceOfFundedAmount | [amount](#amount) | How much the `fundedAmount` would convert to through the exchange rate of this order.
### 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.
**Raw order data:** 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).
@@ -4062,6 +4387,7 @@ options | object | *Optional* Options affecting what ledger and how much data to
*options.* includeAllData | boolean | *Optional* Include full transactions and/or state information if `includeTransactions` and/or `includeState` is set.
*options.* includeState | boolean | *Optional* Return an array of hashes for all state data or an array of all state data in this ledger version, depending on whether `includeAllData` is set.
*options.* includeTransactions | boolean | *Optional* Return an array of hashes for each transaction or an array of all transactions that were validated in this ledger version, depending on whether `includeAllData` is set.
*options.* ledgerHash | string | *Optional* Get ledger data for this historical ledger hash.
*options.* ledgerVersion | integer | *Optional* Get ledger data for this historical ledger version.
*options.* ledgerVersion | string | *Optional* Get ledger data for this historical ledger version.
@@ -4149,7 +4475,7 @@ console.log(JSON.stringify(flags, null, 2))
## prepareTransaction
`prepareTransaction(address: string, transaction: object, instructions: object): Promise<object>`
`prepareTransaction(transaction: object, instructions: object): Promise<object>`
Prepare a transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
@@ -4258,8 +4584,11 @@ const payment = {
}
}
};
return api.preparePayment(address, payment).then(prepared =>
{/* ... */});
return api.preparePayment(address, payment).then(prepared => {
/* ... */
}).catch(error => {
/* ... as with all prepare* methods, use a Promise catch block to handle errors ... */
})
```
@@ -5156,8 +5485,13 @@ This method returns an object with the following structure:
Name | Type | Description
---- | ---- | -----------
resultCode | string | The result code returned by rippled. [List of transaction responses](https://ripple.com/build/transactions/#full-transaction-response-list)
resultMessage | string | Human-readable explanation of the status of the transaction.
resultCode | string | Deprecated: Use `engine_result` instead.
resultMessage | string | Deprecated: Use `engine_result_message` instead.
engine_result | string | Code indicating the preliminary result of the transaction, for example `tesSUCCESS`. [List of transaction responses](https://developers.ripple.com/transaction-results.html)
engine_result_code | integer | Numeric code indicating the preliminary result of the transaction, directly correlated to `engine_result`
engine_result_message | string | Human-readable explanation of the transaction's preliminary result.
tx_blob | string | The complete transaction in hex string format.
tx_json | [tx-json](https://developers.ripple.com/transaction-formats.html) | The complete transaction in JSON format.
### Example
@@ -5171,7 +5505,27 @@ return api.submit(signedTransaction)
```json
{
"resultCode": "tesSUCCESS",
"resultMessage": "The transaction was applied. Only final in a validated ledger."
"resultMessage": "The transaction was applied. Only final in a validated ledger.",
"engine_result": "tesSUCCESS",
"engine_result_code": 0,
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
"tx_blob": "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754",
"tx_json": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": {
"currency": "USD",
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"value": "1"
},
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "10000",
"Flags": 2147483648,
"Sequence": 360,
"SigningPubKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
"TransactionType": "Payment",
"TxnSignature": "304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F8580",
"hash": "4D5D90890F8D49519E4151938601EF3D0B30B16CD6A519D9C99102C9FA77F7E0"
}
}
```

View File

@@ -0,0 +1,254 @@
## formatBidsAndAsks
`formatBidsAndAsks(orderbookInfo: {base: Issue, counter: Issue}, offers: BookOffer[]): orderbook`
Returns formatted bids and asks, which make up an orderbook.
This is a static method on the `RippleAPI` class.
### Parameters
This method takes two parameters.
1. An `OrderbookInfo` object: `{ base: Issue, counter: Issue }`.
2. An array of `BookOffer` objects.
### Return Value
This method returns an object with two properties: `bids` and `asks`, each of which is an array of bids (buy orders) or asks (sell orders), respectively. (Note: the structures of `bids` and `asks` are identical.)
Object structure:
<%- renderSchema('output/get-orderbook.json') %>
**Raw order data:** 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
const orderbookInfo = {
"base": {
"currency": "USD",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counter": {
"currency": "BTC",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
};
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return Promise.all(
[
this.api.request('book_offers', {
taker_gets: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.base),
taker_pays: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.counter),
ledger_index: 'validated',
limit: 20,
taker: address
}),
this.api.request('book_offers', {
taker_gets: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.counter),
taker_pays: RippleAPI.renameCounterpartyToIssuer(orderbookInfo.base),
ledger_index: 'validated',
limit: 20,
taker: address
})
]
).then((directOfferResults, reverseOfferResults) => {
const directOffers = (directOfferResults ? directOfferResults : []).reduce((acc, res) => acc.concat(res.offers), [])
const reverseOffers = (reverseOfferResults ? reverseOfferResults : []).reduce((acc, res) => acc.concat(res.offers), [])
const orderbook = RippleAPI.formatBidsAndAsks(orderbookInfo, [...directOffers, ...reverseOffers]);
console.log(JSON.stringify(orderbook, null, 2));
});
```
```
{
"bids": [
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "0.71800168",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00016708342",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"sequence": 262660,
"makerExchangeRate": "4297.264683713081"
},
"data": {
"Account": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98580F4456E6FA8239",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "000000000000001D",
"PreviousTxnID": "16D75506C6317723FC03543130B5E0AAB13E8AD22514C1DB098BE05771C90447",
"PreviousTxnLgrSeq": 43127860,
"Sequence": 262660,
"TakerGets": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00016708342"
},
"TakerPays": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.71800168"
},
"index": "DE877FB94EF892A4BCC58DB8CDE063D97AB5133201905DE6C8650B5DEA19E11B",
"owner_funds": "0.03358376764081196",
"quality": "4297.264683713081"
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "1.6770875",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00038681218",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"sequence": 231459,
"makerExchangeRate": "4335.663628792661"
},
"data": {
"Account": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"BookDirectory": "6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98580F67435A75B355",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000001",
"PreviousTxnID": "F049EAFDDDA7B99970F77533743D95C9E12A16FE6C56215A0B09C32C4D23163F",
"PreviousTxnLgrSeq": 43127094,
"Sequence": 231459,
"TakerGets": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00038681218"
},
"TakerPays": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "1.6770875"
},
"index": "3B314A51BD57601CA1509834DF9462037BF4B05AFCC1E1EFD334DB4E2D7B2AA6",
"owner_funds": "0.03906802968738533",
"quality": "4335.663628792661"
}
},
// ... trimmed for brevity ...
],
"asks": [
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.71085738",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00016876265",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"sequence": 262664,
"makerExchangeRate": "0.0002374071856720401"
},
"data": {
"Account": "rUKoQ1Zhn6c8EfPsaVa2Yx5NqaKN1JQSvq",
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A451086F34ADB0EA11",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "000000000000001D",
"PreviousTxnID": "54CE0B2783AF973718FAFA35E864A3C172BE488EBBB6F2852611C6DAC8893BDF",
"PreviousTxnLgrSeq": 43127875,
"Sequence": 262664,
"TakerGets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.71085738"
},
"TakerPays": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00016876265"
},
"index": "2D4ED103D6B3FEFA21BC385C53B63359F5678E5AA5429DDE6E1D8FE8B41CD6A8",
"owner_funds": "142.8821425048244",
"quality": "0.0002374071856720401"
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "1.6438778",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "0.00039462656",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"sequence": 231483,
"makerExchangeRate": "0.0002400583303698121"
},
"data": {
"Account": "rpmL45YbZWKgp8AH8EjBSknWo5c8dNuuBM",
"BookDirectory": "20294C923E80A51B487EB9547B3835FD483748B170D2D0A4510887515B1216C9",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000001",
"PreviousTxnID": "6FA370F52C45F6149482156FF7B4226713AECE991FB7D053F74172CB0B8F24E9",
"PreviousTxnLgrSeq": 43127158,
"Sequence": 231483,
"TakerGets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "1.6438778"
},
"TakerPays": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0.00039462656"
},
"index": "735F9661AD006BA0776859BE371D445555FC0815604603AC056469C16AC84AE3",
"owner_funds": "166.0316626329364",
"quality": "0.0002400583303698121"
}
},
// ... trimmed for brevity ...
]
}
```

View File

@@ -4,6 +4,10 @@
Returns open orders for the specified account. Open orders are orders that have not yet been fully executed and are still in the order book.
**Breaking change:** In ripple-lib 1.1.0 and earlier, orders returned by this method were not sorted correctly. Orders are now sorted correctly, from best to worst.
**See also:** An alternative way to get orderbooks is with `request` and [`formatBidsAndAsks`](#formatbidsandasks).
### Parameters
<%- renderSchema('input/get-orderbook.json') %>
@@ -14,9 +18,7 @@ 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.
**Raw order data:** 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).

View File

@@ -8,6 +8,11 @@
<% include request.md.ejs %>
<% include hasNextPage.md.ejs %>
<% include requestNextPage.md.ejs %>
<% include staticMethods.md.ejs %>
<% include renameCounterpartyToIssuer.md.ejs %>
<% include formatBidsAndAsks.md.ejs %>
<% include methods.md.ejs %>
<% include connect.md.ejs %>
<% include disconnect.md.ejs %>

View File

@@ -23,8 +23,11 @@ All "prepare*" methods have the same return type.
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const payment = <%- importFile('test/fixtures/requests/prepare-payment.json') %>;
return api.preparePayment(address, payment).then(prepared =>
{/* ... */});
return api.preparePayment(address, payment).then(prepared => {
/* ... */
}).catch(error => {
/* ... as with all prepare* methods, use a Promise catch block to handle errors ... */
})
```
<%- renderFixture("responses/prepare-payment.json") %>

View File

@@ -1,6 +1,6 @@
## prepareTransaction
`prepareTransaction(address: string, transaction: object, instructions: object): Promise<object>`
`prepareTransaction(transaction: object, instructions: object): Promise<object>`
Prepare a transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).

View File

@@ -0,0 +1,37 @@
## renameCounterpartyToIssuer
`renameCounterpartyToIssuer(issue: {currency: string, counterparty: address}): {currency: string, issuer: address}`
Returns an object with the `counterparty` field renamed to `issuer`. This is useful because RippleAPI generally uses the name `counterparty` while the rippled API generally uses the name `issuer`.
This is a static method on the `RippleAPI` class.
### Parameters
This method takes one parameter, an object with a `counterparty` field.
### Return Value
This method returns a new object similar to the source object, but with `issuer` instead of `counterparty`.
### Example
```javascript
const orderbookInfo = {
"base": {
"currency": "USD",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counter": {
"currency": "BTC",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
};
console.log(RippleAPI.renameCounterpartyToIssuer(orderbookInfo.base))
console.log(RippleAPI.renameCounterpartyToIssuer(orderbookInfo.counter))
```
```
{ currency: 'USD', issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B' }
{ currency: 'BTC', issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B' }
```

View File

@@ -0,0 +1 @@
# Static Methods

View File

@@ -15,7 +15,7 @@ Type | Description
[escrowCancellation](#escrow-cancellation) | An `escrowCancellation` transaction unlocks the funds in an escrow and sends them back to the creator of the escrow, but it will only work after the escrow expires.
[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.
[checkCancel](#check-cancel) | A `checkCancel` transaction cancels an unredeemed Check, removing it from the ledger without sending any money.
[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.
@@ -53,7 +53,7 @@ Transaction instructions indicate how to execute a transaction, complementary wi
<%- renderSchema("objects/instructions.json") %>
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.
We recommend that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeed 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

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "1.1.0",
"version": "1.2.1",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [
@@ -23,8 +23,8 @@
"jsonschema": "1.2.2",
"lodash": "^4.17.4",
"ripple-address-codec": "^2.0.1",
"ripple-binary-codec": "0.2.0",
"ripple-hashes": "^0.3.1",
"ripple-binary-codec": "0.2.1",
"ripple-hashes": "0.3.2",
"ripple-keypairs": "^0.10.1",
"ripple-lib-transactionparser": "0.7.1",
"ws": "^3.3.1"
@@ -32,19 +32,16 @@
"devDependencies": {
"@types/node": "^8.0.53",
"assert-diff": "^1.0.1",
"coveralls": "^2.13.1",
"doctoc": "^0.15.0",
"ejs": "^2.3.4",
"eventemitter2": "^0.4.14",
"gulp": "^3.8.10",
"gulp-bump": "^0.1.13",
"gulp-rename": "^1.2.0",
"http-server": "^0.8.5",
"jayson": "^1.2.2",
"json-loader": "^0.5.2",
"json-schema-to-markdown-table": "^0.4.0",
"mocha": "^2.1.0",
"mocha-in-sauce": "^0.0.1",
"mocha": "6.0.2",
"mocha-junit-reporter": "^1.9.1",
"null-loader": "^0.1.1",
"nyc": "^11.3.0",
@@ -66,8 +63,7 @@
"compile": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/ && tsc",
"watch": "tsc -w",
"prepublish": "npm run clean && npm run compile && npm run build",
"test": "nyc mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"test": "nyc mocha --exit",
"lint": "tslint -p ./",
"perf": "./scripts/perf_test.sh",
"start": "node scripts/http.js",

View File

@@ -16,7 +16,7 @@ unittest() {
# test "src"
mocha test --reporter mocha-junit-reporter --reporter-options mochaFile=$CIRCLE_TEST_REPORTS/test-results.xml
yarn test --coverage
yarn run coveralls
#yarn run coveralls
# test compiled version in "dist/npm"
$(npm bin)/babel -D --optional runtime --ignore "**/node_modules/**" -d test-compiled/ test/

View File

@@ -1,100 +0,0 @@
const _ = require('lodash');
const MochaSauce = require('mocha-in-sauce');
const testUrl = 'http://testripple.circleci.com:8080/test/saucerunner.html';
function main() {
// uncomment for more debug info
// process.env.DEBUG = '*';
// configure
const config = {
name: 'RippleAPI',
host: 'localhost',
port: 4445,
maxDuration: 180000,
// the current build name (optional)
build: Date.now(),
url: testUrl,
runSauceConnect: true
};
if (process.env.CIRCLE_BUILD_NUM) {
config.build = process.env.CIRCLE_BUILD_NUM;
config.tags = [process.env.CIRCLE_BRANCH, process.env.CIRCLE_SHA1];
config.tunnelIdentifier = process.env.CIRCLE_BUILD_NUM;
}
const sauce = new MochaSauce(config);
sauce.concurrency(5);
// setup what browsers to test with
sauce.browser({browserName: 'firefox', platform: 'Linux',
version: '43'});
sauce.browser({browserName: 'firefox', platform: 'Windows 8.1',
version: '43'});
sauce.browser({browserName: 'firefox', platform: 'OS X 10.11',
version: '43'});
sauce.browser({browserName: 'safari', platform: 'OS X 10.11',
version: '9'});
sauce.browser({browserName: 'safari', platform: 'OS X 10.10',
version: '8'});
sauce.browser({browserName: 'safari', platform: 'OS X 10.9',
version: '7'});
sauce.browser({browserName: 'chrome', platform: 'OS X 10.11',
version: '47'});
sauce.browser({browserName: 'chrome', platform: 'Linux',
version: '47'});
sauce.browser({browserName: 'chrome', platform: 'Windows 8.1',
version: '47'});
sauce.browser({browserName: 'internet explorer', platform: 'Windows 10',
version: '11'});
sauce.browser({browserName: 'MicrosoftEdge', platform: 'Windows 10',
version: '20'});
sauce.on('init', function(browser) {
console.log(' init : %s %s', browser.browserName, browser.platform);
});
sauce.on('start', function(browser) {
console.log(' start : %s %s', browser.browserName, browser.platform);
});
sauce.on('end', function(browser, res) {
console.log(' end : %s %s : %d failures', browser.browserName,
browser.platform, res && res.failures);
});
sauce.on('connected', sauceConnectProcess => {
sauceConnectProcess.on('exit', function(code, /* signal */) {
if (code > 0) {
console.log('something wrong - exiting');
process.exit();
} else {
console.log('normal tunnel exit');
}
});
});
sauce.start(function(err, res) {
let failure = false;
if (err) {
console.log('Error starting Sauce');
console.error(err);
process.exitCode = 2;
} else {
console.log('-------------- done --------------');
failure = _.some(res, 'failures');
console.log('Tests are failed:', failure);
if (failure) {
process.exitCode = 1;
}
}
});
}
main();

View File

@@ -22,7 +22,8 @@ import getBalances from './ledger/balances'
import getBalanceSheet from './ledger/balance-sheet'
import getPaths from './ledger/pathfind'
import getOrders from './ledger/orders'
import getOrderbook from './ledger/orderbook'
import {getOrderbook,
formatBidsAndAsks} from './ledger/orderbook'
import {getSettings, parseAccountFlags} from './ledger/settings'
import getAccountInfo from './ledger/accountinfo'
import getAccountObjects from './ledger/accountobjects'
@@ -69,8 +70,8 @@ import * as ledgerUtils from './ledger/utils'
import * as transactionUtils from './transaction/utils'
import * as schemaValidator from './common/schema-validator'
import {getServerInfo, getFee} from './common/serverinfo'
import {clamp} from './ledger/utils'
import {Instructions, Prepare} from './transaction/types'
import {clamp, renameCounterpartyToIssuer} from './ledger/utils'
import {TransactionJSON, Instructions, Prepare} from './transaction/types'
export type APIOptions = {
server?: string,
@@ -114,6 +115,9 @@ class RippleAPI extends EventEmitter {
schemaValidator
}
static renameCounterpartyToIssuer = renameCounterpartyToIssuer
static formatBidsAndAsks = formatBidsAndAsks
constructor(options: APIOptions = {}) {
super()
validate.apiOptions(options)
@@ -206,7 +210,7 @@ class RippleAPI extends EventEmitter {
*
* You can later submit the transaction with `submit()`.
*/
async prepareTransaction(txJSON: object, instructions: Instructions = {}):
async prepareTransaction(txJSON: TransactionJSON, instructions: Instructions = {}):
Promise<Prepare> {
return transactionUtils.prepareTransaction(txJSON, this, instructions)
}
@@ -295,8 +299,8 @@ class RippleAPI extends EventEmitter {
getBalances = getBalances
getBalanceSheet = getBalanceSheet
getPaths = getPaths
getOrders = getOrders
getOrderbook = getOrderbook
getOrders = getOrders
getSettings = getSettings
getAccountInfo = getAccountInfo
getAccountObjects = getAccountObjects

View File

@@ -268,7 +268,7 @@ class Connection extends EventEmitter {
options.agent = new HttpsProxyAgent(proxyOptions)
}
if (this._authorization !== undefined) {
const base64 = new Buffer(this._authorization).toString('base64')
const base64 = Buffer.from(this._authorization).toString('base64')
options.headers = {Authorization: `Basic ${base64}`}
}
const optionsOverrides = _.omitBy({
@@ -445,7 +445,7 @@ class Connection extends EventEmitter {
this.once(eventName, response => {
if (response.status === 'error') {
_reject(new RippledError(response.error, response))
_reject(new RippledError(response.error_message || response.error, response))
} else if (response.status === 'success') {
_resolve(response.result)
} else {

View File

@@ -1,16 +1,51 @@
import {txFlagIndices} from './txflags'
// Ordering from https://developers.ripple.com/accountroot.html
const accountRootFlags = {
PasswordSpent: 0x00010000, // password set fee is spent
RequireDestTag: 0x00020000, // require a DestinationTag for payments
RequireAuth: 0x00040000, // require authorization to hold IOUs
DepositAuth: 0x01000000, // require account to auth deposits
DisallowXRP: 0x00080000, // disallow sending XRP
DisableMaster: 0x00100000, // force regular key
NoFreeze: 0x00200000, // permanently disallowed freezing trustlines
GlobalFreeze: 0x00400000, // trustlines globally frozen
DefaultRipple: 0x00800000
// lsfDefaultRipple:
// Enable rippling on trust lines by default.
// Required for issuing addresses; discouraged for others.
DefaultRipple: 0x00800000,
// lsfDepositAuth:
// Require account to auth deposits.
// This account can only receive funds from transactions it sends,
// or preauthorized accounts.
DepositAuth: 0x01000000,
// lsfDisableMaster:
// Force regular key.
// Disallows use of the master key.
DisableMaster: 0x00100000,
// lsfDisallowXRP:
// Disallow sending XRP.
// Not enforced by rippled; client applications should check.
DisallowXRP: 0x00080000,
// lsfGlobalFreeze:
// Trustlines globally frozen.
GlobalFreeze: 0x00400000,
// lsfNoFreeze:
// Permanently disallowed freezing trustlines.
// Once enabled, cannot be disabled.
NoFreeze: 0x00200000,
// lsfPasswordSpent:
// Password set fee is spent.
// The account has used its free SetRegularKey transaction.
PasswordSpent: 0x00010000,
// lsfRequireAuth:
// Require authorization to hold IOUs (issuances).
RequireAuth: 0x00040000,
// lsfRequireDestTag:
// Require a DestinationTag for incoming payments.
RequireDestTag: 0x00020000
}
const AccountFlags = {

View File

@@ -7,6 +7,10 @@
"options": {
"description": "Options affecting what ledger and how much data to return.",
"properties": {
"ledgerHash": {
"type": "string",
"description": "Get ledger data for this historical ledger hash."
},
"ledgerVersion": {
"$ref": "ledgerVersion",
"description": "Get ledger data for this historical ledger version."

View File

@@ -1,11 +1,12 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "tx",
"link": "https://ripple.com/build/transactions/",
"title": "tx-json",
"link": "https://developers.ripple.com/transaction-formats.html",
"description": "An object in rippled txJSON format",
"type": "object",
"properties": {
"Account": {"$ref": "address"}
"Account": {"$ref": "address"},
"TransactionType": {"type": "string"}
},
"required": ["Account"]
"required": ["Account", "TransactionType"]
}

View File

@@ -6,7 +6,7 @@
"properties": {
"result": {
"type": "string",
"description": "Result code returned by rippled. See [Transaction Results](https://ripple.com/build/transactions/#full-transaction-response-list) for a complete list."
"description": "Result code returned by rippled. See [Transaction Results](https://developers.ripple.com/transaction-results.html) for a complete list."
},
"timestamp": {
"type": "string",

View File

@@ -5,13 +5,33 @@
"properties": {
"resultCode": {
"type": "string",
"description": "The result code returned by rippled. [List of transaction responses](https://ripple.com/build/transactions/#full-transaction-response-list)"
"description": "Deprecated: Use `engine_result` instead."
},
"resultMessage": {
"type": "string",
"description": "Human-readable explanation of the status of the transaction."
"description": "Deprecated: Use `engine_result_message` instead."
},
"engine_result": {
"type": "string",
"description": "Code indicating the preliminary result of the transaction, for example `tesSUCCESS`. [List of transaction responses](https://developers.ripple.com/transaction-results.html)"
},
"engine_result_code": {
"type": "integer",
"description": "Numeric code indicating the preliminary result of the transaction, directly correlated to `engine_result`"
},
"engine_result_message": {
"type": "string",
"description": "Human-readable explanation of the transaction's preliminary result."
},
"tx_blob": {
"type": "string",
"description": "The complete transaction in hex string format."
},
"tx_json": {
"$ref": "tx-json",
"description": "The complete transaction in JSON format."
}
},
"required": ["resultCode", "resultMessage"],
"required": ["resultCode", "resultMessage", "engine_result", "engine_result_code", "engine_result_message", "tx_blob", "tx_json"],
"additionalProperties": false
}

View File

@@ -18,5 +18,6 @@ export interface Ledger {
hash?: string,
close_flags?: number,
parent_close_time?: number,
accountState?: any[]
accountState?: any[],
validated?: boolean
}

View File

@@ -125,7 +125,6 @@ function removeUndefined<T extends object>(obj: T): T {
/**
* @param {Number} rpepoch (seconds since 1/1/2000 GMT)
* @return {Number} ms since unix epoch
*
*/
function rippleToUnixTimestamp(rpepoch: number): number {
return (rpepoch + 0x386D4380) * 1000

View File

@@ -124,3 +124,6 @@ _.partial(schemaValidate, 'api-options')
export const instructions =
_.partial(schemaValidate, 'instructions')
export const tx_json =
_.partial(schemaValidate, 'tx-json')

View File

@@ -3,6 +3,7 @@ import {FormattedLedger, parseLedger} from './parse/ledger'
import {RippleAPI} from '../api'
export type GetLedgerOptions = {
ledgerHash?: string,
ledgerVersion?: number,
includeAllData?: boolean,
includeTransactions?: boolean,
@@ -16,6 +17,7 @@ async function getLedger(
validate.getLedger({options})
// 2. Make Request
const response = await this.request('ledger', {
ledger_hash: options.ledgerHash,
ledger_index: options.ledgerVersion || 'validated',
expand: options.includeAllData,
transactions: options.includeTransactions,

View File

@@ -8,6 +8,7 @@ import {validate} from '../common'
import {Amount, Issue} from '../common/types/objects'
import {BookOffer} from '../common/types/commands'
import {RippleAPI} from '../api'
import BigNumber from 'bignumber.js'
export type FormattedOrderbook = {
bids: FormattedOrderbookOrder[],
@@ -38,7 +39,7 @@ function alignOrder(base: Amount, order: FormattedOrderbookOrder) {
return isSameIssue(quantity, base) ? order : flipOrder(order)
}
function formatBidsAndAsks(
export function formatBidsAndAsks(
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
@@ -50,7 +51,10 @@ function formatBidsAndAsks(
// for asks: lowest quality => lowest totalPrice/quantity => lowest price
// for both bids and asks, lowest quality is closest to mid-market
// we sort the orders so that earlier orders are closer to mid-market
const orders = _.sortBy(offers, 'quality').map(parseOrderbookOrder)
const orders = offers.sort((a, b) => {
return (new BigNumber(a.quality)).comparedTo(b.quality)
}).map(parseOrderbookOrder)
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base))
const bids = alignedOrders.filter(_.partial(directionFilter, 'buy'))
const asks = alignedOrders.filter(_.partial(directionFilter, 'sell'))
@@ -87,7 +91,7 @@ export type OrderbookInfo = {
counter: Issue
}
export default async function getOrderbook(
export async function getOrderbook(
this: RippleAPI,
address: string,
orderbook: OrderbookInfo,
@@ -105,5 +109,6 @@ export default async function getOrderbook(
directOfferResult => directOfferResult.offers)
const reverseOffers = _.flatMap(reverseOfferResults,
reverseOfferResult => reverseOfferResult.offers)
return formatBidsAndAsks(orderbook, [...directOffers, ...reverseOffers])
return formatBidsAndAsks(orderbook,
[...directOffers, ...reverseOffers])
}

View File

@@ -5,7 +5,7 @@ const AccountFields = constants.AccountFields
function parseField(info, value) {
if (info.encoding === 'hex' && !info.length) { // e.g. "domain"
return new Buffer(value, 'hex').toString('ascii')
return Buffer.from(value, 'hex').toString('ascii')
}
if (info.shift) {
return (new BigNumber(value)).shift(-info.shift).toNumber()

View File

@@ -59,6 +59,11 @@ function parseState(state) {
return {rawState: JSON.stringify(state)}
}
/**
* @param {Ledger} ledger must be a *closed* ledger with valid `close_time` and `parent_close_time`
* @returns {FormattedLedger} formatted ledger
* @throws RangeError: Invalid time value (rippleTimeToISO8601)
*/
export function parseLedger(ledger: Ledger): FormattedLedger {
const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10)
return removeUndefined(Object.assign(

View File

@@ -4,6 +4,7 @@ import {PayChannelLedgerEntry} from '../../common/types/objects'
export type FormattedPaymentChannel = {
account: string,
amount: string,
balance: string,
publicKey: string,
destination: string,

View File

@@ -122,7 +122,7 @@ function parseOutcome(tx: any): any|undefined {
}
function hexToString(hex: string): string|undefined {
return hex ? new Buffer(hex, 'hex').toString('utf-8') : undefined
return hex ? Buffer.from(hex, 'hex').toString('utf-8') : undefined
}
function parseMemos(tx: any): Array<Memo>|undefined {

View File

@@ -46,9 +46,7 @@ function requestPathFind(connection: Connection, pathfind: PathFind
&& !request.destination_amount.issuer) {
// Convert blank issuer to sender's address
// (Ripple convention for 'any issuer')
// https://ripple.com/build/transactions/
// #special-issuer-values-for-sendmax-and-amount
// https://ripple.com/build/ripple-rest/#counterparties-in-payments
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
request.destination_amount.issuer = request.destination_account
}
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {

View File

@@ -4,6 +4,7 @@ import parseTransaction from './parse/transaction'
import {validate, errors} from '../common'
import {Connection} from '../common'
import {FormattedTransactionType} from '../transaction/types'
import {RippledError} from '../common/errors'
export type TransactionOptions = {
minLedgerVersion?: number,
@@ -59,10 +60,16 @@ function isTransactionInRange(tx: any, options: TransactionOptions) {
}
function convertError(connection: Connection, options: TransactionOptions,
error: Error
error: RippledError
): Promise<Error> {
const _error = (error.message === 'txnNotFound') ?
new errors.NotFoundError('Transaction not found') : error
let shouldUseNotFoundError = false
if ((error.data && error.data.error === 'txnNotFound') || error.message === 'txnNotFound') {
shouldUseNotFoundError = true
}
// In the future, we should deprecate this error, instead passing through the one from rippled.
const _error = shouldUseNotFoundError ? new errors.NotFoundError('Transaction not found') : error
if (_error instanceof errors.NotFoundError) {
return utils.hasCompleteLedgerRange(connection, options.minLedgerVersion,
options.maxLedgerVersion).then(hasCompleteLedgerRange => {

View File

@@ -76,7 +76,7 @@ function signum(num) {
* Order two rippled transactions based on their ledger_index.
* If two transactions took place in the same ledger, sort
* them based on TransactionIndex
* See: https://ripple.com/build/transactions/
* See: https://developers.ripple.com/transaction-metadata.html
*/
function compareTransactions(
first: FormattedTransactionType, second: FormattedTransactionType

View File

@@ -4,4 +4,3 @@ export {
deriveKeypair,
deriveAddress
}

View File

@@ -2,17 +2,18 @@ import keypairs = require('ripple-keypairs')
import * as common from '../common'
const {errors, validate} = common
function generateAddress(options?: object): object {
const secret = keypairs.generateSeed(options)
const keypair = keypairs.deriveKeypair(secret)
const address = keypairs.deriveAddress(keypair.publicKey)
return {secret, address}
export type GeneratedAddress = {
secret: string,
address: string
}
function generateAddressAPI(options?: object): object {
function generateAddressAPI(options?: any): GeneratedAddress {
validate.generateAddress({options})
try {
return generateAddress(options)
const secret = keypairs.generateSeed(options)
const keypair = keypairs.deriveKeypair(secret)
const address = keypairs.deriveAddress(keypair.publicKey)
return {secret, address}
} catch (error) {
throw new errors.UnexpectedError(error.message)
}

View File

@@ -1,14 +1,14 @@
import * as utils from './utils'
import {TransactionJSON, prepareTransaction} from './utils'
import {validate} from '../common'
import {Instructions, Prepare} from './types'
export type CheckCancel = {
export type CheckCancelParameters = {
checkID: string
}
function createCheckCancelTransaction(account: string,
cancel: CheckCancel
): object {
cancel: CheckCancelParameters
): TransactionJSON {
const txJSON = {
Account: account,
TransactionType: 'CheckCancel',
@@ -19,14 +19,18 @@ function createCheckCancelTransaction(account: string,
}
function prepareCheckCancel(address: string,
checkCancel: CheckCancel,
checkCancel: CheckCancelParameters,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareCheckCancel(
{address, checkCancel, instructions})
const txJSON = createCheckCancelTransaction(
address, checkCancel)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareCheckCancel(
{address, checkCancel, instructions})
const txJSON = createCheckCancelTransaction(
address, checkCancel)
return prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareCheckCancel

View File

@@ -2,18 +2,18 @@ import * as utils from './utils'
const ValidationError = utils.common.errors.ValidationError
const toRippledAmount = utils.common.toRippledAmount
import {validate} from '../common'
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
import {Amount} from '../common/types/objects'
export type CheckCash = {
export type CheckCashParameters = {
checkID: string,
amount?: Amount,
deliverMin?: Amount
}
function createCheckCashTransaction(account: string,
checkCash: CheckCash
): object {
checkCash: CheckCashParameters
): TransactionJSON {
if (checkCash.amount && checkCash.deliverMin) {
throw new ValidationError('"amount" and "deliverMin" properties on '
+ 'CheckCash are mutually exclusive')
@@ -37,14 +37,18 @@ function createCheckCashTransaction(account: string,
}
function prepareCheckCash(address: string,
checkCash: CheckCash,
checkCash: CheckCashParameters,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareCheckCash(
{address, checkCash, instructions})
const txJSON = createCheckCashTransaction(
address, checkCash)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareCheckCash(
{address, checkCash, instructions})
const txJSON = createCheckCashTransaction(
address, checkCash)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareCheckCash

View File

@@ -1,10 +1,10 @@
import * as utils from './utils'
const toRippledAmount = utils.common.toRippledAmount
import {validate, iso8601ToRippleTime} from '../common'
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
import {Amount} from '../common/types/objects'
export type CheckCreate = {
export type CheckCreateParameters = {
destination: string,
sendMax: Amount,
destinationTag?: number,
@@ -13,8 +13,8 @@ export type CheckCreate = {
}
function createCheckCreateTransaction(account: string,
check: CheckCreate
): object {
check: CheckCreateParameters
): TransactionJSON {
const txJSON: any = {
Account: account,
TransactionType: 'CheckCreate',
@@ -38,14 +38,18 @@ function createCheckCreateTransaction(account: string,
}
function prepareCheckCreate(address: string,
checkCreate: CheckCreate,
checkCreate: CheckCreateParameters,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareCheckCreate(
{address, checkCreate, instructions})
const txJSON = createCheckCreateTransaction(
address, checkCreate)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareCheckCreate(
{address, checkCreate, instructions})
const txJSON = createCheckCreateTransaction(
address, checkCreate)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareCheckCreate

View File

@@ -7,7 +7,7 @@ import {validate} from '../common'
import {computeBinaryTransactionHash} from 'ripple-hashes'
function addressToBigNumber(address) {
const hex = (new Buffer(decodeAddress(address))).toString('hex')
const hex = (Buffer.from(decodeAddress(address))).toString('hex')
return new BigNumber(hex, 16)
}

View File

@@ -1,18 +1,20 @@
import * as _ from 'lodash'
import * as utils from './utils'
const validate = utils.common.validate
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
import {Memo} from '../common/types/objects'
export type EscrowCancellation = {
owner: string,
escrowSequence: number,
// TODO: This ripple-lib memo format should be deprecated in favor of rippled's format.
// If necessary, expose a public method for converting between the two formats.
memos?: Array<Memo>
}
function createEscrowCancellationTransaction(account: string,
payment: EscrowCancellation
): object {
): TransactionJSON {
const txJSON: any = {
TransactionType: 'EscrowCancel',
Account: account,
@@ -20,7 +22,7 @@ function createEscrowCancellationTransaction(account: string,
OfferSequence: payment.escrowSequence
}
if (payment.memos !== undefined) {
txJSON.Memos = _.map(payment.memos, utils.convertMemo)
txJSON.Memos = payment.memos.map(utils.convertMemo)
}
return txJSON
}

View File

@@ -1,8 +1,7 @@
import * as _ from 'lodash'
import * as utils from './utils'
import {validate, iso8601ToRippleTime, xrpToDrops} from '../common'
const ValidationError = utils.common.errors.ValidationError
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
import {Memo} from '../common/types/objects'
export type EscrowCreation = {
@@ -18,7 +17,7 @@ export type EscrowCreation = {
function createEscrowCreationTransaction(account: string,
payment: EscrowCreation
): object {
): TransactionJSON {
const txJSON: any = {
TransactionType: 'EscrowCreate',
Account: account,
@@ -42,7 +41,7 @@ function createEscrowCreationTransaction(account: string,
txJSON.DestinationTag = payment.destinationTag
}
if (payment.memos !== undefined) {
txJSON.Memos = _.map(payment.memos, utils.convertMemo)
txJSON.Memos = payment.memos.map(utils.convertMemo)
}
if (Boolean(payment.allowCancelAfter) && Boolean(payment.allowExecuteAfter) &&
txJSON.CancelAfter <= txJSON.FinishAfter) {
@@ -56,11 +55,15 @@ function prepareEscrowCreation(address: string,
escrowCreation: EscrowCreation,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareEscrowCreation(
{address, escrowCreation, instructions})
const txJSON = createEscrowCreationTransaction(
address, escrowCreation)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareEscrowCreation(
{address, escrowCreation, instructions})
const txJSON = createEscrowCreationTransaction(
address, escrowCreation)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareEscrowCreation

View File

@@ -1,4 +1,3 @@
import * as _ from 'lodash'
import * as utils from './utils'
const validate = utils.common.validate
const ValidationError = utils.common.errors.ValidationError
@@ -15,7 +14,7 @@ export type EscrowExecution = {
function createEscrowExecutionTransaction(account: string,
payment: EscrowExecution
): object {
): utils.TransactionJSON {
const txJSON: any = {
TransactionType: 'EscrowFinish',
Account: account,
@@ -35,7 +34,7 @@ function createEscrowExecutionTransaction(account: string,
txJSON.Fulfillment = payment.fulfillment
}
if (payment.memos !== undefined) {
txJSON.Memos = _.map(payment.memos, utils.convertMemo)
txJSON.Memos = payment.memos.map(utils.convertMemo)
}
return txJSON
}
@@ -44,11 +43,15 @@ function prepareEscrowExecution(address: string,
escrowExecution: EscrowExecution,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareEscrowExecution(
{address, escrowExecution, instructions})
const txJSON = createEscrowExecutionTransaction(
address, escrowExecution)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareEscrowExecution(
{address, escrowExecution, instructions})
const txJSON = createEscrowExecutionTransaction(
address, escrowExecution)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareEscrowExecution

View File

@@ -1,4 +1,3 @@
import * as _ from 'lodash'
import * as utils from './utils'
const offerFlags = utils.common.txFlags.OfferCreate
import {validate, iso8601ToRippleTime} from '../common'
@@ -39,7 +38,7 @@ function createOrderTransaction(
txJSON.OfferSequence = order.orderToReplace
}
if (order.memos !== undefined) {
txJSON.Memos = _.map(order.memos, utils.convertMemo)
txJSON.Memos = order.memos.map(utils.convertMemo)
}
return txJSON as OfferCreateTransaction
}
@@ -47,9 +46,13 @@ function createOrderTransaction(
function prepareOrder(address: string, order: FormattedOrderSpecification,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareOrder({address, order, instructions})
const txJSON = createOrderTransaction(address, order)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareOrder({address, order, instructions})
const txJSON = createOrderTransaction(address, order)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareOrder

View File

@@ -1,18 +1,17 @@
import * as _ from 'lodash'
import * as utils from './utils'
const validate = utils.common.validate
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
function createOrderCancellationTransaction(account: string,
orderCancellation: any
): object {
): TransactionJSON {
const txJSON: any = {
TransactionType: 'OfferCancel',
Account: account,
OfferSequence: orderCancellation.orderSequence
}
if (orderCancellation.memos !== undefined) {
txJSON.Memos = _.map(orderCancellation.memos, utils.convertMemo)
txJSON.Memos = orderCancellation.memos.map(utils.convertMemo)
}
return txJSON
}
@@ -20,9 +19,13 @@ function createOrderCancellationTransaction(account: string,
function prepareOrderCancellation(address: string, orderCancellation: object,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareOrderCancellation({address, orderCancellation, instructions})
const txJSON = createOrderCancellationTransaction(address, orderCancellation)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareOrderCancellation({address, orderCancellation, instructions})
const txJSON = createOrderCancellationTransaction(address, orderCancellation)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareOrderCancellation

View File

@@ -16,8 +16,8 @@ export type PaymentChannelClaim = {
function createPaymentChannelClaimTransaction(account: string,
claim: PaymentChannelClaim
): object {
const txJSON: any = {
): utils.TransactionJSON {
const txJSON: utils.TransactionJSON = {
Account: account,
TransactionType: 'PaymentChannelClaim',
Channel: claim.channel,
@@ -62,11 +62,15 @@ function preparePaymentChannelClaim(address: string,
paymentChannelClaim: PaymentChannelClaim,
instructions: Instructions = {}
): Promise<Prepare> {
validate.preparePaymentChannelClaim(
{address, paymentChannelClaim, instructions})
const txJSON = createPaymentChannelClaimTransaction(
address, paymentChannelClaim)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.preparePaymentChannelClaim(
{address, paymentChannelClaim, instructions})
const txJSON = createPaymentChannelClaimTransaction(
address, paymentChannelClaim)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default preparePaymentChannelClaim

View File

@@ -14,7 +14,7 @@ export type PaymentChannelCreate = {
function createPaymentChannelCreateTransaction(account: string,
paymentChannel: PaymentChannelCreate
): object {
): utils.TransactionJSON {
const txJSON: any = {
Account: account,
TransactionType: 'PaymentChannelCreate',
@@ -41,11 +41,15 @@ function preparePaymentChannelCreate(address: string,
paymentChannelCreate: PaymentChannelCreate,
instructions: Instructions = {}
): Promise<Prepare> {
validate.preparePaymentChannelCreate(
{address, paymentChannelCreate, instructions})
const txJSON = createPaymentChannelCreateTransaction(
address, paymentChannelCreate)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.preparePaymentChannelCreate(
{address, paymentChannelCreate, instructions})
const txJSON = createPaymentChannelCreateTransaction(
address, paymentChannelCreate)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default preparePaymentChannelCreate

View File

@@ -10,8 +10,8 @@ export type PaymentChannelFund = {
function createPaymentChannelFundTransaction(account: string,
fund: PaymentChannelFund
): object {
const txJSON: any = {
): utils.TransactionJSON {
const txJSON: utils.TransactionJSON = {
Account: account,
TransactionType: 'PaymentChannelFund',
Channel: fund.channel,
@@ -29,11 +29,15 @@ function preparePaymentChannelFund(address: string,
paymentChannelFund: PaymentChannelFund,
instructions: Instructions = {}
): Promise<Prepare> {
validate.preparePaymentChannelFund(
{address, paymentChannelFund, instructions})
const txJSON = createPaymentChannelFundTransaction(
address, paymentChannelFund)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.preparePaymentChannelFund(
{address, paymentChannelFund, instructions})
const txJSON = createPaymentChannelFundTransaction(
address, paymentChannelFund)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default preparePaymentChannelFund

View File

@@ -4,7 +4,7 @@ const validate = utils.common.validate
const toRippledAmount = utils.common.toRippledAmount
const paymentFlags = utils.common.txFlags.Payment
const ValidationError = utils.common.errors.ValidationError
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
import {Amount, Adjustment, MaxAdjustment,
MinAdjustment, Memo} from '../common/types/objects'
import {xrpToDrops} from '../common'
@@ -59,9 +59,7 @@ function isIOUWithoutCounterparty(amount: Amount): boolean {
function applyAnyCounterpartyEncoding(payment: Payment): void {
// Convert blank counterparty to sender or receiver's address
// (Ripple convention for 'any counterparty')
// https://ripple.com/build/transactions/
// #special-issuer-values-for-sendmax-and-amount
// https://ripple.com/build/ripple-rest/#counterparties-in-payments
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
_.forEach([payment.source, payment.destination], adjustment => {
_.forEach(['amount', 'minAmount', 'maxAmount'], key => {
if (isIOUWithoutCounterparty(adjustment[key])) {
@@ -86,7 +84,7 @@ function createMaximalAmount(amount: Amount): Amount {
}
function createPaymentTransaction(address: string, paymentArgument: Payment
): object {
): TransactionJSON {
const payment = _.cloneDeep(paymentArgument)
applyAnyCounterpartyEncoding(payment)
@@ -172,9 +170,13 @@ function createPaymentTransaction(address: string, paymentArgument: Payment
function preparePayment(address: string, payment: Payment,
instructions: Instructions = {}
): Promise<Prepare> {
validate.preparePayment({address, payment, instructions})
const txJSON = createPaymentTransaction(address, payment)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.preparePayment({address, payment, instructions})
const txJSON = createPaymentTransaction(address, payment)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default preparePayment

View File

@@ -1,17 +1,13 @@
import * as _ from 'lodash'
import * as assert from 'assert'
import BigNumber from 'bignumber.js'
import * as utils from './utils'
const validate = utils.common.validate
const AccountFlagIndices = utils.common.constants.AccountFlagIndices
const AccountFields = utils.common.constants.AccountFields
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, SettingsTransaction} from './types'
import {FormattedSettings, WeightedSigner} from '../common/types/objects'
// Emptry string passed to setting will clear it
const CLEAR_SETTING = null
function setTransactionFlags(txJSON: any, values: FormattedSettings) {
function setTransactionFlags(txJSON: utils.TransactionJSON, values: FormattedSettings) {
const keys = Object.keys(values)
assert(keys.length === 1, 'ERROR: can only set one setting per transaction')
const flagName = keys[0]
@@ -26,7 +22,8 @@ function setTransactionFlags(txJSON: any, values: FormattedSettings) {
}
}
function setTransactionFields(txJSON: object, input: FormattedSettings) {
// Sets `null` fields to their `default`.
function setTransactionFields(txJSON: utils.TransactionJSON, input: FormattedSettings) {
const fieldSchema = AccountFields
for (const fieldName in fieldSchema) {
const field = fieldSchema[fieldName]
@@ -37,13 +34,13 @@ function setTransactionFields(txJSON: object, input: FormattedSettings) {
}
// The value required to clear an account root field varies
if (value === CLEAR_SETTING && field.hasOwnProperty('defaults')) {
if (value === null && field.hasOwnProperty('defaults')) {
value = field.defaults
}
if (field.encoding === 'hex' && !field.length) {
// This is currently only used for Domain field
value = new Buffer(value, 'ascii').toString('hex').toUpperCase()
value = Buffer.from(value, 'ascii').toString('hex').toUpperCase()
}
txJSON[fieldName] = value
@@ -63,7 +60,7 @@ function setTransactionFields(txJSON: object, input: FormattedSettings) {
* are returned
*/
function convertTransferRate(transferRate: number | string): number | string {
function convertTransferRate(transferRate: number): number {
return (new BigNumber(transferRate)).shift(9).toNumber()
}
@@ -78,7 +75,7 @@ function formatSignerEntry(signer: WeightedSigner): object {
function createSettingsTransactionWithoutMemos(
account: string, settings: FormattedSettings
): any {
): SettingsTransaction {
if (settings.regularKey !== undefined) {
const removeRegularKey = {
TransactionType: 'SetRegularKey',
@@ -87,7 +84,7 @@ function createSettingsTransactionWithoutMemos(
if (settings.regularKey === null) {
return removeRegularKey
}
return _.assign({}, removeRegularKey, {RegularKey: settings.regularKey})
return Object.assign({}, removeRegularKey, {RegularKey: settings.regularKey})
}
if (settings.signers !== undefined) {
@@ -95,17 +92,19 @@ function createSettingsTransactionWithoutMemos(
TransactionType: 'SignerListSet',
Account: account,
SignerQuorum: settings.signers.threshold,
SignerEntries: _.map(settings.signers.weights, formatSignerEntry)
SignerEntries: settings.signers.weights.map(formatSignerEntry)
}
}
const txJSON: any = {
const txJSON: SettingsTransaction = {
TransactionType: 'AccountSet',
Account: account
}
setTransactionFlags(txJSON, _.omit(settings, 'memos'))
setTransactionFields(txJSON, settings)
const settingsWithoutMemos = Object.assign({}, settings)
delete settingsWithoutMemos.memos
setTransactionFlags(txJSON, settingsWithoutMemos)
setTransactionFields(txJSON, settings) // Sets `null` fields to their `default`.
if (txJSON.TransferRate !== undefined) {
txJSON.TransferRate = convertTransferRate(txJSON.TransferRate)
@@ -114,10 +113,10 @@ function createSettingsTransactionWithoutMemos(
}
function createSettingsTransaction(account: string, settings: FormattedSettings
): object {
): SettingsTransaction {
const txJSON = createSettingsTransactionWithoutMemos(account, settings)
if (settings.memos !== undefined) {
txJSON.Memos = _.map(settings.memos, utils.convertMemo)
txJSON.Memos = settings.memos.map(utils.convertMemo)
}
return txJSON
}
@@ -125,9 +124,13 @@ function createSettingsTransaction(account: string, settings: FormattedSettings
function prepareSettings(address: string, settings: FormattedSettings,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareSettings({address, settings, instructions})
const txJSON = createSettingsTransaction(address, settings)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareSettings({address, settings, instructions})
const txJSON = createSettingsTransaction(address, settings)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareSettings

View File

@@ -20,8 +20,15 @@ function isImmediateRejection(engineResult: string): boolean {
function formatSubmitResponse(response): FormattedSubmitResponse {
const data = {
// @deprecated
resultCode: response.engine_result,
resultMessage: response.engine_result_message
// @deprecated
resultMessage: response.engine_result_message,
engine_result: response.engine_result,
engine_result_code: response.engine_result_code,
engine_result_message: response.engine_result_message,
tx_blob: response.tx_blob,
tx_json: response.tx_json
}
if (isImmediateRejection(response.engine_result)) {
throw new utils.common.errors.RippledError('Submit failed', data)

View File

@@ -1,9 +1,8 @@
import * as _ from 'lodash'
import BigNumber from 'bignumber.js'
import * as utils from './utils'
const validate = utils.common.validate
const trustlineFlags = utils.common.txFlags.TrustSet
import {Instructions, Prepare} from './types'
import {Instructions, Prepare, TransactionJSON} from './types'
import {
FormattedTrustlineSpecification
} from '../common/types/objects/trustlines'
@@ -14,7 +13,7 @@ function convertQuality(quality) {
function createTrustlineTransaction(account: string,
trustline: FormattedTrustlineSpecification
): object {
): TransactionJSON {
const limit = {
currency: trustline.currency,
issuer: trustline.counterparty,
@@ -45,7 +44,7 @@ function createTrustlineTransaction(account: string,
trustlineFlags.SetFreeze : trustlineFlags.ClearFreeze
}
if (trustline.memos !== undefined) {
txJSON.Memos = _.map(trustline.memos, utils.convertMemo)
txJSON.Memos = trustline.memos.map(utils.convertMemo)
}
return txJSON
}
@@ -53,9 +52,13 @@ function createTrustlineTransaction(account: string,
function prepareTrustline(address: string,
trustline: FormattedTrustlineSpecification, instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareTrustline({address, trustline, instructions})
const txJSON = createTrustlineTransaction(address, trustline)
return utils.prepareTransaction(txJSON, this, instructions)
try {
validate.prepareTrustline({address, trustline, instructions})
const txJSON = createTrustlineTransaction(address, trustline)
return utils.prepareTransaction(txJSON, this, instructions)
} catch (e) {
return Promise.reject(e)
}
}
export default prepareTrustline

View File

@@ -7,7 +7,12 @@ import {
Memo,
FormattedSettings
} from '../common/types/objects'
import {ApiMemo} from './utils'
import {
ApiMemo,
TransactionJSON
} from './utils'
export type TransactionJSON = TransactionJSON
export type Instructions = {
sequence?: number,
@@ -37,7 +42,7 @@ export type Submit = {
txJson?: object
}
export interface OfferCreateTransaction {
export interface OfferCreateTransaction extends TransactionJSON {
TransactionType: 'OfferCreate',
Account: string,
Fee: string,
@@ -48,7 +53,11 @@ export interface OfferCreateTransaction {
TakerPays: RippledAmount,
Expiration?: number,
OfferSequence?: number,
Memos: {Memo: ApiMemo}[]
Memos?: {Memo: ApiMemo}[]
}
export interface SettingsTransaction extends TransactionJSON {
TransferRate?: number
}
export type KeyPair = {

View File

@@ -1,6 +1,6 @@
import BigNumber from 'bignumber.js'
import * as common from '../common'
import {Memo} from '../common/types/objects'
import {Memo, RippledAmount} from '../common/types/objects'
const txFlags = common.txFlags
import {Instructions, Prepare} from './types'
import {RippleAPI} from '../api'
@@ -12,6 +12,15 @@ export type ApiMemo = {
MemoFormat?: string
}
export type TransactionJSON = {
Account: string,
TransactionType: string,
Memos?: {Memo: ApiMemo}[],
Flags?: number,
Fulfillment?: string,
[Field: string]: string | number | Array<any> | RippledAmount
}
function formatPrepareResponse(txJSON: any): Prepare {
const instructions = {
fee: common.dropsToXrp(txJSON.Fee),
@@ -37,10 +46,11 @@ function scaleValue(value, multiplier, extra = 0) {
return (new BigNumber(value)).times(multiplier).plus(extra).toString()
}
function prepareTransaction(txJSON: any, api: RippleAPI,
function prepareTransaction(txJSON: TransactionJSON, api: RippleAPI,
instructions: Instructions
): Promise<Prepare> {
common.validate.instructions(instructions)
common.validate.tx_json(txJSON)
const account = txJSON.Account
setCanonicalFlag(txJSON)
@@ -81,7 +91,7 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
(txJSON.TransactionType !== 'EscrowFinish' ||
txJSON.Fulfillment === undefined) ? 0 :
(cushion * feeRef * (32 + Math.floor(
new Buffer(txJSON.Fulfillment, 'hex').length / 16)))
Buffer.from(txJSON.Fulfillment, 'hex').length / 16)))
const feeDrops = common.xrpToDrops(fee)
const maxFeeXRP = instructions.maxFee ?
BigNumber.min(api._maxFeeXRP, instructions.maxFee) : api._maxFeeXRP
@@ -96,14 +106,28 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
async function prepareSequence(): Promise<object> {
if (instructions.sequence !== undefined) {
txJSON.Sequence = instructions.sequence
if (txJSON.Sequence === undefined || instructions.sequence === txJSON.Sequence) {
txJSON.Sequence = instructions.sequence
return Promise.resolve(txJSON)
} else {
// Both txJSON.Sequence and instructions.sequence are defined, and they are NOT equal
return Promise.reject(new ValidationError('`Sequence` in txJSON must match `sequence` in Instructions'))
}
}
if (txJSON.Sequence !== undefined) {
return Promise.resolve(txJSON)
}
const response = await api.request('account_info', {
account: account as string
})
txJSON.Sequence = response.account_data.Sequence
return txJSON
try {
// Consider requesting from the 'current' ledger (instead of 'validated').
const response = await api.request('account_info', {
account
})
txJSON.Sequence = response.account_data.Sequence
return Promise.resolve(txJSON)
} catch (e) {
return Promise.reject(e)
}
}
return Promise.all([
@@ -114,7 +138,7 @@ function prepareTransaction(txJSON: any, api: RippleAPI,
}
function convertStringToHex(string: string): string {
return new Buffer(string, 'utf8').toString('hex').toUpperCase()
return Buffer.from(string, 'utf8').toString('hex').toUpperCase()
}
function convertMemo(memo: Memo): {Memo: ApiMemo} {

File diff suppressed because it is too large Load Diff

View File

@@ -396,7 +396,8 @@ 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, 'invalidParams')
assert.strictEqual(error.message, 'Invalid parameters.')
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' })

View File

@@ -0,0 +1,12 @@
{
"stateHash": "A155BFE86054BE654796EC449E7C374CD5CAA3789BA75D302E7F0F4CE470CCB3",
"closeTime": "2018-12-07T11:10:30.000Z",
"closeTimeResolution": 10,
"closeFlags": 0,
"ledgerHash": "15F20E5FA6EA9770BBFFDBD62787400960B04BE32803B20C41F117F41C13830D",
"ledgerVersion": 14995338,
"parentLedgerHash": "E0BC4F5FB8D9025087BE238664833DFA5658C9E7CE413B3B6F7DF4FFF1EDBF40",
"parentCloseTime": "2018-12-07T11:10:22.000Z",
"totalDrops": "99997114637345372",
"transactionHash": "52C0B6604D2EF203710FEA24F4A3750A4F2BCD5C67D6EB5FB1B2DBAE9A14DCE8"
}

View File

@@ -83,6 +83,7 @@ module.exports = {
},
getLedger: {
header: require('./get-ledger'),
headerByHash: require('./get-ledger-by-hash'),
full: require('./get-ledger-full'),
withSettingsTx: require('./get-ledger-with-settings-tx'),
withStateAsHashes: require('./get-ledger-with-state-as-hashes'),

View File

@@ -1,4 +1,24 @@
{
"resultCode": "tesSUCCESS",
"resultMessage": "The transaction was applied. Only final in a validated ledger."
"resultMessage": "The transaction was applied. Only final in a validated ledger.",
"engine_result": "tesSUCCESS",
"engine_result_code": 0,
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
"tx_blob": "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754",
"tx_json": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": {
"currency": "USD",
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"value": "1"
},
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "10000",
"Flags": 2147483648,
"Sequence": 360,
"SigningPubKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
"TransactionType": "Payment",
"TxnSignature": "304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F8580",
"hash": "4D5D90890F8D49519E4151938601EF3D0B30B16CD6A519D9C99102C9FA77F7E0"
}
}

View File

@@ -2,470 +2,11 @@
'use strict'
const _ = require('lodash')
module.exports.requestBookOffersBidsResponse = function(request, options = {}) {
_.defaults(options, {
gets: {
currency: 'USD',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
pays: {
currency: 'BTC',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
})
return JSON.stringify({
id: request.id,
result: {
ledger_index: 10716345,
offers: [
{
Account: 'r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B15A60037FFCF',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'544932DC56D72E845AF2B738821FE07865E32EC196270678AB0D947F54E9F49F',
PreviousTxnLgrSeq: 10679000,
Sequence: 434,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '3205.1'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '10'
},
index:
'CE457115A4ADCC8CB351B3E35A0851E48DE16605C23E305017A9B697B156DE5A',
owner_funds: '41952.95917199965',
quality: '0.003120027456241615'
},
{
Account: 'rDYCRhpahKEhCFV25xScg67Bwf4W9sTYAm',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B1A2BC2EC5000',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'F68F9658AB3D462FEB027E6C380F054BC6D2514B43EC3C6AD46EE19C59BF1CC3',
PreviousTxnLgrSeq: 10704238,
Sequence: 233,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '1599.063669386278'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '4.99707396683212'
},
index:
'BF14FBB305159DBCAEA91B7E848408F5B559A91B160EBCB6D244958A6A16EA6B',
owner_funds: '3169.910902910102',
quality: '0.003125'
},
{
Account: 'raudnGKfTK23YKfnS7ixejHrqGERTYNFXk',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B2BF1C2F4D4C9',
BookNode: '0000000000000000',
Expiration: 472785284,
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '00000000000008F0',
PreviousTxnID:
'446410E1CD718AC01929DD16B558FCF6B3A7B8BF208C420E67A280C089C5C59B',
PreviousTxnLgrSeq: 10713576,
Sequence: 110104,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '143.1050962074379'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.4499999999999999'
},
index:
'67924B0EAA15784CC00CCD5FDD655EE2D6D2AE40341776B5F14E52341E7FC73E',
owner_funds: '0',
quality: '0.003144542101755081',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0'
}
},
{
Account: 'rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B2CD7A2BFBB75',
BookNode: '0000000000000000',
Expiration: 472772651,
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '00000000000003CD',
PreviousTxnID:
'D49164AB68DDA3AEC9DFCC69A35685C4F532B5C231D3C1D25FEA7D5D0224FB84',
PreviousTxnLgrSeq: 10711128,
Sequence: 35625,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '254.329207354604'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.8'
},
index:
'567BF2825173E3FB28FC94E436B6EB30D9A415FC2335E6D25CDE1BE47B25D120',
owner_funds: '0',
quality: '0.003145529403882357',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0'
}
},
{
Account: 'rwBYyfufTzk77zUSKEu4MvixfarC35av1J',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B3621DF140FDA',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000008',
PreviousTxnID:
'2E371E2B287C8A9FBB3424E4204B17AD9FA1BAA9F3B33C7D2261E3B038AFF083',
PreviousTxnLgrSeq: 10716291,
Sequence: 387756,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '390.4979'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '1.23231134568807'
},
index:
'8CA23E55BF9F46AC7E803D3DB40FD03225EFCA66650D4CF0CBDD28A7CCDC8400',
owner_funds: '5704.824764087842',
quality: '0.003155743848271834'
},
{
Account: 'rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B3A4D41FF4211',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'91763FA7089C63CC4D5D14CBA6A5A5BF7ECE949B0D34F00FD35E733AF9F05AF1',
PreviousTxnLgrSeq: 10716292,
Sequence: 208927,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '1'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.003160328237957649'
},
index:
'7206866E39D9843623EE79E570242753DEE3C597F3856AEFB4631DD5AD8B0557',
owner_funds: '45.55665106096075',
quality: '0.003160328237957649'
},
{
Account: 'r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B4748E68669A7',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'3B3CF6FF1A336335E78513CF77AFD3A784ACDD7B1B4D3F1F16E22957A060BFAE',
PreviousTxnLgrSeq: 10639969,
Sequence: 429,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '4725'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '15'
},
index:
'42894809370C7E6B23498EF8E22AD4B05F02B94F08E6983357A51EA96A95FF7F',
quality: '0.003174603174603175'
},
{
Account: 'rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B58077ED03C1B',
BookNode: '0000000000000000',
Flags: 131072,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000001',
PreviousTxnID:
'98F3F2D02D3BB0AEAC09EECCF2F24BBE5E1AB2C71C40D7BD0A5199E12541B6E2',
PreviousTxnLgrSeq: 10715839,
Sequence: 110099,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '1.24252537879871'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.gets.issuer,
value: '0.003967400879423823'
},
index:
'F4404D6547149419D3607F81D7080979FBB3AFE2661F9A933E2F6C07AC1D1F6D',
owner_funds: '73.52163803897041',
quality: '0.003193013959408667'
},
{
Account: 'rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B72A555B981A3',
BookNode: '0000000000000000',
Expiration: 472772652,
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '00000000000003CD',
PreviousTxnID:
'146C8DBB047BAAFAE5B8C8DECCCDACD9DFCD7A464E5AB273230FF975E9B83CF7',
PreviousTxnLgrSeq: 10711128,
Sequence: 35627,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '496.5429474010489'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '1.6'
},
index:
'50CAA04E81D0009115B61C132FC9887FA9E5336E0CB8A2E7D3280ADBF6ABC043',
quality: '0.003222279177208227',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0'
}
},
{
Account: 'r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B730474DD96E5',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'624F9ADA85EC3BE845EAC075B47E01E4F89288EAF27823C715777B3DFFB21F24',
PreviousTxnLgrSeq: 10639989,
Sequence: 431,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '3103'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '10'
},
index:
'8A319A496288228AD9CAD74375E32FA81805C56A9AD84798A26756A8B3F9EE23',
quality: '0.003222687721559781'
}
],
validated: false
},
status: 'success',
type: 'response'
})
}
module.exports.requestBookOffersBidsPartialFundedResponse = function(
request,
options = {}
) {
_.defaults(options, {
gets: {
currency: 'BTC',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
pays: {
currency: 'USD',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
})
return JSON.stringify({
id: request.id,
status: 'success',
type: 'response',
result: {
ledger_current_index: 10714274,
offers: [
{
Account: 'rpUirQxhaFqMp7YHPLMZCWxgZQbaZkp4bM',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B75DA97A99CE7',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'52801D1249261E410632BF6C00F503B1F51B31798C1E7DBD67B976FE65BE4DA4',
PreviousTxnLgrSeq: 10630313,
Sequence: 132,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '310'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '1'
},
index:
'861D15BECDA5DCA1327CF4D8080C181425F043AC969A992C5FAE5D12813785D0',
owner_funds: '259.7268806690133',
quality: '0.003225806451612903',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '259.2084637415302'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.8361563346500974'
}
}
]
}
})
}
module.exports.requestBookOffersAsksPartialFundedResponse = function(
request,
options = {}
) {
_.defaults(options, {
gets: {
currency: 'BTC',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
pays: {
currency: 'USD',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
})
return JSON.stringify({
id: request.id,
status: 'success',
type: 'response',
result: {
ledger_current_index: 10714274,
offers: [
{
Account: 'rPyYxUGK8L4dgEvjPs3aRc1B1jEiLr3Hx5',
BookDirectory:
'6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570BCB85BCA78000',
BookNode: '0000000000000000',
Flags: 131072,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'D22993C68C94ACE3F2FCE4A334EBEA98CC46DCA92886C12B5E5B4780B5E17D4E',
PreviousTxnLgrSeq: 10711938,
Sequence: 392,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0.8095'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '268.754'
},
index:
'18B136E08EF50F0DEE8521EA22D16A950CD8B6DDF5F6E07C35F7FDDBBB09718D',
owner_funds: '0.8095132334507441',
quality: '332',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0.8078974385735969'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '268.2219496064341'
}
}
]
}
})
}
module.exports.requestBookOffersAsksResponse = function(request, options = {}) {
_.defaults(options, {
pays: {
currency: 'USD',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
gets: {
currency: 'BTC',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
})
module.exports.requestBookOffersBidsResponse = function(request) {
const options = {
gets: request.taker_gets,
pays: request.taker_pays
}
return JSON.stringify({
id: request.id,
@@ -782,6 +323,453 @@ module.exports.requestBookOffersAsksResponse = function(request, options = {}) {
})
}
module.exports.requestBookOffersBidsPartialFundedResponse = function(
request,
options = {}
) {
_.defaults(options, {
gets: {
currency: 'BTC',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
pays: {
currency: 'USD',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
})
return JSON.stringify({
id: request.id,
status: 'success',
type: 'response',
result: {
ledger_current_index: 10714274,
offers: [
{
Account: 'rpUirQxhaFqMp7YHPLMZCWxgZQbaZkp4bM',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B75DA97A99CE7',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'52801D1249261E410632BF6C00F503B1F51B31798C1E7DBD67B976FE65BE4DA4',
PreviousTxnLgrSeq: 10630313,
Sequence: 132,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '310'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '1'
},
index:
'861D15BECDA5DCA1327CF4D8080C181425F043AC969A992C5FAE5D12813785D0',
owner_funds: '259.7268806690133',
quality: '0.003225806451612903',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '259.2084637415302'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.8361563346500974'
}
}
]
}
})
}
module.exports.requestBookOffersAsksPartialFundedResponse = function(
request,
options = {}
) {
_.defaults(options, {
gets: {
currency: 'BTC',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
pays: {
currency: 'USD',
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
})
return JSON.stringify({
id: request.id,
status: 'success',
type: 'response',
result: {
ledger_current_index: 10714274,
offers: [
{
Account: 'rPyYxUGK8L4dgEvjPs3aRc1B1jEiLr3Hx5',
BookDirectory:
'6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC98570BCB85BCA78000',
BookNode: '0000000000000000',
Flags: 131072,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'D22993C68C94ACE3F2FCE4A334EBEA98CC46DCA92886C12B5E5B4780B5E17D4E',
PreviousTxnLgrSeq: 10711938,
Sequence: 392,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0.8095'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '268.754'
},
index:
'18B136E08EF50F0DEE8521EA22D16A950CD8B6DDF5F6E07C35F7FDDBBB09718D',
owner_funds: '0.8095132334507441',
quality: '332',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0.8078974385735969'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '268.2219496064341'
}
}
]
}
})
}
module.exports.requestBookOffersAsksResponse = function(request) {
const options = {
gets: request.taker_gets,
pays: request.taker_pays
}
return JSON.stringify({
id: request.id,
result: {
ledger_index: 10716345,
offers: [
{
Account: 'r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B15A60037FFCF',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'544932DC56D72E845AF2B738821FE07865E32EC196270678AB0D947F54E9F49F',
PreviousTxnLgrSeq: 10679000,
Sequence: 434,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '3205.1'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '10'
},
index:
'CE457115A4ADCC8CB351B3E35A0851E48DE16605C23E305017A9B697B156DE5A',
owner_funds: '41952.95917199965',
quality: '0.003120027456241615'
},
{
Account: 'rDYCRhpahKEhCFV25xScg67Bwf4W9sTYAm',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B1A2BC2EC5000',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'F68F9658AB3D462FEB027E6C380F054BC6D2514B43EC3C6AD46EE19C59BF1CC3',
PreviousTxnLgrSeq: 10704238,
Sequence: 233,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '1599.063669386278'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '4.99707396683212'
},
index:
'BF14FBB305159DBCAEA91B7E848408F5B559A91B160EBCB6D244958A6A16EA6B',
owner_funds: '3169.910902910102',
quality: '0.003125'
},
{
Account: 'raudnGKfTK23YKfnS7ixejHrqGERTYNFXk',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B2BF1C2F4D4C9',
BookNode: '0000000000000000',
Expiration: 472785284,
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '00000000000008F0',
PreviousTxnID:
'446410E1CD718AC01929DD16B558FCF6B3A7B8BF208C420E67A280C089C5C59B',
PreviousTxnLgrSeq: 10713576,
Sequence: 110104,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '143.1050962074379'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.4499999999999999'
},
index:
'67924B0EAA15784CC00CCD5FDD655EE2D6D2AE40341776B5F14E52341E7FC73E',
owner_funds: '0',
quality: '0.003144542101755081',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0'
}
},
{
Account: 'rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B2CD7A2BFBB75',
BookNode: '0000000000000000',
Expiration: 472772651,
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '00000000000003CD',
PreviousTxnID:
'D49164AB68DDA3AEC9DFCC69A35685C4F532B5C231D3C1D25FEA7D5D0224FB84',
PreviousTxnLgrSeq: 10711128,
Sequence: 35625,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '254.329207354604'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.8'
},
index:
'567BF2825173E3FB28FC94E436B6EB30D9A415FC2335E6D25CDE1BE47B25D120',
owner_funds: '0',
quality: '0.003145529403882357',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0'
}
},
{
Account: 'rwBYyfufTzk77zUSKEu4MvixfarC35av1J',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B3621DF140FDA',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000008',
PreviousTxnID:
'2E371E2B287C8A9FBB3424E4204B17AD9FA1BAA9F3B33C7D2261E3B038AFF083',
PreviousTxnLgrSeq: 10716291,
Sequence: 387756,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '390.4979'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '1.23231134568807'
},
index:
'8CA23E55BF9F46AC7E803D3DB40FD03225EFCA66650D4CF0CBDD28A7CCDC8400',
owner_funds: '5704.824764087842',
quality: '0.003155743848271834'
},
{
Account: 'rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B3A4D41FF4211',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'91763FA7089C63CC4D5D14CBA6A5A5BF7ECE949B0D34F00FD35E733AF9F05AF1',
PreviousTxnLgrSeq: 10716292,
Sequence: 208927,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '1'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0.003160328237957649'
},
index:
'7206866E39D9843623EE79E570242753DEE3C597F3856AEFB4631DD5AD8B0557',
owner_funds: '45.55665106096075',
quality: '0.003160328237957649'
},
{
Account: 'r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B4748E68669A7',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'3B3CF6FF1A336335E78513CF77AFD3A784ACDD7B1B4D3F1F16E22957A060BFAE',
PreviousTxnLgrSeq: 10639969,
Sequence: 429,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '4725'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '15'
},
index:
'42894809370C7E6B23498EF8E22AD4B05F02B94F08E6983357A51EA96A95FF7F',
quality: '0.003174603174603175'
},
{
Account: 'rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B58077ED03C1B',
BookNode: '0000000000000000',
Flags: 131072,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000001',
PreviousTxnID:
'98F3F2D02D3BB0AEAC09EECCF2F24BBE5E1AB2C71C40D7BD0A5199E12541B6E2',
PreviousTxnLgrSeq: 10715839,
Sequence: 110099,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '1.24252537879871'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.gets.issuer,
value: '0.003967400879423823'
},
index:
'F4404D6547149419D3607F81D7080979FBB3AFE2661F9A933E2F6C07AC1D1F6D',
owner_funds: '73.52163803897041',
quality: '0.003193013959408667'
},
{
Account: 'rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B72A555B981A3',
BookNode: '0000000000000000',
Expiration: 472772652,
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '00000000000003CD',
PreviousTxnID:
'146C8DBB047BAAFAE5B8C8DECCCDACD9DFCD7A464E5AB273230FF975E9B83CF7',
PreviousTxnLgrSeq: 10711128,
Sequence: 35627,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '496.5429474010489'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '1.6'
},
index:
'50CAA04E81D0009115B61C132FC9887FA9E5336E0CB8A2E7D3280ADBF6ABC043',
quality: '0.003222279177208227',
taker_gets_funded: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '0'
},
taker_pays_funded: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '0'
}
},
{
Account: 'r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ',
BookDirectory:
'20294C923E80A51B487EB9547B3835FD483748B170D2D0A4520B730474DD96E5',
BookNode: '0000000000000000',
Flags: 0,
LedgerEntryType: 'Offer',
OwnerNode: '0000000000000000',
PreviousTxnID:
'624F9ADA85EC3BE845EAC075B47E01E4F89288EAF27823C715777B3DFFB21F24',
PreviousTxnLgrSeq: 10639989,
Sequence: 431,
TakerGets: {
currency: options.gets.currency,
issuer: options.gets.issuer,
value: '3103'
},
TakerPays: {
currency: options.pays.currency,
issuer: options.pays.issuer,
value: '10'
},
index:
'8A319A496288228AD9CAD74375E32FA81805C56A9AD84798A26756A8B3F9EE23',
quality: '0.003222687721559781'
}
],
validated: false
},
status: 'success',
type: 'response'
})
}
module.exports.requestBookOffersXRPBaseResponse = function(request) {
return JSON.stringify({
id: request.id,

View File

@@ -7,6 +7,7 @@ module.exports = {
},
ledger: {
normal: require('./ledger'),
normalByHash: require('./ledger-by-hash'),
notFound: require('./ledger-not-found'),
withoutCloseTime: require('./ledger-without-close-time'),
withSettingsTx: require('./ledger-with-settings-tx'),

View File

@@ -0,0 +1,28 @@
{
"id":1,
"result": {
"ledger": {
"accepted": true,
"account_hash": "A155BFE86054BE654796EC449E7C374CD5CAA3789BA75D302E7F0F4CE470CCB3",
"close_flags": 0,
"close_time": 597496230,
"close_time_human": "2018-Dec-07 11:10:30.000000000",
"close_time_resolution": 10,
"closed": true,
"hash": "15F20E5FA6EA9770BBFFDBD62787400960B04BE32803B20C41F117F41C13830D",
"ledger_hash": "15F20E5FA6EA9770BBFFDBD62787400960B04BE32803B20C41F117F41C13830D",
"ledger_index": "14995338",
"parent_close_time": 597496222,
"parent_hash": "E0BC4F5FB8D9025087BE238664833DFA5658C9E7CE413B3B6F7DF4FFF1EDBF40",
"seqNum": "14995338",
"totalCoins": "99997114637345372",
"total_coins": "99997114637345372",
"transaction_hash": "52C0B6604D2EF203710FEA24F4A3750A4F2BCD5C67D6EB5FB1B2DBAE9A14DCE8"
},
"ledger_hash": "15F20E5FA6EA9770BBFFDBD62787400960B04BE32803B20C41F117F41C13830D",
"ledger_index": 14995338,
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,13 @@
{
"taker_gets": {
"currency": "XRP"
},
"taker_pays": {
"currency": "JPY",
"issuer": "rB3gZey7VWHYRqJHLoHDEJXJ2pEPNieKiS"
},
"ledger_index": "validated",
"limit": 400,
"taker": "rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR",
"command": "book_offers"
}

View File

@@ -0,0 +1,13 @@
{
"taker_gets": {
"currency": "JPY",
"issuer": "rB3gZey7VWHYRqJHLoHDEJXJ2pEPNieKiS"
},
"taker_pays": {
"currency": "XRP"
},
"ledger_index": "validated",
"limit": 400,
"taker": "rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR",
"command": "book_offers"
}

View File

@@ -0,0 +1,13 @@
{
"taker_gets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"taker_pays": {
"currency": "XRP"
},
"ledger_index": "validated",
"limit": 400,
"taker": "rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR",
"command": "book_offers"
}

View File

@@ -0,0 +1,13 @@
{
"taker_gets": {
"currency": "XRP"
},
"taker_pays": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"ledger_index": "validated",
"limit": 400,
"taker": "rE9qNjzJXpiUbVomdv7R4xhrXVeH2oVmGR",
"command": "book_offers"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
{
"ledger_hash": "C4F68C1CF2E0BFC09284690067ED7B1A38D4509A09DF26D66EABCE4F196CE9E9",
"ledger_index": 42595629,
"offers": [],
"validated": true
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,22 @@
"engine_result": "tesSUCCESS",
"engine_result_code": 0,
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
"tx_blob": "12000322000000002400000017201B0086955468400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D87446304402207660BDEF67105CE1EBA9AD35DC7156BAB43FF1D47633199EE257D70B6B9AAFBF02207F5517BC8AEF2ADC1325897ECDBA8C673838048BCA62F4E98B252F19BE88796D770A726970706C652E636F6D81144FBFF73DA4ECF9B701940F27341FA8020C313443",
"tx_json": {}
"tx_blob": "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754",
"tx_json": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": {
"currency": "USD",
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"value": "1"
},
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "10000",
"Flags": 2147483648,
"Sequence": 360,
"SigningPubKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
"TransactionType": "Payment",
"TxnSignature": "304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F8580",
"hash": "4D5D90890F8D49519E4151938601EF3D0B30B16CD6A519D9C99102C9FA77F7E0"
}
}
}

View File

@@ -11,6 +11,7 @@ const accountLinesResponse = require('./fixtures/rippled/account-lines');
const accountObjectsResponse = require('./fixtures/rippled/account-objects');
const fullLedger = require('./fixtures/rippled/ledger-full-38129.json');
const { getFreePort } = require('./utils/net-utils');
const fs = require('fs');
function isUSD(json) {
return json === 'USD' || json === '0000000000000000000000005553440000000000';
@@ -237,11 +238,40 @@ module.exports = function createMockRippled(port) {
} else if (request.account === addresses.NOTFOUND) {
conn.send(createResponse(request, fixtures.account_info.notfound));
} else if (request.account === addresses.THIRD_ACCOUNT) {
const response = _.assign({}, fixtures.account_info.normal);
const response = Object.assign({}, fixtures.account_info.normal);
response.Account = addresses.THIRD_ACCOUNT;
conn.send(createResponse(request, response));
} else if (request.account === undefined) {
const response = Object.assign({}, {
error: 'invalidParams',
error_code: 31,
error_message: 'Missing field \'account\'.',
id: 2,
request: { command: 'account_info', id: 2 },
status: 'error',
type: 'response'
});
conn.send(createResponse(request, response));
} else {
assert(false, 'Unrecognized account address: ' + request.account);
const response = Object.assign({}, {
account: request.account,
error: 'actNotFound',
error_code: 19,
error_message: 'Account not found.',
id: 2,
ledger_current_index: 17714714,
request:
// This will be inaccurate, but that's OK because this is just a mock rippled
{ account: 'rogvkYnY8SWjxkJNgU4ZRVfLeRyt5DR9i',
command: 'account_info',
id: 2 },
status: 'error',
type: 'response',
validated: false
});
conn.send(createResponse(request, response));
}
});
@@ -267,6 +297,8 @@ module.exports = function createMockRippled(port) {
const response = _.assign({}, fixtures.ledger.normal,
{ result: { ledger: fullLedger } });
conn.send(createLedgerResponse(request, response));
} else if (request.ledger_hash === '15F20E5FA6EA9770BBFFDBD62787400960B04BE32803B20C41F117F41C13830D') {
conn.send(createLedgerResponse(request, fixtures.ledger.normalByHash));
} else if (request.ledger_index === 'validated' ||
request.ledger_index === 14661789 ||
request.ledger_index === 14661788 /* getTransaction - order */) {
@@ -464,6 +496,8 @@ module.exports = function createMockRippled(port) {
}
});
let requestsCache = undefined;
mock.on('request_book_offers', function (request, conn) {
if (request.taker_pays.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
conn.send(createResponse(request, fixtures.book_offers.xrp_usd));
@@ -479,6 +513,30 @@ module.exports = function createMockRippled(port) {
conn.send(
fixtures.book_offers.fabric.requestBookOffersAsksResponse(request));
} else {
const rippledDir = 'test/fixtures/rippled';
if (!requestsCache) {
requestsCache = fs.readdirSync(rippledDir + '/requests');
}
for (var i = 0; i < requestsCache.length; i++) {
const file = requestsCache[i];
const json = fs.readFileSync(rippledDir + '/requests/' + file, 'utf8');
const r = JSON.parse(json);
const requestWithoutId = Object.assign({}, request);
delete requestWithoutId.id;
if (JSON.stringify(requestWithoutId) === JSON.stringify(r)) {
const responseFile = rippledDir + '/responses/' + file.split('.')[0] + '-res.json';
const res = fs.readFileSync(responseFile, 'utf8');
const response = createResponse(request, {
"id": 0,
"type": "response",
"status": "success",
"result": JSON.parse(res)
});
conn.send(response);
return;
}
}
assert(false, 'Unrecognized order book: ' + JSON.stringify(request));
}
});

View File

@@ -1,32 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<!-- encoding must be set for mocha's special characters to render properly -->
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
<script src="/test/vendor/lodash.min.js"></script>
</head>
<body>
<div id="deb"></div>
<div id="mocha"></div>
<script src="/node_modules/mocha/mocha.js"></script>
<script src="/node_modules/mocha-in-sauce/client.js"></script>
<script src="/build/ripple-latest-min.js"></script>
<script>
mocha.ui('bdd')
</script>
<script src="../test-compiled-for-web/api-test.js"></script>
<script src="../test-compiled-for-web/broadcast-api-test.js"></script>
<script src="../test-compiled-for-web/connection-test.js"></script>
<script src="/test-compiled-for-web/rangeset-test.js"></script>
<script>
mochaSaucePlease({xunit: false});
</script>
</body>
</html>

1241
yarn.lock

File diff suppressed because it is too large Load Diff