Compare commits

...

18 Commits

Author SHA1 Message Date
Chris Clark
27ed1aadd5 Bump version to 0.14.0 2015-11-23 17:36:16 -08:00
Chris Clark
001f203983 Merge pull request #648 from clark800/memos
Allow memos on all transaction types
2015-11-23 17:25:09 -08:00
Chris Clark
515047d2dc Merge pull request #649 from clark800/darkdarkdragon-develop-RLJS-549
boost coverage to almost 100%
2015-11-23 17:24:46 -08:00
Ivan Tivonenko
995606b1e6 boost coverage to almost 100% 2015-11-23 17:06:55 -08:00
Chris Clark
b5081344da Allow memos on all transaction types 2015-11-23 14:12:32 -08:00
Chris Clark
4f86691fb8 Merge pull request #647 from clark800/cancellation-spec
BREAKING CHANGE: prepareOrderCancellation now takes orderCancellation specification instead of sequence
2015-11-23 13:14:00 -08:00
Chris Clark
45aca016d4 Merge pull request #646 from clark800/api-options-doc
Add documentation for RippleAPI options
2015-11-23 12:47:43 -08:00
Chris Clark
7f33d8a71e BREAKING CHANGE: prepareOrderCancellation now takes orderCancellation specification instead of sequence 2015-11-23 12:45:44 -08:00
Chris Clark
af620755c5 Fix trace option 2015-11-23 12:01:28 -08:00
Chris Clark
a76b554cad Add documentation for RippleAPI options 2015-11-23 12:01:28 -08:00
Chris Clark
ef1e9e1b70 Merge pull request #644 from mDuo13/patch-1
Docs: more on basic types, tx types
2015-11-23 10:23:38 -08:00
mDuo13
fdbac63f46 Docs: more on basic types, tx types 2015-11-20 18:49:03 -08:00
Chris Clark
377f1dbfa1 Merge pull request #643 from clark800/proxy-auth
Fix proxy support and add support for proxy authorization
2015-11-20 16:32:53 -08:00
Chris Clark
14b840f3fe Fix proxy support and add support for proxy authorization 2015-11-20 15:23:56 -08:00
Chris Clark
beb1cc0cde Merge pull request #642 from mDuo13/patch-1
Doc introduction changes
2015-11-20 14:30:05 -08:00
Rome Reginelli
ef2515507d Docs: revised introductory material 2015-11-20 14:15:40 -08:00
Chris Clark
a271b9e816 Merge pull request #641 from clark800/ledger-event
BREAKING CHANGE: Rename "ledgerClosed" event to "ledger" and convert drops amounts to XRP
2015-11-20 11:30:35 -08:00
Chris Clark
8a3d4a64db BREAKING CHANGE: Rename "ledgerClosed" event to "ledger" and convert drops amounts to XRP 2015-11-20 11:23:19 -08:00
85 changed files with 2417 additions and 266 deletions

View File

@@ -1,3 +1,17 @@
##0.14.0
**Breaking Changes**
+ [prepareOrderCancellation now takes orderCancellation specification](https://github.com/ripple/ripple-lib/commit/7f33d8a71e56289e5a5e0ead1c74f75ebcde72bc)
+ [Rename "ledgerClosed" event to "ledger" and change format](https://github.com/ripple/ripple-lib/commit/8a3d4a64db5fbf560ebf87dc62e0212513c5e18a)
**Changes**
+ [Fix proxy support and add support for proxy authorization](https://github.com/ripple/ripple-lib/commit/14b840f3feca758e0384b746c94e36d8bf59b8c2)
+ [Fix trace option](https://github.com/ripple/ripple-lib/commit/af620755c53556c55eed12de4b0013ef5a349ce2)
+ [Allow memos on all transaction types](https://github.com/ripple/ripple-lib/commit/b5081344da8e66fbd3a5113cc3313325ef72a494)
+ [Add documentation for RippleAPI options](https://github.com/ripple/ripple-lib/commit/a76b554cadb9f9f918b06f8386bc29355682a1a4)
+ [Docs: more on basic types, tx types](https://github.com/ripple/ripple-lib/commit/fdbac63f466b4fd3be701d4878800d856692e26e)
+ [Docs: revised introductory material](https://github.com/ripple/ripple-lib/commit/ef2515507dbd3c6a426ab5b31332a1bdf72d5b2d)
+ [boost coverage to almost 100%](https://github.com/ripple/ripple-lib/commit/995606b1e6f3643af34d9fd442ccd31f320b03eb)
##0.13.2
**Changes**

View File

@@ -16,6 +16,7 @@
- [Transaction Fees](#transaction-fees)
- [Transaction Instructions](#transaction-instructions)
- [Transaction ID](#transaction-id)
- [Transaction Memos](#transaction-memos)
- [Transaction Specifications](#transaction-specifications)
- [Payment](#payment)
- [Trustline](#trustline)
@@ -56,24 +57,33 @@
- [generateAddress](#generateaddress)
- [computeLedgerHash](#computeledgerhash)
- [API Events](#api-events)
- [ledgerClosed](#ledgerclosed)
- [ledger](#ledger)
- [error](#error)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Introduction
RippleAPI allows you to query and submit transactions to a node on the Ripple network.
RippleAPI is the official client library to the Ripple Consensus Ledger. Currently, RippleAPI is only available in JavaScript.
Using RippleAPI, you can:
* [Query transactions from the network](#gettransaction)
* [Sign](#sign) transactions securely without connecting to any server
* [Submit](#submit) transactions to the Ripple Consensus Ledger, including [Payments](#payment), [Orders](#order), [Settings changes](#settings), and [other types](#transaction-types)
* [Generate a new Ripple Address](#generateaddress)
* ... and [much more](#api-methods).
RippleAPI only provides access to *validated*, *immutable* transaction data.
## Boilerplate
Use the following [boilerplate code](https://en.wikipedia.org/wiki/Boilerplate_code) to wrap your custom code using RippleAPI.
```javascript
const {RippleAPI} = require('ripple-lib');
const api = new RippleAPI({
servers: ['wss://s1.ripple.com']
servers: ['wss://s1.ripple.com'] //Public rippled server hosted by Ripple, Inc.
});
api.connect().then(() => {
/* insert code here */
@@ -82,26 +92,48 @@ api.connect().then(() => {
}).catch(console.error);
```
To get started, first install [nodejs](https://nodejs.org) version `0.12.0` or greater, then:
RippleAPI is designed to work in [NodeJS](https://nodejs.org) (version `0.12.0` or greater) using [Babel](https://babeljs.io/) for [ECMAScript 6](https://babeljs.io/docs/learn-es2015/) support.
`npm install -g babel`
`npm install ripple-lib`
Then create a script based on the boilerplate shown here and run with:
`babel-node script.js`
The code samples in this documentation are written in ES6, but `RippleAPI` will work with ES5 also. Regardless of whether you use ES5 or ES6, the methods that return promises will return ES6-style promises.
The code samples in this documentation are written in ES6, but `RippleAPI` will work with ES5 also. Regardless of whether you use ES5 or ES6, the methods that return promises will return [ES6-style promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise_).
<aside class="notice">
All the code snippets in this documentation assume that you have surrounded them with this boilerplate.
</aside>
<aside class="notice">
Dont forget the "catch" or errors may not be visible.
If you omit the "catch" section, errors may not be visible.
</aside>
### Parameters
Name | Type | Description
---- | ---- | -----------
authorization | string | *Optional* Username and password for HTTP basic authentication to the rippled server in the format **username:password**.
feeCushion | number | *Optional* Factor to multiply estimated fee by to provide a cushion in case the required fee rises during submission of a transaction. Defaults to `1.2`.
proxy | uri string | *Optional* URI for HTTP/HTTPS proxy to use to connect to the rippled server.
proxyAuthorization | string | *Optional* Username and password for HTTP basic authentication to the proxy in the format **username:password**.
servers | array\<uri string\> | *Optional* Array of rippled servers to connect to. Currently only one server is supported.
timeout | integer | *Optional* Timeout in milliseconds before considering a request to have failed.
trace | boolean | *Optional* If true, log rippled requests and responses to stdout.
trustedCertificates | array\<string\> | *Optional* Array of PEM-formatted SSL certificates to trust when connecting to a proxy. This is useful if you want to use a self-signed certificate on the proxy server. Note: Each element must contain a single certificate; concatenated certificates are not valid.
### Installation ###
1. Install [NodeJS](https://nodejs.org) and the Node Package Manager (npm). Most Linux distros have a package for NodeJS, but make sure you have version `0.12.0` or higher.
2. Use npm to install [Babel](https://babeljs.io/) globally:
`npm install -g babel`
3. Use npm to install RippleAPI:
`npm install ripple-lib`
After you have installed ripple-lib, you can create scripts using the [boilerplate](#boilerplate) and run them using babel-node:
`babel-node script.js`
<aside class="notice">
Instead of using babel-node in production, we recommend using Babel to transpile to ECMAScript 5 first.
</aside>
# Basic Types
## Ripple Address
@@ -110,23 +142,28 @@ Dont forget the "catch" or errors may not be visible.
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
```
Every Ripple account has an *address*, which is a base58-encoding of a hash of the account's public key.
Every Ripple account has an *address*, which is a base58-encoding of a hash of the account's public key. Ripple addresses always start with the lowercase letter `r`.
## Account Sequence Number
Every Ripple account has a *sequence number* that is used to order transactions. Every transaction must have a sequence number and transaction can only be executed in order by sequence number. This prevents one transaction from executing twice and transactions executing out of order. The sequence number starts at `1` and increments for each transaction that the account makes.
Every Ripple account has a *sequence number* that is used to keep transactions in order. Every transaction must have a sequence number. A transaction can only be executed if it has the next sequence number in order, of the account sending it. This prevents one transaction from executing twice and transactions executing out of order. The sequence number starts at `1` and increments for each transaction that the account makes.
## Currency
Currencies are represented as either 3-character currency codes or 40-character uppercase hexadecimal strings. We recommend using uppercase [ISO 4217 Currency Codes](http://www.xe.com/iso4217.php) only. The string "XRP" is disallowed on trustlines because it is reserved for the Ripple native currency. The following characters are permitted: all uppercase and lowercase letters, digits, as well as the symbols `?`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, and `|`.
## Value
A *value* is a quantity of a currency represented as a decimal string (string encoding is used because javascript numbers do not have sufficient precision).
A *value* is a quantity of a currency represented as a decimal string. Be careful: JavaScript's native number format does not have sufficient precision to represent all values. XRP has different precision from other currencies.
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
An XRP value has 6 significant digits past the decimal point. A non-XRP value has 16 total digits of precision.
## Amount
Example amount:
```json
{
"currency": "USD",
@@ -135,6 +172,7 @@ An XRP value has 6 significant digits past the decimal point. A non-XRP value ha
}
```
Example XRP amount:
```json
{
"currency": "XRP",
@@ -142,7 +180,7 @@ An XRP value has 6 significant digits past the decimal point. A non-XRP value ha
}
```
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value (for all currencies besides "XRP").
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value. For XRP, there is no counterparty.
A *lax amount* allows the counterparty to be omitted for all currencies. If the counterparty is not specified in an amount within a transaction specification, then any counterparty may be used for that amount.
@@ -164,7 +202,7 @@ A transaction type is specified by the strings in the first column in the table
Type | Description
---- | -----------
[payment](#payment) | A `payment` transaction represents a transfer of value from one account to another. Depending on the path taken, additional exchanges of value may occur atomically to facilitate the payment.
[payment](#payment) | A `payment` transaction represents a transfer of value from one account to another. Depending on the [path](https://ripple.com/build/paths/) taken, additional exchanges of value may occur atomically to facilitate the payment.
[order](#order) | An `order` transaction creates a limit order. It defines an intent to exchange currencies, and creates an order in the Ripple Consensus Ledger's order book if not completely fulfilled when placed. Orders can be partially fulfilled.
[orderCancellation](#order-cancellation) | An `orderCancellation` transaction cancels an order in the Ripple Consensus Ledger's order book.
[trustline](#trustline) | A `trustline` transactions creates or modifies a trust line between two accounts.
@@ -177,20 +215,28 @@ Type | Description
Executing a transaction with `RippleAPI` requires the following four steps:
1. prepare - Create an unsigned transaction based on a [specification](#transaction-specifications) and [instructions](#transaction-instructions).
2. sign - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place.
3. submit - Submit the transaction to the connected server.
4. verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted. It is recommended that you specify a `maxLedgerVersion` in the instructions when preparing a transaction because without it there is no way to know that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the network ledger version exceeds the `maxLedgerVersion` provided in the transaction instructions.
1. Prepare - Create an unsigned transaction based on a [specification](#transaction-specifications) and [instructions](#transaction-instructions). There is a method to prepare each type of transaction:
* [preparePayment](#preparepayment)
* [prepareTrustline](#preparetrustline)
* [prepareOrder](#prepareorder)
* [prepareOrderCancellation](#prepareordercancellation)
* [prepareSettings](#preparesettings)
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place.
3. [Submit](#submit) - Submit the transaction to the connected server.
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
## Transaction Fees
Every transaction requires a *fee* to be paid in XRP. The fee is destroyed; it is not sent to any other party. The purpose of the fee is to prevent denial of service attacks on the Ripple network.
Every transaction must destroy a small amount of XRP as a cost to send the transaction. This is also called a *transaction fee*. The transaction cost is designed to increase along with the load on the Ripple network, making it very expensive to deliberately or inadvertently overload the network.
You can choose the size of the fee you want to pay or let a default be used. The fee is like a bid in an auction for slots in the next ledger closing. If the fee you choose is too low, your transaction will not be included in the next ledger closing. You can get an estimate of the fee required to be included in the next ledger closing with the [getFee](#getfee) method.
You can choose the size of the fee you want to pay or let a default be used. You can get an estimate of the fee required to be included in the next ledger closing with the [getFee](#getfee) method.
## Transaction Instructions
Transactions instructions indicates how to execute a transaction, complementary with the [transaction specification](#transaction-specifications).
Transaction instructions indicate how to execute a transaction, complementary with the [transaction specification](#transaction-specifications).
Name | Type | Description
---- | ---- | -----------
@@ -200,13 +246,27 @@ maxLedgerVersion | integer | *Optional* The highest ledger version that the tran
maxLedgerVersionOffset | integer | *Optional* Offset from current legder version to highest ledger version that the transaction can be included in.
sequence | [sequence](#account-sequence-number) | *Optional* The initiating account's sequence number for this transaction.
We recommended that you specify a `maxLedgerVersion` because without it there is no way to know that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the network ledger version exceeds the transaction's `maxLedgerVersion`.
## Transaction ID
```json
"F4AB442A6D4CBB935D66E1DA7309A5FC71C7143ED4049053EC14E3875B0CF9BF"
```
A hash of the transaction that can be used to identify it. A transaction can be looked up by its ID using the [getTransaction](#gettransaction) method.
A transaction ID is a 64-bit hexadecimal string that uniquely identifies the transaction. The transaction ID is derived from the transaction instruction and specifications, using a strong hash function.
You can look up a transaction by ID using the [getTransaction](#gettransaction) method.
## Transaction Memos
Every transaction can optionally have an array of memos for user applications. The `memos` field in each [transaction specification](#transaction-specifications) is an array of objects with the following structure:
Name | Type | Description
---- | ---- | -----------
data | string | *Optional* Arbitrary string, conventionally containing the content of the memo.
format | string | *Optional* Conventionally containing information on how the memo is encoded, for example as a [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml). Only characters allowed in URLs are permitted.
type | string | *Optional* Conventionally, a unique relation (according to [RFC 5988](http://tools.ietf.org/html/rfc5988#section-4)) that defines the format of this memo. Only characters allowed in URLs are permitted.
# Transaction Specifications
@@ -232,11 +292,7 @@ destination | object | The destination of the funds to be sent.
allowPartialPayment | boolean | *Optional* A boolean that, if set to true, indicates that this payment should go through even if the whole amount cannot be delivered because of a lack of liquidity or funds in the source account account
invoiceID | string | *Optional* A 256-bit hash that can be used to identify a particular payment.
limitQuality | boolean | *Optional* Only take paths where all the conversions have an input:output ratio that is equal or better than the ratio of destination.amount:source.maxAmount.
memos | array | *Optional* Array of memos to attach to the transaction.
memos[] | object | Memo objects represent arbitrary data that can be included in a transaction
*memos[].* data | string | *Optional* Arbitrary string, conventionally containing the content of the memo.
*memos[].* format | string | *Optional* Conventionally containing information on how the memo is encoded, for example as a [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml). Only characters allowed in URLs are permitted.
*memos[].* type | string | *Optional* Conventionally, a unique relation (according to [RFC 5988](http://tools.ietf.org/html/rfc5988#section-4)) that defines the format of this memo. Only characters allowed in URLs are permitted.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
noDirectRipple | boolean | *Optional* A boolean that can be set to true if paths are specified and the sender would like the Ripple Network to disregard any direct paths from the source account to the destination account. This may be used to take advantage of an arbitrage opportunity or by gateways wishing to issue balances from a hot wallet to a user who has mistakenly set a trustline directly to the hot wallet
paths | string | *Optional* The paths of trustlines and orders to use in executing the payment.
@@ -276,6 +332,7 @@ counterparty | [address](#ripple-address) | The address of the account this trus
limit | [value](#value) | The maximum amount that the owner of the trustline can be owed through the trustline.
authorized | boolean | *Optional* If true, authorize the counterparty to hold issuances from this account.
frozen | boolean | *Optional* If true, the trustline is frozen, which means that funds can only be sent to the owner.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
qualityIn | number | *Optional* Incoming balances on this trustline are valued at this ratio.
qualityOut | number | *Optional* Outgoing balances on this trustline are valued at this ratio.
ripplingDisabled | boolean | *Optional* If true, payments cannot ripple through this trustline.
@@ -308,6 +365,7 @@ totalPrice | [amount](#amount) | The total price to be paid for the `quantity` t
expirationTime | date-time string | *Optional* Time after which the offer is no longer active, as an [ISO 8601 date-time](https://en.wikipedia.org/wiki/ISO_8601).
fillOrKill | boolean | *Optional* Treat the offer as a [Fill or Kill order](http://en.wikipedia.org/wiki/Fill_or_kill). Only attempt to match existing offers in the ledger, and only do so if the entire quantity can be exchanged.
immediateOrCancel | boolean | *Optional* Treat the offer as an [Immediate or Cancel order](http://en.wikipedia.org/wiki/Immediate_or_cancel). If enabled, the offer will never become a ledger node: it only attempts to match existing offers in the ledger.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
passive | boolean | *Optional* If enabled, the offer will not consume offers that exactly match it, and instead becomes an Offer node in the ledger. It will still consume offers that cross it.
### Example
@@ -325,7 +383,8 @@ passive | boolean | *Optional* If enabled, the offer will not consume offers tha
"currency": "XRP",
"value": "2"
},
"immediateOrCancel": true
"passive": true,
"fillOrKill": true
}
```
@@ -337,12 +396,15 @@ See [Transaction Types](#transaction-types) for a description.
Name | Type | Description
---- | ---- | -----------
orderSequence | [sequence](#account-sequence-number) | The [account sequence number](#account-sequence-number) of the order to cancel.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
### Example
```json
23
{
"orderSequence": 23
}
```
@@ -359,6 +421,7 @@ domain | string | *Optional* The domain that owns this account, as a hexadecima
emailHash | string,null | *Optional* Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.
enableTransactionIDTracking | boolean | *Optional* Track the ID of this accounts most recent transaction.
globalFreeze | boolean | *Optional* Freeze all assets issued by this account.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
messageKey | string | *Optional* Public key for sending encrypted messages to this account. Conventionally, it should be a secp256k1 key, the same encryption that is used by the rest of Ripple.
noFreeze | boolean | *Optional* Permanently give up the ability to freeze individual trust lines. This flag can never be disabled after being enabled.
passwordSpent | boolean | *Optional* Indicates that the account has used its free SetRegularKey transaction.
@@ -394,11 +457,7 @@ destination | object | Fields pertaining to the destination of the payment.
allowCancelAfter | date-time string | *Optional* If present, the suspended payment may be cancelled after this time.
allowExecuteAfter | date-time string | *Optional* If present, the suspended payment can not be executed before this time.
digest | string | *Optional* If present, proof is required upon execution.
memos | array | *Optional* Array of memos to attach to the transaction.
memos[] | object | Memo objects represent arbitrary data that can be included in a transaction
*memos[].* data | string | *Optional* Arbitrary string, conventionally containing the content of the memo.
*memos[].* format | string | *Optional* Conventionally containing information on how the memo is encoded, for example as a [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml). Only characters allowed in URLs are permitted.
*memos[].* type | string | *Optional* Conventionally, a unique relation (according to [RFC 5988](http://tools.ietf.org/html/rfc5988#section-4)) that defines the format of this memo. Only characters allowed in URLs are permitted.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
### Example
@@ -434,11 +493,7 @@ Name | Type | Description
---- | ---- | -----------
owner | [address](#ripple-address) | The address of the owner of the suspended payment to cancel.
suspensionSequence | [sequence](#account-sequence-number) | The [account sequence number](#account-sequence-number) of the [Suspended Payment Creation](#suspended-payment-creation) transaction for the suspended payment to cancel.
memos | array | *Optional* Array of memos to attach to the transaction.
memos[] | object | Memo objects represent arbitrary data that can be included in a transaction
*memos[].* data | string | *Optional* Arbitrary string, conventionally containing the content of the memo.
*memos[].* format | string | *Optional* Conventionally containing information on how the memo is encoded, for example as a [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml). Only characters allowed in URLs are permitted.
*memos[].* type | string | *Optional* Conventionally, a unique relation (according to [RFC 5988](http://tools.ietf.org/html/rfc5988#section-4)) that defines the format of this memo. Only characters allowed in URLs are permitted.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
### Example
@@ -460,11 +515,7 @@ Name | Type | Description
owner | [address](#ripple-address) | The address of the owner of the suspended payment to execute.
suspensionSequence | [sequence](#account-sequence-number) | The [account sequence number](#account-sequence-number) of the [Suspended Payment Creation](#suspended-payment-creation) transaction for the suspended payment to execute.
digest | string | *Optional* The original `digest` from the suspended payment creation transaction. This is sha256 hash of `proof` string. It is replicated here so that the relatively expensive hashing operation can be delegated to a server without ledger history and the server with ledger history only has to do a quick comparison of the old digest with the new digest.
memos | array | *Optional* Array of memos to attach to the transaction.
memos[] | object | Memo objects represent arbitrary data that can be included in a transaction
*memos[].* data | string | *Optional* Arbitrary string, conventionally containing the content of the memo.
*memos[].* format | string | *Optional* Conventionally containing information on how the memo is encoded, for example as a [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml). Only characters allowed in URLs are permitted.
*memos[].* type | string | *Optional* Conventionally, a unique relation (according to [RFC 5988](http://tools.ietf.org/html/rfc5988#section-4)) that defines the format of this memo. Only characters allowed in URLs are permitted.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
method | integer | *Optional* The method for verifying the proof; only method `1` is supported.
proof | string | *Optional* A value that produces the digest when hashed. It must be 32 charaters long and contain only 8-bit characters.
@@ -575,8 +626,8 @@ validatedLedger | object | Information about the fully-validated ledger with the
*validatedLedger.* age | integer | The time since the ledger was closed, in seconds.
*validatedLedger.* baseFeeXRP | number | Base fee, in XRP. This may be represented in scientific notation such as 1e-05 for 0.00005.
*validatedLedger.* hash | string | Unique hash for the ledger, as an uppercase hexadecimal string.
*validatedLedger.* reserveBaseXRP | integer | Minimum amount of XRP (not drops) necessary for every account to keep in reserve.
*validatedLedger.* reserveIncrementXRP | integer | Amount of XRP (not drops) added to the account reserve for each object an account is responsible for in the ledger.
*validatedLedger.* reserveBaseXRP | integer | Minimum amount of XRP necessary for every account to keep in reserve.
*validatedLedger.* reserveIncrementXRP | integer | Amount of XRP added to the account reserve for each object an account is responsible for in the ledger.
*validatedLedger.* ledgerVersion | integer | Identifying sequence number of this ledger version.
validationQuorum | number | Minimum number of trusted validations required in order to validate a ledger version. Some circumstances may cause the server to require more validations.
load | object | *Optional* *(Admin only)* Detailed information about the current load state of the server.
@@ -1070,7 +1121,7 @@ counterparty | object | Properties of the trustline from the perspective of the
*counterparty.* frozen | boolean | *Optional* If true, the trustline is frozen, which means that funds can only be sent to the counterparty.
*counterparty.* ripplingDisabled | boolean | *Optional* If true, payments cannot ripple through this trustline.
state | object | Properties of the trustline regarding it's current state that are not part of the specification.
*state.* balance | [value](#value) | The balance on the trustline, representing which party owes the other and by how much.
*state.* balance | [signedValue](#value) | The balance on the trustline, representing which party owes the other and by how much.
### Example
@@ -2527,6 +2578,7 @@ domain | string | *Optional* The domain that owns this account, as a hexadecima
emailHash | string,null | *Optional* Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.
enableTransactionIDTracking | boolean | *Optional* Track the ID of this accounts most recent transaction.
globalFreeze | boolean | *Optional* Freeze all assets issued by this account.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
messageKey | string | *Optional* Public key for sending encrypted messages to this account. Conventionally, it should be a secp256k1 key, the same encryption that is used by the rest of Ripple.
noFreeze | boolean | *Optional* Permanently give up the ability to freeze individual trust lines. This flag can never be disabled after being enabled.
passwordSpent | boolean | *Optional* Indicates that the account has used its free SetRegularKey transaction.
@@ -2838,7 +2890,8 @@ const order = {
"currency": "XRP",
"value": "2"
},
"immediateOrCancel": true
"passive": true,
"fillOrKill": true
};
return api.prepareOrder(address, order)
.then(prepared => {/* ... */});
@@ -2847,11 +2900,11 @@ return api.prepareOrder(address, order)
```json
{
"txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8820051
"maxLedgerVersion": 8819954
}
}
```
@@ -2868,7 +2921,7 @@ Prepare an order cancellation transaction. The prepared transaction must subsequ
Name | Type | Description
---- | ---- | -----------
address | [address](#ripple-address) | The address of the account that is creating the transaction.
sequence | [sequence](#account-sequence-number) | The account sequence number of the transaction that created the order to cancel.
orderCancellation | [orderCancellation](#order-cancellation) | The specification of the order cancellation to prepare.
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
### Return Value
@@ -2891,7 +2944,7 @@ instructions | object | The instructions for how to execute the transaction afte
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const sequence = 123;
const orderCancellation = {orderSequence: 123};
return api.prepareOrderCancellation(address, sequence)
.then(prepared => {/* ... */});
```
@@ -3311,7 +3364,7 @@ return api.computeLedgerHash(ledger);
# API Events
## ledgerClosed
## ledger
This event is emitted whenever a new ledger version is validated on the connected server.
@@ -3319,12 +3372,11 @@ This event is emitted whenever a new ledger version is validated on the connecte
Name | Type | Description
---- | ---- | -----------
feeBase | integer | Base fee, in drops.
feeReference | integer | Cost of the 'reference transaction' in 'fee units'.
baseFeeXRP | [value](#value) | Base fee, in XRP.
ledgerHash | string | Unique hash of the ledger that was closed, as hex.
ledgerTimestamp | date-time string | The time at which this ledger closed.
reserveBase | integer | The minimum reserve, in drops of XRP, that is required for an account.
reserveIncrement | integer | The increase in account reserve that is added for each item the account owns, such as offers or trust lines.
reserveBaseXRP | [value](#value) | The minimum reserve, in drops of XRP, that is required for an account.
reserveIncrementXRP | [value](#value) | The increase in account reserve that is added for each item the account owns, such as offers or trust lines.
transactionCount | integer | Number of new transactions included in this ledger.
ledgerVersion | integer | Ledger version of the ledger that closed.
validatedLedgerVersions | string | Range of ledgers that the server has available. This may be discontiguous.
@@ -3332,7 +3384,7 @@ validatedLedgerVersions | string | Range of ledgers that the server has availabl
### Example
```javascript
api.on('ledgerClosed', ledger => {
api.on('ledger', ledger => {
console.log(JSON.stringify(ledger, null, 2));
});
```
@@ -3340,13 +3392,12 @@ api.on('ledgerClosed', ledger => {
```json
{
"feeBase": 10,
"feeReference": 10,
"baseFeeXRP": "0.00001",
"ledgerVersion": 14804627,
"ledgerHash": "9141FA171F2C0CE63E609466AF728FF66C12F7ACD4B4B50B0947A7F3409D593A",
"ledgerTimestamp": "2015-07-23T05:50:40.000Z",
"reserveBase": 20000000,
"reserveIncrement": 5000000,
"reserveBaseXRP": "20",
"reserveIncrementXRP": "5",
"transactionCount": 19,
"validatedLedgerVersions": "13983423-14804627"
}

View File

@@ -6,23 +6,28 @@
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
```
Every Ripple account has an *address*, which is a base58-encoding of a hash of the account's public key.
Every Ripple account has an *address*, which is a base58-encoding of a hash of the account's public key. Ripple addresses always start with the lowercase letter `r`.
## Account Sequence Number
Every Ripple account has a *sequence number* that is used to order transactions. Every transaction must have a sequence number and transaction can only be executed in order by sequence number. This prevents one transaction from executing twice and transactions executing out of order. The sequence number starts at `1` and increments for each transaction that the account makes.
Every Ripple account has a *sequence number* that is used to keep transactions in order. Every transaction must have a sequence number. A transaction can only be executed if it has the next sequence number in order, of the account sending it. This prevents one transaction from executing twice and transactions executing out of order. The sequence number starts at `1` and increments for each transaction that the account makes.
## Currency
Currencies are represented as either 3-character currency codes or 40-character uppercase hexadecimal strings. We recommend using uppercase [ISO 4217 Currency Codes](http://www.xe.com/iso4217.php) only. The string "XRP" is disallowed on trustlines because it is reserved for the Ripple native currency. The following characters are permitted: all uppercase and lowercase letters, digits, as well as the symbols `?`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, and `|`.
## Value
A *value* is a quantity of a currency represented as a decimal string (string encoding is used because javascript numbers do not have sufficient precision).
A *value* is a quantity of a currency represented as a decimal string. Be careful: JavaScript's native number format does not have sufficient precision to represent all values. XRP has different precision from other currencies.
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
An XRP value has 6 significant digits past the decimal point. A non-XRP value has 16 total digits of precision.
## Amount
Example amount:
```json
{
"currency": "USD",
@@ -31,6 +36,7 @@ An XRP value has 6 significant digits past the decimal point. A non-XRP value ha
}
```
Example XRP amount:
```json
{
"currency": "XRP",
@@ -38,7 +44,7 @@ An XRP value has 6 significant digits past the decimal point. A non-XRP value ha
}
```
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value (for all currencies besides "XRP").
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value. For XRP, there is no counterparty.
A *lax amount* allows the counterparty to be omitted for all currencies. If the counterparty is not specified in an amount within a transaction specification, then any counterparty may be used for that amount.

View File

@@ -1,10 +1,12 @@
## Boilerplate
Use the following [boilerplate code](https://en.wikipedia.org/wiki/Boilerplate_code) to wrap your custom code using RippleAPI.
```javascript
const {RippleAPI} = require('ripple-lib');
const api = new RippleAPI({
servers: ['wss://s1.ripple.com']
servers: ['wss://s1.ripple.com'] //Public rippled server hosted by Ripple, Inc.
});
api.connect().then(() => {
/* insert code here */
@@ -13,22 +15,35 @@ api.connect().then(() => {
}).catch(console.error);
```
To get started, first install [nodejs](https://nodejs.org) version `0.12.0` or greater, then:
RippleAPI is designed to work in [NodeJS](https://nodejs.org) (version `0.12.0` or greater) using [Babel](https://babeljs.io/) for [ECMAScript 6](https://babeljs.io/docs/learn-es2015/) support.
`npm install -g babel`
`npm install ripple-lib`
Then create a script based on the boilerplate shown here and run with:
`babel-node script.js`
The code samples in this documentation are written in ES6, but `RippleAPI` will work with ES5 also. Regardless of whether you use ES5 or ES6, the methods that return promises will return ES6-style promises.
The code samples in this documentation are written in ES6, but `RippleAPI` will work with ES5 also. Regardless of whether you use ES5 or ES6, the methods that return promises will return [ES6-style promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise_).
<aside class="notice">
All the code snippets in this documentation assume that you have surrounded them with this boilerplate.
</aside>
<aside class="notice">
Dont forget the "catch" or errors may not be visible.
If you omit the "catch" section, errors may not be visible.
</aside>
### Parameters
<%- renderSchema('input/api-options.json') %>
### Installation ###
1. Install [NodeJS](https://nodejs.org) and the Node Package Manager (npm). Most Linux distros have a package for NodeJS, but make sure you have version `0.12.0` or higher.
2. Use npm to install [Babel](https://babeljs.io/) globally:
`npm install -g babel`
3. Use npm to install RippleAPI:
`npm install ripple-lib`
After you have installed ripple-lib, you can create scripts using the [boilerplate](#boilerplate) and run them using babel-node:
`babel-node script.js`
<aside class="notice">
Instead of using babel-node in production, we recommend using Babel to transpile to ECMAScript 5 first.
</aside>

View File

@@ -1,22 +1,22 @@
# API Events
## ledgerClosed
## ledger
This event is emitted whenever a new ledger version is validated on the connected server.
### Return Value
<%- renderSchema('output/ledger-closed.json') %>
<%- renderSchema('output/ledger-event.json') %>
### Example
```javascript
api.on('ledgerClosed', ledger => {
api.on('ledger', ledger => {
console.log(JSON.stringify(ledger, null, 2));
});
```
<%- renderFixture('responses/ledger-closed.json') %>
<%- renderFixture('responses/ledger-event.json') %>
## error

View File

@@ -1,5 +1,12 @@
# Introduction
RippleAPI allows you to query and submit transactions to a node on the Ripple network.
RippleAPI is the official client library to the Ripple Consensus Ledger. Currently, RippleAPI is only available in JavaScript.
Using RippleAPI, you can:
* [Query transactions from the network](#gettransaction)
* [Sign](#sign) transactions securely without connecting to any server
* [Submit](#submit) transactions to the Ripple Consensus Ledger, including [Payments](#payment), [Orders](#order), [Settings changes](#settings), and [other types](#transaction-types)
* [Generate a new Ripple Address](#generateaddress)
* ... and [much more](#api-methods).
RippleAPI only provides access to *validated*, *immutable* transaction data.

View File

@@ -22,7 +22,7 @@ All "prepare" methods have the same return type.
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const sequence = 123;
const orderCancellation = {orderSequence: 123};
return api.prepareOrderCancellation(address, sequence)
.then(prepared => {/* ... */});
```

View File

@@ -6,7 +6,7 @@ A transaction type is specified by the strings in the first column in the table
Type | Description
---- | -----------
[payment](#payment) | A `payment` transaction represents a transfer of value from one account to another. Depending on the path taken, additional exchanges of value may occur atomically to facilitate the payment.
[payment](#payment) | A `payment` transaction represents a transfer of value from one account to another. Depending on the [path](https://ripple.com/build/paths/) taken, additional exchanges of value may occur atomically to facilitate the payment.
[order](#order) | An `order` transaction creates a limit order. It defines an intent to exchange currencies, and creates an order in the Ripple Consensus Ledger's order book if not completely fulfilled when placed. Orders can be partially fulfilled.
[orderCancellation](#order-cancellation) | An `orderCancellation` transaction cancels an order in the Ripple Consensus Ledger's order book.
[trustline](#trustline) | A `trustline` transactions creates or modifies a trust line between two accounts.
@@ -19,27 +19,45 @@ Type | Description
Executing a transaction with `RippleAPI` requires the following four steps:
1. prepare - Create an unsigned transaction based on a [specification](#transaction-specifications) and [instructions](#transaction-instructions).
2. sign - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place.
3. submit - Submit the transaction to the connected server.
4. verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted. It is recommended that you specify a `maxLedgerVersion` in the instructions when preparing a transaction because without it there is no way to know that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the network ledger version exceeds the `maxLedgerVersion` provided in the transaction instructions.
1. Prepare - Create an unsigned transaction based on a [specification](#transaction-specifications) and [instructions](#transaction-instructions). There is a method to prepare each type of transaction:
* [preparePayment](#preparepayment)
* [prepareTrustline](#preparetrustline)
* [prepareOrder](#prepareorder)
* [prepareOrderCancellation](#prepareordercancellation)
* [prepareSettings](#preparesettings)
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place.
3. [Submit](#submit) - Submit the transaction to the connected server.
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
## Transaction Fees
Every transaction requires a *fee* to be paid in XRP. The fee is destroyed; it is not sent to any other party. The purpose of the fee is to prevent denial of service attacks on the Ripple network.
Every transaction must destroy a small amount of XRP as a cost to send the transaction. This is also called a *transaction fee*. The transaction cost is designed to increase along with the load on the Ripple network, making it very expensive to deliberately or inadvertently overload the network.
You can choose the size of the fee you want to pay or let a default be used. The fee is like a bid in an auction for slots in the next ledger closing. If the fee you choose is too low, your transaction will not be included in the next ledger closing. You can get an estimate of the fee required to be included in the next ledger closing with the [getFee](#getfee) method.
You can choose the size of the fee you want to pay or let a default be used. You can get an estimate of the fee required to be included in the next ledger closing with the [getFee](#getfee) method.
## Transaction Instructions
Transactions instructions indicates how to execute a transaction, complementary with the [transaction specification](#transaction-specifications).
Transaction instructions indicate how to execute a transaction, complementary with the [transaction specification](#transaction-specifications).
<%- renderSchema("objects/instructions.json") %>
We recommended that you specify a `maxLedgerVersion` because without it there is no way to know that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the network ledger version exceeds the transaction's `maxLedgerVersion`.
## Transaction ID
```json
"F4AB442A6D4CBB935D66E1DA7309A5FC71C7143ED4049053EC14E3875B0CF9BF"
```
A hash of the transaction that can be used to identify it. A transaction can be looked up by its ID using the [getTransaction](#gettransaction) method.
A transaction ID is a 64-bit hexadecimal string that uniquely identifies the transaction. The transaction ID is derived from the transaction instruction and specifications, using a strong hash function.
You can look up a transaction by ID using the [getTransaction](#gettransaction) method.
## Transaction Memos
Every transaction can optionally have an array of memos for user applications. The `memos` field in each [transaction specification](#transaction-specifications) is an array of objects with the following structure:
<%- renderSchema('objects/memos.json') %>

2
npm-shrinkwrap.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.13.2",
"version": "0.14.0",
"dependencies": {
"ajv": {
"version": "1.4.8",

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.13.2",
"version": "0.14.0",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [

View File

@@ -16,8 +16,11 @@ class Connection extends EventEmitter {
constructor(url, options = {}) {
super();
this._url = url;
this._proxyURL = options.proxyURL;
this._trace = options.trace;
this._proxyURL = options.proxy;
this._proxyAuthorization = options.proxyAuthorization;
this._authorization = options.authorization;
this._trustedCertificates = options.trustedCertificates;
this._timeout = options.timeout || (20 * 1000);
this._isReady = false;
this._ws = null;
@@ -50,6 +53,9 @@ class Connection extends EventEmitter {
_onMessage(message) {
let parameters;
if (this._trace) {
console.log(message);
}
try {
parameters = this._parseMessage(message);
} catch (error) {
@@ -74,6 +80,7 @@ class Connection extends EventEmitter {
}
_onUnexpectedClose() {
this._ws = null;
this._isReady = false;
this.connect().then();
}
@@ -92,12 +99,18 @@ class Connection extends EventEmitter {
});
}
_createWebSocket(url, proxyURL, authorization) {
_createWebSocket(url, proxyURL, proxyAuthorization, authorization,
trustedCertificates) {
const options = {};
if (proxyURL !== undefined) {
const parsedURL = parseURL(url);
const proxyOptions = parseURL(proxyURL);
proxyOptions.secureEndpoint = (parsedURL.protocol === 'wss:');
proxyOptions.secureProxy = (proxyOptions.protocol === 'https:');
proxyOptions.auth = proxyAuthorization;
if (trustedCertificates) {
proxyOptions.ca = trustedCertificates;
}
let HttpsProxyAgent;
try {
HttpsProxyAgent = require('https-proxy-agent');
@@ -125,9 +138,11 @@ class Connection extends EventEmitter {
this._ws.once('open', resolve);
} else {
this._ws = this._createWebSocket(this._url, this._proxyURL,
this._authorization);
this._proxyAuthorization, this._authorization,
this._trustedCertificates);
this._ws.on('message', this._onMessage.bind(this));
this._ws.once('close', () => this._onUnexpectedClose);
this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(this);
this._ws.once('close', this._onUnexpectedCloseBound);
this._ws.once('open', () => this._onOpen().then(resolve, reject));
}
});
@@ -140,7 +155,7 @@ class Connection extends EventEmitter {
} else if (this._state === WebSocket.CLOSING) {
this._ws.once('close', resolve);
} else {
this._ws.removeListener('close', this._onUnexpectedClose);
this._ws.removeListener('close', this._onUnexpectedCloseBound);
this._ws.once('close', () => {
this._ws = null;
this._isReady = false;
@@ -182,6 +197,9 @@ class Connection extends EventEmitter {
}
_send(message) {
if (this._trace) {
console.log(message);
}
return new Promise((resolve, reject) => {
this._ws.send(message, undefined, (error, result) => {
if (error) {

View File

@@ -43,6 +43,7 @@ function loadSchemas() {
require('./schemas/objects/signed-value.json'),
require('./schemas/objects/orderbook.json'),
require('./schemas/objects/instructions.json'),
require('./schemas/objects/settings.json'),
require('./schemas/specifications/settings.json'),
require('./schemas/specifications/payment.json'),
require('./schemas/specifications/suspended-payment-cancellation.json'),
@@ -61,7 +62,7 @@ function loadSchemas() {
require('./schemas/output/get-orders.json'),
require('./schemas/output/order-change.json'),
require('./schemas/output/prepare.json'),
require('./schemas/output/ledger-closed.json'),
require('./schemas/output/ledger-event.json'),
require('./schemas/output/get-paths.json'),
require('./schemas/output/get-server-info.json'),
require('./schemas/output/get-settings.json'),

View File

@@ -3,21 +3,49 @@
"title": "api-options",
"type": "object",
"properties": {
"trace": {"type": "boolean"},
"feeCushion": {"$ref": "value"},
"trace": {
"type": "boolean",
"description": "If true, log rippled requests and responses to stdout."
},
"feeCushion": {
"type": "number",
"minimum": 1,
"description": "Factor to multiply estimated fee by to provide a cushion in case the required fee rises during submission of a transaction. Defaults to `1.2`."
},
"servers": {
"type": "array",
"description": "Array of rippled servers to connect to. Currently only one server is supported.",
"items": {
"type": "string",
"description": "URI for rippled websocket port. Must start with `wss://` or `ws://`.",
"format": "uri",
"pattern": "^wss?://"
}
},
"proxy": {
"format": "uri"
"format": "uri",
"description": "URI for HTTP/HTTPS proxy to use to connect to the rippled server."
},
"timeout": {
"type": "integer",
"description": "Timeout in milliseconds before considering a request to have failed.",
"minimum": 1
},
"proxyAuthorization": {
"type": "string",
"description": "Username and password for HTTP basic authentication to the proxy in the format **username:password**."
},
"authorization": {
"type": "string"
"type": "string",
"description": "Username and password for HTTP basic authentication to the rippled server in the format **username:password**."
},
"trustedCertificates": {
"type": "array",
"description": "Array of PEM-formatted SSL certificates to trust when connecting to a proxy. This is useful if you want to use a self-signed certificate on the proxy server. Note: Each element must contain a single certificate; concatenated certificates are not valid.",
"items": {
"type": "string",
"description": "A PEM-formatted SSL certificate to trust when connecting to a proxy."
}
}
},
"additionalProperties": false

View File

@@ -7,12 +7,12 @@
"$ref": "address",
"description": "The address of the account that is creating the transaction."
},
"sequence": {
"$ref": "sequence",
"description": "The account sequence number of the transaction that created the order to cancel."
"orderCancellation": {
"$ref": "orderCancellation",
"description": "The specification of the order cancellation to prepare."
},
"instructions": {"$ref": "instructions"}
},
"additionalProperties": false,
"required": ["address", "sequence"]
"required": ["address", "orderCancellation"]
}

View File

@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "memos",
"link": "transaction-memos",
"description": "Array of memos to attach to the transaction.",
"type": "array",
"items": {

View File

@@ -0,0 +1,74 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "settingsPlusMemos",
"type": "object",
"properties": {
"passwordSpent": {
"type": "boolean",
"description": "Indicates that the account has used its free SetRegularKey transaction."
},
"requireDestinationTag": {
"type": "boolean",
"description": "Requires incoming payments to specify a destination tag."
},
"requireAuthorization": {
"type": "boolean",
"description": "If set, this account must individually approve other users in order for those users to hold this accounts issuances."
},
"disallowIncomingXRP": {
"type": "boolean",
"description": "Indicates that client applications should not send XRP to this account. Not enforced by rippled."
},
"disableMasterKey": {
"type": "boolean",
"description": "Disallows use of the master key to sign transactions for this account."
},
"enableTransactionIDTracking": {
"type": "boolean",
"description": "Track the ID of this accounts most recent transaction."
},
"noFreeze": {
"type": "boolean",
"description": "Permanently give up the ability to freeze individual trust lines. This flag can never be disabled after being enabled."
},
"globalFreeze": {
"type": "boolean",
"description": "Freeze all assets issued by this account."
},
"defaultRipple": {
"type": "boolean",
"description": "Enable [rippling](https://ripple.com/knowledge_center/understanding-the-noripple-flag/) on this accounts trust lines by default. (New in [rippled 0.27.3](https://github.com/ripple/rippled/releases/tag/0.27.3))"
},
"emailHash": {
"description": "Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.",
"oneOf": [
{"type": "null"},
{"$ref": "hash128"}
]
},
"messageKey": {
"type": "string",
"description": "Public key for sending encrypted messages to this account. Conventionally, it should be a secp256k1 key, the same encryption that is used by the rest of Ripple."
},
"domain": {
"type": "string",
"description": " The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
},
"transferRate": {
"description": " The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.",
"oneOf": [
{"type": "null"},
{"type": "number", "minimum": 1, "maximum": 4.294967295}
]
},
"regularKey": {
"oneOf": [
{"$ref": "address"},
{"type": "null"}
],
"description": "The public key of a new keypair, to use as the regular key to this account, as a base-58-encoded string in the same format as an account address. Use `null` to remove the regular key."
},
"memos": {"$ref": "memos"}
},
"additionalProperties": false
}

View File

@@ -93,12 +93,12 @@
"reserveBaseXRP": {
"type": "integer",
"minimum": 0,
"description": "Minimum amount of XRP (not drops) necessary for every account to keep in reserve."
"description": "Minimum amount of XRP necessary for every account to keep in reserve."
},
"reserveIncrementXRP": {
"type": "integer",
"minimum": 0,
"description": "Amount of XRP (not drops) added to the account reserve for each object an account is responsible for in the ledger."
"description": "Amount of XRP added to the account reserve for each object an account is responsible for in the ledger."
},
"ledgerVersion": {
"type": "integer",

View File

@@ -1,73 +1,8 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getSettings",
"type": "object",
"properties": {
"passwordSpent": {
"type": "boolean",
"description": "Indicates that the account has used its free SetRegularKey transaction."
},
"requireDestinationTag": {
"type": "boolean",
"description": "Requires incoming payments to specify a destination tag."
},
"requireAuthorization": {
"type": "boolean",
"description": "If set, this account must individually approve other users in order for those users to hold this accounts issuances."
},
"disallowIncomingXRP": {
"type": "boolean",
"description": "Indicates that client applications should not send XRP to this account. Not enforced by rippled."
},
"disableMasterKey": {
"type": "boolean",
"description": "Disallows use of the master key to sign transactions for this account."
},
"enableTransactionIDTracking": {
"type": "boolean",
"description": "Track the ID of this accounts most recent transaction."
},
"noFreeze": {
"type": "boolean",
"description": "Permanently give up the ability to freeze individual trust lines. This flag can never be disabled after being enabled."
},
"globalFreeze": {
"type": "boolean",
"description": "Freeze all assets issued by this account."
},
"defaultRipple": {
"type": "boolean",
"description": "Enable [rippling](https://ripple.com/knowledge_center/understanding-the-noripple-flag/) on this accounts trust lines by default. (New in [rippled 0.27.3](https://github.com/ripple/rippled/releases/tag/0.27.3))"
},
"emailHash": {
"description": "Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.",
"oneOf": [
{"type": "null"},
{"$ref": "hash128"}
]
},
"messageKey": {
"type": "string",
"description": "Public key for sending encrypted messages to this account. Conventionally, it should be a secp256k1 key, the same encryption that is used by the rest of Ripple."
},
"domain": {
"type": "string",
"description": " The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
},
"transferRate": {
"description": " The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.",
"oneOf": [
{"type": "null"},
{"type": "number", "minimum": 1, "maximum": 4.294967295}
]
},
"regularKey": {
"oneOf": [
{"$ref": "address"},
{"type": "null"}
],
"description": "The public key of a new keypair, to use as the regular key to this account, as a base-58-encoded string in the same format as an account address. Use `null` to remove the regular key."
}
},
"additionalProperties": false
"$ref": "settingsPlusMemos",
"not": {
"required": ["memos"]
}
}

View File

@@ -34,7 +34,7 @@
"state": {
"properties": {
"balance": {
"$ref": "value",
"$ref": "signedValue",
"description": "The balance on the trustline, representing which party owes the other and by how much."
}
},

View File

@@ -1,18 +1,12 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "ledgerClosed",
"description": "A ledgerClosed event message",
"title": "ledgerEvent",
"description": "A ledger event message",
"type": "object",
"properties": {
"feeBase": {
"type": "integer",
"minimum": 0,
"description": "Base fee, in drops."
},
"feeReference": {
"type": "integer",
"minimum": 0,
"description": "Cost of the 'reference transaction' in 'fee units'."
"baseFeeXRP": {
"$ref": "value",
"description": "Base fee, in XRP."
},
"ledgerHash": {
"$ref": "hash256",
@@ -27,14 +21,12 @@
"format": "date-time",
"description": "The time at which this ledger closed."
},
"reserveBase": {
"type": "integer",
"minimum": 0,
"reserveBaseXRP": {
"$ref": "value",
"description": "The minimum reserve, in drops of XRP, that is required for an account."
},
"reserveIncrement": {
"type": "integer",
"minimum": 0,
"reserveIncrementXRP": {
"$ref": "value",
"description": "The increase in account reserve that is added for each item the account owns, such as offers or trust lines."
},
"transactionCount": {
@@ -48,7 +40,7 @@
}
},
"addtionalProperties": false,
"required": ["feeBase", "feeReference", "ledgerHash", "ledgerTimestamp",
"reserveBase", "reserveIncrement", "transactionCount",
"required": ["baseFeeXRP", "ledgerHash", "ledgerTimestamp",
"reserveBaseXRP", "reserveIncrementXRP", "transactionCount",
"ledgerVersion", "validatedLedgerVersions"]
}

View File

@@ -7,7 +7,8 @@
"orderSequence": {
"$ref": "sequence",
"description": "The [account sequence number](#account-sequence-number) of the order to cancel."
}
},
"memos": {"$ref": "memos"}
},
"required": ["orderSequence"],
"additionalProperties": false

View File

@@ -33,7 +33,8 @@
"type": "string",
"format": "date-time",
"description": "Time after which the offer is no longer active, as an [ISO 8601 date-time](https://en.wikipedia.org/wiki/ISO_8601)."
}
},
"memos": {"$ref": "memos"}
},
"required": ["direction", "quantity", "totalPrice"],
"additionalProperties": false,

View File

@@ -2,11 +2,17 @@
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "settings",
"link": "settings",
"allOf": [
"$ref": "settingsPlusMemos",
"oneOf": [
{
"$ref": "getSettings"
"required": ["memos"],
"minProperties": 2,
"maxProperties": 2
},
{
"not": {
"required": ["memos"]
},
"minProperties": 1,
"maxProperties": 1
}

View File

@@ -35,7 +35,8 @@
"frozen": {
"type": "boolean",
"description": "If true, the trustline is frozen, which means that funds can only be sent to the owner."
}
},
"memos": {"$ref": "memos"}
},
"required": ["currency", "counterparty", "limit"],
"additionalProperties": false

View File

@@ -54,7 +54,8 @@ type APIOptions = {
servers?: Array<string>,
feeCushion?: number,
trace?: boolean,
proxy?: string
proxy?: string,
timeout?: number
}
// prevent access to non-validated ledger versions
@@ -82,7 +83,7 @@ class RippleAPI extends EventEmitter {
if (servers.length === 1) {
this.connection = new RestrictedConnection(servers[0], options);
this.connection.on('ledgerClosed', message => {
this.emit('ledgerClosed', server.formatLedgerClose(message));
this.emit('ledger', server.formatLedgerClose(message));
});
this.connection.on('error', (type, info) => {
this.emit('error', type, info);

View File

@@ -47,9 +47,6 @@ function parseAccountTxTransaction(tx) {
}
function counterpartyFilter(filters, tx: TransactionType) {
if (!filters.counterparty) {
return true;
}
if (tx.address === filters.counterparty || (
tx.specification && (
(tx.specification.destination &&

View File

@@ -30,13 +30,12 @@ function getFee(): Promise<number> {
function formatLedgerClose(ledgerClose: Object): Object {
return {
feeBase: ledgerClose.fee_base,
feeReference: ledgerClose.fee_ref,
baseFeeXRP: common.dropsToXrp(ledgerClose.fee_base),
ledgerHash: ledgerClose.ledger_hash,
ledgerVersion: ledgerClose.ledger_index,
ledgerTimestamp: common.rippleTimeToISO8601(ledgerClose.ledger_time),
reserveBase: ledgerClose.reserve_base,
reserveIncrement: ledgerClose.reserve_inc,
reserveBaseXRP: common.dropsToXrp(ledgerClose.reserve_base),
reserveIncrementXRP: common.dropsToXrp(ledgerClose.reserve_inc),
transactionCount: ledgerClose.txn_count,
validatedLedgerVersions: ledgerClose.validated_ledgers
};

View File

@@ -1,5 +1,6 @@
/* @flow */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const offerFlags = utils.common.txFlags.OfferCreate;
const {validate, iso8601ToRippleTime} = utils.common;
@@ -34,6 +35,9 @@ function createOrderTransaction(account: string, order: Order): Object {
if (order.expirationTime !== undefined) {
txJSON.Expiration = iso8601ToRippleTime(order.expirationTime);
}
if (order.memos !== undefined) {
txJSON.Memos = _.map(order.memos, utils.convertMemo);
}
return txJSON;
}

View File

@@ -1,24 +1,29 @@
/* @flow */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const validate = utils.common.validate;
import type {Instructions, Prepare} from './types.js';
function createOrderCancellationTransaction(account: string,
sequence: number
orderCancellation: Object
): Object {
return {
const txJSON: Object = {
TransactionType: 'OfferCancel',
Account: account,
OfferSequence: sequence
OfferSequence: orderCancellation.orderSequence
};
if (orderCancellation.memos !== undefined) {
txJSON.Memos = _.map(orderCancellation.memos, utils.convertMemo);
}
return txJSON;
}
function prepareOrderCancellation(address: string, sequence: number,
function prepareOrderCancellation(address: string, orderCancellation: Object,
instructions: Instructions = {}
): Promise<Prepare> {
validate.prepareOrderCancellation({address, sequence, instructions});
const txJSON = createOrderCancellationTransaction(address, sequence);
validate.prepareOrderCancellation({address, orderCancellation, instructions});
const txJSON = createOrderCancellationTransaction(address, orderCancellation);
return utils.prepareTransaction(txJSON, this, instructions);
}

View File

@@ -33,8 +33,10 @@ type Payment = {
}
function isXRPToXRPPayment(payment: Payment): boolean {
const sourceCurrency = _.get(payment, 'source.maxAmount.currency');
const destinationCurrency = _.get(payment, 'destination.amount.currency');
const sourceCurrency = _.get(payment, 'source.maxAmount.currency',
_.get(payment, 'source.amount.currency'));
const destinationCurrency = _.get(payment, 'destination.amount.currency',
_.get(payment, 'destination.minAmount.currency'));
return sourceCurrency === 'XRP' && destinationCurrency === 'XRP';
}

View File

@@ -93,6 +93,9 @@ function createSettingsTransaction(account: string, settings: Settings
if (txJSON.TransferRate !== undefined) {
txJSON.TransferRate = convertTransferRate(txJSON.TransferRate);
}
if (settings.memos !== undefined) {
txJSON.Memos = _.map(settings.memos, utils.convertMemo);
}
return txJSON;
}

View File

@@ -1,5 +1,6 @@
/* @flow */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const validate = utils.common.validate;
const trustlineFlags = utils.common.txFlags.TrustSet;
@@ -8,8 +9,7 @@ import type {Instructions, Prepare} from './types.js';
import type {TrustLineSpecification} from '../ledger/trustlines-types.js';
function convertQuality(quality) {
return quality === undefined ? undefined :
(new BigNumber(quality)).shift(9).truncated().toNumber();
return (new BigNumber(quality)).shift(9).truncated().toNumber();
}
function createTrustlineTransaction(account: string,
@@ -44,6 +44,9 @@ function createTrustlineTransaction(account: string,
txJSON.Flags |= trustline.frozen ?
trustlineFlags.SetFreeze : trustlineFlags.ClearFreeze;
}
if (trustline.memos !== undefined) {
txJSON.Memos = _.map(trustline.memos, utils.convertMemo);
}
return txJSON;
}

View File

@@ -1,6 +1,7 @@
/* eslint-disable max-nested-callbacks */
'use strict';
const _ = require('lodash');
const net = require('net');
const assert = require('assert-diff');
const setupAPI = require('./setup-api');
const RippleAPI = require('ripple-api').RippleAPI;
@@ -15,6 +16,9 @@ const utils = RippleAPI._PRIVATE.ledgerUtils;
const ledgerClosed = require('./fixtures/rippled/ledger-close-newer');
const schemaValidator = RippleAPI._PRIVATE.schemaValidator;
function unused() {
}
function closeLedger(connection) {
connection._ws.emit('message', JSON.stringify(ledgerClosed));
}
@@ -31,11 +35,247 @@ function checkResult(expected, schemaName, response) {
return response;
}
function createServer() {
return new Promise((resolve, reject) => {
const server = net.createServer();
server.on('listening', function() {
resolve(server);
});
server.on('error', function(error) {
reject(error);
});
server.listen(0, '0.0.0.0');
});
}
describe('RippleAPI', function() {
const instructions = {maxLedgerVersionOffset: 100};
beforeEach(setupAPI.setup);
afterEach(setupAPI.teardown);
describe('Connection', function() {
it('connection default options', function() {
const connection = new utils.common.Connection('url');
assert.strictEqual(connection._url, 'url');
assert(_.isUndefined(connection._proxyURL));
assert(_.isUndefined(connection._authorization));
});
it('with proxy', function(done) {
createServer().then((server) => {
const port = server.address().port;
const expect = 'CONNECT localhost';
server.on('connection', (socket) => {
socket.on('data', (data) => {
const got = data.toString('ascii', 0, expect.length);
assert.strictEqual(got, expect);
server.close();
done();
});
});
const options = {
proxy: 'ws://localhost:' + port,
authorization: 'authorization',
trustedCertificates: 'something'
};
const connection =
new utils.common.Connection(this.api.connection._url, options);
connection.connect().catch(done);
connection.connect().catch(done);
}, done);
});
it('Multiply disconnect calls', function() {
this.api.disconnect();
return this.api.disconnect();
});
it('reconnect', function() {
return this.api.connection.reconnect();
});
it('NotConnectedError', function() {
const connection = new utils.common.Connection('url');
return connection.getLedgerVersion().then(() => {
assert(false, 'Should throw NotConnectedError');
}).catch(error => {
assert(error instanceof this.api.errors.NotConnectedError);
});
});
it('DisconnectedError', function() {
this.api.connection._send = function() {
this._ws.close();
};
return this.api.getServerInfo().then(() => {
assert(false, 'Should throw DisconnectedError');
}).catch(error => {
assert(error instanceof this.api.errors.DisconnectedError);
});
});
it('TimeoutError', function() {
this.api.connection._send = function() {
return Promise.resolve({});
};
const request = {command: 'server_info'};
return this.api.connection.request(request, 1).then(() => {
assert(false, 'Should throw TimeoutError');
}).catch(error => {
assert(error instanceof this.api.errors.TimeoutError);
});
});
it('DisconnectedError on send', function() {
this.api.connection._ws.send = function(message, options, callback) {
unused(message, options);
callback({message: 'not connected'});
};
return this.api.getServerInfo().then(() => {
assert(false, 'Should throw DisconnectedError');
}).catch(error => {
assert(error instanceof this.api.errors.DisconnectedError);
assert.strictEqual(error.message, 'not connected');
});
});
it('ResponseFormatError', function() {
this.api.connection._send = function(message) {
const parsed = JSON.parse(message);
setTimeout(() => {
this._ws.emit('message', JSON.stringify({
id: parsed.id,
type: 'response',
status: 'unrecognized'
}));
}, 2);
return new Promise(() => {});
};
return this.api.getServerInfo().then(() => {
assert(false, 'Should throw ResponseFormatError');
}).catch(error => {
assert(error instanceof this.api.errors.ResponseFormatError);
});
});
it('reconnect on unexpected close ', function(done) {
this.api.connection.on('connected', () => {
done();
});
setTimeout(() => {
this.api.connection._ws.close();
}, 1);
});
it('Multiply connect calls', function() {
return this.api.connect().then(() => {
return this.api.connect();
});
});
it('hasLedgerVersion', function() {
return this.api.connection.hasLedgerVersion(8819951).then((result) => {
assert(result);
});
});
it('Cannot connect because no server', function() {
const connection = new utils.common.Connection();
return connection.connect().then(() => {
assert(false, 'Should throw ConnectionError');
}).catch(error => {
assert(error instanceof this.api.errors.ConnectionError);
});
});
it('connect multiserver error', function() {
const options = {
servers: ['wss://server1.com', 'wss://server2.com']
};
assert.throws(function() {
const api = new RippleAPI(options);
unused(api);
}, this.api.errors.RippleError);
});
it('connect throws error', function(done) {
this.api.once('error', (type, info) => {
assert.strictEqual(type, 'type');
assert.strictEqual(info, 'info');
done();
});
this.api.connection.emit('error', 'type', 'info');
});
it('connection emit stream messages', function(done) {
let transactionCount = 0;
let pathFindCount = 0;
this.api.connection.on('transaction', () => {
transactionCount++;
});
this.api.connection.on('path_find', () => {
pathFindCount++;
});
this.api.connection.on('1', () => {
assert.strictEqual(transactionCount, 1);
assert.strictEqual(pathFindCount, 1);
done();
});
this.api.connection._onMessage(JSON.stringify({
type: 'transaction'
}));
this.api.connection._onMessage(JSON.stringify({
type: 'path_find'
}));
this.api.connection._onMessage(JSON.stringify({
type: 'response', id: 1
}));
});
it('connection - invalid message id', function(done) {
this.api.on('error', (type, message) => {
assert.strictEqual(type, 'badMessage');
assert.strictEqual(message,
'{"type":"response","id":"must be integer"}');
done();
});
this.api.connection._onMessage(JSON.stringify({
type: 'response', id: 'must be integer'
}));
});
it('connection - error message', function(done) {
this.api.on('error', (type, message) => {
assert.strictEqual(type, 'slowDown');
assert.strictEqual(message, 'slow down');
done();
});
this.api.connection._onMessage(JSON.stringify({
error: 'slowDown', error_message: 'slow down'
}));
});
it('connection - unrecognized message type', function(done) {
this.api.on('error', (type, message) => {
assert.strictEqual(type, 'badMessage');
assert.strictEqual(message, '{"type":"unknown"}');
done();
});
this.api.connection._onMessage(JSON.stringify({type: 'unknown'}));
});
});
it('error inspect', function() {
const error = new this.api.errors.RippleError('mess', {data: 1});
assert.strictEqual(error.inspect(), '[RippleError(mess, { data: 1 })]');
});
it('preparePayment', function() {
const localInstructions = _.defaults({
maxFee: '0.000012'
@@ -45,6 +285,40 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.preparePayment.normal, 'prepare'));
});
it('preparePayment - min amount xrp', function() {
const localInstructions = _.defaults({
maxFee: '0.000012'
}, instructions);
return this.api.preparePayment(
address, requests.preparePaymentMinAmountXRP, localInstructions).then(
_.partial(checkResult, responses.preparePayment.minAmountXRP, 'prepare'));
});
it('preparePayment - min amount xrp2xrp', function() {
return this.api.preparePayment(
address, requests.preparePaymentMinAmount, instructions).then(
_.partial(checkResult,
responses.preparePayment.minAmountXRPXRP, 'prepare'));
});
it('preparePayment - XRP to XRP no partial', function() {
assert.throws(() => {
this.api.preparePayment(address, requests.preparePaymentWrongPartial);
}, /XRP to XRP payments cannot be partial payments/);
});
it('preparePayment - address must match payment.source.address', function() {
assert.throws(() => {
this.api.preparePayment(address, requests.preparePaymentWrongAddress);
}, /address must match payment.source.address/);
});
it('preparePayment - wrong amount', function() {
assert.throws(() => {
this.api.preparePayment(address, requests.preparePaymentWrongAmount);
}, this.api.errors.ValidationError);
});
it('preparePayment with all options specified', function() {
return this.api.getLedgerVersion().then((ver) => {
const localInstructions = {
@@ -73,7 +347,7 @@ describe('RippleAPI', function() {
it('prepareOrder - buy order', function() {
const request = requests.prepareOrder.buy;
return this.api.prepareOrder(address, request, instructions)
return this.api.prepareOrder(address, request)
.then(_.partial(checkResult, responses.prepareOrder.buy, 'prepare'));
});
@@ -93,7 +367,15 @@ describe('RippleAPI', function() {
it('prepareOrderCancellation', function() {
const request = requests.prepareOrderCancellation;
return this.api.prepareOrderCancellation(address, request, instructions)
.then(_.partial(checkResult, responses.prepareOrderCancellation,
.then(_.partial(checkResult, responses.prepareOrder.cancellation,
'prepare'));
});
it('prepareOrderCancellation - no instructions', function() {
const request = requests.prepareOrderCancellation;
return this.api.prepareOrderCancellation(address, request)
.then(_.partial(checkResult,
responses.prepareOrder.cancellationNoInstructions,
'prepare'));
});
@@ -103,6 +385,12 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.prepareTrustline.simple, 'prepare'));
});
it('prepareTrustline - frozen', function() {
return this.api.prepareTrustline(
address, requests.prepareTrustline.frozen).then(
_.partial(checkResult, responses.prepareTrustline.frozen, 'prepare'));
});
it('prepareTrustline - complex', function() {
return this.api.prepareTrustline(
address, requests.prepareTrustline.complex, instructions).then(
@@ -115,6 +403,15 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.prepareSettings.flags, 'prepare'));
});
it('prepareSettings - no instructions', function() {
return this.api.prepareSettings(
address, requests.prepareSettings).then(
_.partial(
checkResult,
responses.prepareSettings.noInstructions,
'prepare'));
});
it('prepareSettings - regularKey', function() {
const regularKey = {regularKey: 'rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD'};
return this.api.prepareSettings(address, regularKey, instructions).then(
@@ -167,6 +464,13 @@ describe('RippleAPI', function() {
'prepare'));
});
it('prepareSuspendedPaymentCreation full', function() {
return this.api.prepareSuspendedPaymentCreation(
address, requests.prepareSuspendedPaymentCreationFull).then(
_.partial(checkResult, responses.prepareSuspendedPaymentCreationFull,
'prepare'));
});
it('prepareSuspendedPaymentExecution', function() {
return this.api.prepareSuspendedPaymentExecution(
address, requests.prepareSuspendedPaymentExecution, instructions).then(
@@ -174,6 +478,13 @@ describe('RippleAPI', function() {
'prepare'));
});
it('prepareSuspendedPaymentExecution - simple', function() {
return this.api.prepareSuspendedPaymentExecution(
address, requests.prepareSuspendedPaymentExecutionSimple).then(
_.partial(checkResult, responses.prepareSuspendedPaymentExecutionSimple,
'prepare'));
});
it('prepareSuspendedPaymentCancellation', function() {
return this.api.prepareSuspendedPaymentCancellation(
address, requests.prepareSuspendedPaymentCancellation, instructions).then(
@@ -181,6 +492,13 @@ describe('RippleAPI', function() {
'prepare'));
});
it('prepareSuspendedPaymentCancellation with memos', function() {
return this.api.prepareSuspendedPaymentCancellation(
address, requests.prepareSuspendedPaymentCancellationMemos).then(
_.partial(checkResult, responses.prepareSuspendedPaymentCancellationMemos,
'prepare'));
});
it('sign', function() {
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
const result = this.api.sign(requests.sign.txJSON, secret);
@@ -218,7 +536,8 @@ describe('RippleAPI', function() {
it('getBalances - limit', function() {
const options = {
limit: 3
limit: 3,
ledgerVersion: 123456
};
const expectedResponse = responses.getBalances.slice(0, 3);
return this.api.getBalances(address, options).then(
@@ -255,6 +574,18 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.getBalanceSheet, 'getBalanceSheet'));
});
it('getBalanceSheet - invalid options', function() {
assert.throws(() => {
this.api.getBalanceSheet(address, {invalid: 'options'});
}, this.api.errors.ValidationError);
});
it('getBalanceSheet - empty', function() {
const options = {ledgerVersion: 123456};
return this.api.getBalanceSheet(address, options).then(
_.partial(checkResult, {}, 'getBalanceSheet'));
});
describe('getTransaction', () => {
it('getTransaction - payment', function() {
return this.api.getTransaction(hashes.VALID_TRANSACTION_HASH).then(
@@ -279,6 +610,15 @@ describe('RippleAPI', function() {
'getTransaction'));
});
it('getTransaction - sell order', function() {
const hash =
'458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2';
closeLedger(this.api.connection);
return this.api.getTransaction(hash).then(
_.partial(checkResult, responses.getTransaction.orderSell,
'getTransaction'));
});
it('getTransaction - order cancellation', function() {
const hash =
'809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E';
@@ -456,6 +796,15 @@ describe('RippleAPI', function() {
'getTransaction'));
});
it('getTransaction - SuspendedPaymentCreation iou', function() {
const hash =
'144F272380BDB4F1BD92329A2178BABB70C20F59042C495E10BF72EBFB408EE2';
return this.api.getTransaction(hash).then(
_.partial(checkResult,
responses.getTransaction.SuspendedPaymentCreationIOU,
'getTransaction'));
});
it('getTransaction - SuspendedPaymentCancellation', function() {
const hash =
'F346E542FFB7A8398C30A87B952668DAB48B7D421094F8B71776DA19775A3B22';
@@ -466,14 +815,46 @@ describe('RippleAPI', function() {
});
it('getTransaction - SuspendedPaymentExecution', function() {
const options = {
minLedgerVersion: 10,
maxLedgerVersion: 15
};
const hash =
'CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD136993B';
return this.api.getTransaction(hash).then(
return this.api.getTransaction(hash, options).then(
_.partial(checkResult,
responses.getTransaction.suspendedPaymentExecution,
'getTransaction'));
});
it('getTransaction - SuspendedPaymentExecution simple', function() {
const hash =
'CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD1369931';
return this.api.getTransaction(hash).then(
_.partial(checkResult,
responses.getTransaction.suspendedPaymentExecutionSimple,
'getTransaction'));
});
it('getTransaction - no Meta', function() {
const hash =
'AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B';
return this.api.getTransaction(hash).then(result => {
assert.deepEqual(result, responses.getTransaction.noMeta);
});
});
it('getTransaction - Unrecognized transaction type', function() {
const hash =
'AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA11';
closeLedger(this.api.connection);
return this.api.getTransaction(hash).then(() => {
assert(false, 'Unrecognized transaction type');
}).catch(error => {
assert.strictEqual(error.message, 'Unrecognized transaction type');
});
});
});
it('getTransactions', function() {
@@ -493,6 +874,7 @@ describe('RippleAPI', function() {
_.partial(checkResult, expected, 'getTransactions'));
});
it('getTransactions - earliest first with start option', function() {
const options = {types: ['payment', 'order'], initiated: true, limit: 2,
start: hashes.VALID_TRANSACTION_HASH,
@@ -572,12 +954,32 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.getTransactions, 'getTransactions'));
});
it('getTransactions - start transaction with zero ledger version', function(
) {
const options = {
start: '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA13',
limit: 1
};
return this.api.getTransactions(address, options).then(
_.partial(checkResult, [], 'getTransactions'));
});
it('getTransactions - no options', function() {
return this.api.getTransactions(addresses.OTHER_ACCOUNT).then(
_.partial(checkResult, responses.getTransactionsOne, 'getTransactions'));
});
it('getTrustlines', function() {
const options = {currency: 'USD'};
return this.api.getTrustlines(address, options).then(
_.partial(checkResult, responses.getTrustlines, 'getTrustlines'));
});
it('getTrustlines - ono options', function() {
return this.api.getTrustlines(address).then(
_.partial(checkResult, responses.getTrustlinesAll, 'getTrustlines'));
});
it('generateAddress', function() {
function random() {
return _.fill(Array(16), 0);
@@ -586,24 +988,79 @@ describe('RippleAPI', function() {
responses.generateAddress);
});
it('generateAddress invalid', function() {
assert.throws(() => {
function random() {
return _.fill(Array(1), 0);
}
this.api.generateAddress({entropy: random()});
}, this.api.errors.UnexpectedError);
});
it('getSettings', function() {
return this.api.getSettings(address).then(
_.partial(checkResult, responses.getSettings, 'getSettings'));
});
it('getSettings - options undefined', function() {
return this.api.getSettings(address, undefined).then(
_.partial(checkResult, responses.getSettings, 'getSettings'));
});
it('getSettings - invalid options', function() {
assert.throws(() => {
this.api.getSettings(address, {invalid: 'options'});
}, this.api.errors.ValidationError);
});
it('getAccountInfo', function() {
return this.api.getAccountInfo(address).then(
_.partial(checkResult, responses.getAccountInfo, 'getAccountInfo'));
});
it('getAccountInfo - options undefined', function() {
return this.api.getAccountInfo(address, undefined).then(
_.partial(checkResult, responses.getAccountInfo, 'getAccountInfo'));
});
it('getAccountInfo - invalid options', function() {
assert.throws(() => {
this.api.getAccountInfo(address, {invalid: 'options'});
}, this.api.errors.ValidationError);
});
it('getOrders', function() {
return this.api.getOrders(address).then(
_.partial(checkResult, responses.getOrders, 'getOrders'));
});
it('getOrders', function() {
return this.api.getOrders(address, undefined).then(
_.partial(checkResult, responses.getOrders, 'getOrders'));
});
it('getOrders - invalid options', function() {
assert.throws(() => {
this.api.getOrders(address, {invalid: 'options'});
}, this.api.errors.ValidationError);
});
it('getOrderbook', function() {
return this.api.getOrderbook(address, requests.getOrderbook).then(
_.partial(checkResult, responses.getOrderbook, 'getOrderbook'));
return this.api.getOrderbook(address, requests.getOrderbook, undefined)
.then(
_.partial(checkResult, responses.getOrderbook, 'getOrderbook'));
});
it('getOrderbook - invalid options', function() {
assert.throws(() => {
this.api.getOrderbook(address, requests.getOrderbook,
{invalid: 'options'});
}, this.api.errors.ValidationError);
});
it('getOrderbook with XRP', function() {
return this.api.getOrderbook(address, requests.getOrderbookWithXRP).then(
_.partial(checkResult, responses.getOrderbookWithXRP, 'getOrderbook'));
});
it('getOrderbook - sorted so that best deals come first', function() {
@@ -664,6 +1121,13 @@ describe('RippleAPI', function() {
});
});
it('getFee default', function() {
this.api._feeCushion = undefined;
return this.api.getFee().then(fee => {
assert.strictEqual(fee, '0.000012');
});
});
it('disconnect & isConnected', function() {
assert.strictEqual(this.api.isConnected(), true);
return this.api.disconnect().then(() => {
@@ -702,6 +1166,14 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.getPaths.XrpToXrp, 'getPaths'));
});
it('getPaths - source with issuer', function() {
return this.api.getPaths(requests.getPaths.issuer).then(() => {
assert(false, 'Should throw NotFoundError');
}).catch(error => {
assert(error instanceof this.api.errors.NotFoundError);
});
});
it('getPaths - XRP 2 XRP - not enough', function() {
return this.api.getPaths(requests.getPaths.XrpToXrpNotEnough).then(() => {
assert(false, 'Should throw NotFoundError');
@@ -710,6 +1182,12 @@ describe('RippleAPI', function() {
});
});
it('getPaths - invalid PathFind', function() {
assert.throws(() => {
this.api.getPaths(requests.getPaths.invalid);
}, /Cannot specify both source.amount/);
});
it('getPaths - does not accept currency', function() {
return this.api.getPaths(requests.getPaths.NotAcceptCurrency).then(() => {
assert(false, 'Should throw NotFoundError');
@@ -768,6 +1246,18 @@ describe('RippleAPI', function() {
});
});
it('getLedger - with state as hashes', function() {
const request = {
includeTransactions: true,
includeAllData: false,
includeState: true,
ledgerVersion: 6
};
return this.api.getLedger(request).then(
_.partial(checkResult, responses.getLedger.withStateAsHashes,
'getLedger'));
});
it('getLedger - with settings transaction', function() {
const request = {
includeTransactions: true,
@@ -796,7 +1286,55 @@ describe('RippleAPI', function() {
});
});
it('computeLedgerHash - wrong hash', function() {
const request = {
includeTransactions: true,
includeState: true,
includeAllData: true,
ledgerVersion: 38129
};
return this.api.getLedger(request).then(
_.partial(checkResult, responses.getLedger.full, 'getLedger'))
.then(response => {
const ledger = _.assign({}, response, {
parentCloseTime: response.closeTime, stateHash:
'D9ABF622DA26EEEE48203085D4BC23B0F77DC6F8724AC33D975DA3CA492D2E44'});
assert.throws(() => {
const hash = this.api.computeLedgerHash(ledger);
unused(hash);
}, /does not match computed hash of state/);
});
});
it('RippleError with data', function() {
const error = new this.api.errors.RippleError('_message_', '_data_');
assert.strictEqual(error.toString(),
'[RippleError(_message_, \'_data_\')]');
});
it('NotFoundError default message', function() {
const error = new this.api.errors.NotFoundError();
assert.strictEqual(error.toString(),
'[NotFoundError(Not found)]');
});
it('common utils - toRippledAmount', function() {
const amount = {issuer: 'is', currency: 'c', value: 'v'};
assert.deepEqual(utils.common.toRippledAmount(amount), {
issuer: 'is', currency: 'c', value: 'v'
});
});
it('ledger utils - renameCounterpartyToIssuerInOrder', function() {
const order = {taker_gets: {issuer: '1'}};
const expected = {taker_gets: {issuer: '1'}};
assert.deepEqual(utils.renameCounterpartyToIssuerInOrder(order), expected);
});
it('ledger utils - compareTransactions', function() {
assert.strictEqual(utils.compareTransactions({}, {}), 0);
let first = {outcome: {ledgerVersion: 1, indexInLedger: 100}};
let second = {outcome: {ledgerVersion: 1, indexInLedger: 200}};
@@ -896,9 +1434,9 @@ describe('RippleAPI', function() {
});
it('ledgerClosed', function(done) {
this.api.on('ledgerClosed', message => {
checkResult(responses.ledgerClosed, 'ledgerClosed', message);
it('ledger event', function(done) {
this.api.on('ledger', message => {
checkResult(responses.ledgerEvent, 'ledgerEvent', message);
done();
});
closeLedger(this.api.connection);

View File

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

View File

@@ -0,0 +1,16 @@
{
"source": {
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
"amount": {
"value": "1000002",
"currency": "USD"
}
},
"destination": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"amount": {
"value": "1000002",
"currency": "USD"
}
}
}

View File

@@ -0,0 +1,16 @@
{
"source": {
"address": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
"amount": {
"value": "1000002",
"currency": "USD",
"counterparty": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J"
}
},
"destination": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"amount": {
"currency": "USD"
}
}
}

View File

@@ -8,18 +8,30 @@ module.exports = {
},
prepareOrderCancellation: require('./prepare-order-cancellation'),
preparePayment: require('./prepare-payment'),
preparePaymentMinAmountXRP: require('./prepare-payment-min-xrp'),
preparePaymentMinAmount: require('./prepare-payment-min'),
preparePaymentWrongAddress: require('./prepare-payment-wrong-address'),
preparePaymentWrongAmount: require('./prepare-payment-wrong-amount'),
preparePaymentWrongPartial: require('./prepare-payment-wrong-partial'),
preparePaymentAllOptions: require('./prepare-payment-all-options'),
preparePaymentNoCounterparty: require('./prepare-payment-no-counterparty'),
prepareSettings: require('./prepare-settings'),
prepareSuspendedPaymentCreation:
require('./prepare-suspended-payment-creation'),
prepareSuspendedPaymentCreationFull:
require('./prepare-suspended-payment-creation-full'),
prepareSuspendedPaymentExecution:
require('./prepare-suspended-payment-execution'),
prepareSuspendedPaymentExecutionSimple:
require('./prepare-suspended-payment-execution-simple'),
prepareSuspendedPaymentCancellation:
require('./prepare-suspended-payment-cancellation'),
prepareSuspendedPaymentCancellationMemos:
require('./prepare-suspended-payment-cancellation-memos'),
prepareTrustline: {
simple: require('./prepare-trustline-simple'),
complex: require('./prepare-trustline')
complex: require('./prepare-trustline'),
frozen: require('./prepare-trustline-frozen.json')
},
sign: require('./sign'),
signSuspended: require('./sign-suspended.json'),
@@ -31,9 +43,12 @@ module.exports = {
NotAcceptCurrency: require('./getpaths/not-accept-currency'),
NoPaths: require('./getpaths/no-paths'),
NoPathsWithCurrencies: require('./getpaths/no-paths-with-currencies'),
sendAll: require('./getpaths/send-all')
sendAll: require('./getpaths/send-all'),
invalid: require('./getpaths/invalid'),
issuer: require('./getpaths/issuer')
},
getOrderbook: require('./get-orderbook'),
getOrderbookWithXRP: require('./get-orderbook-with-xrp'),
computeLedgerHash: {
header: require('./compute-ledger-hash'),
transactions: require('./compute-ledger-hash-transactions')

View File

@@ -1 +1,3 @@
23
{
"orderSequence": 23
}

View File

@@ -9,5 +9,6 @@
"currency": "XRP",
"value": "2"
},
"immediateOrCancel": true
"passive": true,
"fillOrKill": true
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,11 @@
{
"owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"suspensionSequence": 1234,
"memos": [
{
"type": "test",
"format": "plain/text",
"data": "texted data"
}
]
}

View File

@@ -0,0 +1,28 @@
{
"source": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"maxAmount": {
"value": "0.01",
"currency": "USD",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
},
"tag": 1
},
"destination": {
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"amount": {
"value": "0.01",
"currency": "USD",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
},
"tag": 2
},
"digest": "8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4",
"allowExecuteAfter": "2014-09-24T21:21:50.000Z",
"memos": [
{
"type": "test",
"data": "texted data"
}
]
}

View File

@@ -0,0 +1,11 @@
{
"owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"suspensionSequence": 1234,
"memos": [
{
"type": "test",
"format": "plain/text",
"data": "texted data"
}
]
}

View File

@@ -0,0 +1,8 @@
{
"currency": "BTC",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"limit": "0.1",
"authorized": true,
"ripplingDisabled": false,
"frozen": true
}

View File

@@ -1,5 +1,5 @@
{
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"AccountSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Domain\":\"726970706C652E636F6D\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23,\"SigningPubKey\":\"02F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D8\"}",
"instructions": {
"fee": "0.000012",
"sequence": 23,

View File

@@ -33,5 +33,5 @@
}
}
],
"rawTransactions": "[{\"Account\":\"rEGy9CxMTFGXFgUHUMreTy2FbqArabGy38\",\"Fee\":\"10\",\"Flags\":0,\"Sequence\":6478,\"SigningPubKey\":\"02CAB6F3A798712136DB5F105A98B0DE27C99AEDB68500181706B087CF1B6D0F2D\",\"TransactionType\":\"AccountSet\",\"TxnSignature\":\"304402202144BD33CC30793455B0F90954576EEE80F13C4C73538D2AEE012564C48E522E02207A8A4AD2CF2B4DB549FB2F05D38E065B5DD1EAA386310698E5247F1BB515E99F\",\"hash\":\"FEEFC959B0351156F58A2275F5A6B37B07AA85CCCE2C4AF8A1342A0196A3CD4D\",\"metaData\":{\"AffectedNodes\":[{\"ModifiedNode\":{\"FinalFields\":{\"Account\":\"rEGy9CxMTFGXFgUHUMreTy2FbqArabGy38\",\"Balance\":\"403657865\",\"Flags\":0,\"OwnerCount\":2,\"Sequence\":6479},\"LedgerEntryType\":\"AccountRoot\",\"LedgerIndex\":\"F64FAA4CAFDB9931DC06890FE30B4E29C32F7AD574FC7C3362B81265682BFAEA\",\"PreviousFields\":{\"Balance\":\"403657875\",\"Sequence\":6478},\"PreviousTxnID\":\"B257B95A637C6C396507AD0AE122161A849C701F065B67009BB939690DB74BC9\",\"PreviousTxnLgrSeq\":4181972}}],\"TransactionIndex\":0,\"TransactionResult\":\"tesSUCCESS\"}}]"
"rawTransactions": "[{\"Account\":\"rEGy9CxMTFGXFgUHUMreTy2FbqArabGy38\",\"Fee\":\"10\",\"ledger_index\":4181996,\"Flags\":0,\"Sequence\":6478,\"SigningPubKey\":\"02CAB6F3A798712136DB5F105A98B0DE27C99AEDB68500181706B087CF1B6D0F2D\",\"TransactionType\":\"AccountSet\",\"TxnSignature\":\"304402202144BD33CC30793455B0F90954576EEE80F13C4C73538D2AEE012564C48E522E02207A8A4AD2CF2B4DB549FB2F05D38E065B5DD1EAA386310698E5247F1BB515E99F\",\"hash\":\"FEEFC959B0351156F58A2275F5A6B37B07AA85CCCE2C4AF8A1342A0196A3CD4D\",\"metaData\":{\"AffectedNodes\":[{\"ModifiedNode\":{\"FinalFields\":{\"Account\":\"rEGy9CxMTFGXFgUHUMreTy2FbqArabGy38\",\"Balance\":\"403657865\",\"Flags\":0,\"OwnerCount\":2,\"Sequence\":6479},\"LedgerEntryType\":\"AccountRoot\",\"LedgerIndex\":\"F64FAA4CAFDB9931DC06890FE30B4E29C32F7AD574FC7C3362B81265682BFAEA\",\"PreviousFields\":{\"Balance\":\"403657875\",\"Sequence\":6478},\"PreviousTxnID\":\"B257B95A637C6C396507AD0AE122161A849C701F065B67009BB939690DB74BC9\",\"PreviousTxnLgrSeq\":4181972}}],\"TransactionIndex\":0,\"TransactionResult\":\"tesSUCCESS\"}}]"
}

View File

@@ -0,0 +1,20 @@
{
"stateHash": "8DBB7FA4036704D96AD32A4573BEE461FDDBDCB1B6F62CB17EDB5182F52AE9F1",
"closeTime": "2015-11-18T11:00:30.000Z",
"closeTimeResolution": 30,
"closeFlags": 0,
"ledgerHash": "3D7115EDB5EC72FEF4ADDF46CA5B7770CBDECEAB3A97EA210BCC04E8C54A7CEE",
"ledgerVersion": 6,
"parentLedgerHash": "6D36AEFD3639EE22A27DDE0FA6C57525D103941F11D7FD6D91AC8D439DE2B3EE",
"parentCloseTime": "2015-11-18T07:53:01.000Z",
"totalDrops": "99999999999999964",
"transactionHash": "B8D716B82BFFF4186BBBE7B7341AE0E1CBD2558952408B96E925EC0A51A6AEC2",
"transactionHashes": [
"B22E27F35F3F7679F76A474E4FF8E71EFA21B313DF2FC6678037A053A00FD084"
],
"stateHashes": [
"2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
"8B24E55376A65D68542C17F3BF446231AC7062CB43BED28817570128A1849819",
"B4979A36CDC7F3D3D5C31A4EAE2AC7D7209DDA877588B9AFC66799692AB0D66B"
]
}

View File

@@ -0,0 +1,44 @@
{
"bids": [
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "10.1",
"counterparty": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw"
},
"totalPrice": {
"currency": "XRP",
"value": "254391353"
}
},
"properties": {
"maker": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"sequence": 5,
"makerExchangeRate": "3.970260734451929e-8"
}
}
],
"asks": [
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "10453252347.1",
"counterparty": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw"
},
"totalPrice": {
"currency": "XRP",
"value": "134"
}
},
"properties": {
"maker": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"sequence": 6,
"makerExchangeRate": "0.0000780093458738806"
}
}
]
}

View File

@@ -0,0 +1,23 @@
{
"type": "payment",
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"sequence": 4,
"id": "AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B",
"specification": {
"source": {
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"maxAmount": {
"currency": "XRP",
"value": "1.112209"
}
},
"destination": {
"address": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"amount": {
"currency": "USD",
"value": "0.001"
}
},
"paths": "[[{\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":48,\"type_hex\":\"0000000000000030\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":49,\"type_hex\":\"0000000000000031\"}]]"
}
}

View File

@@ -0,0 +1,34 @@
{
"type": "order",
"address": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"sequence": 2,
"id": "458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2",
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "10.1",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
},
"totalPrice": {
"currency": "XRP",
"value": "254391353"
}
},
"outcome": {
"result": "tecUNFUNDED_OFFER",
"timestamp": "2015-11-18T20:56:30.000Z",
"fee": "0.000012",
"balanceChanges": {
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh": [
{
"currency": "XRP",
"value": "-0.000012"
}
]
},
"orderbookChanges": {},
"ledgerVersion": 6,
"indexInLedger": 0
}
}

View File

@@ -0,0 +1,51 @@
{
"type": "suspendedPaymentCreation",
"address": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"sequence": 10,
"id": "144F272380BDB4F1BD92329A2178BABB70C20F59042C495E10BF72EBFB408EE2",
"specification": {
"source": {
"address": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"maxAmount": {
"currency": "USD",
"value": "2"
},
"tag": 1
},
"destination": {
"address": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"amount": {
"currency": "USD",
"value": "2",
"counterparty": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
},
"tag": 2
},
"memos": [
{
"type": "x2",
"format": "text/plain",
"data": "mema data"
}
],
"digest": "8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4",
"allowCancelAfter": "2015-11-16T06:53:42.000Z",
"allowExecuteAfter": "2015-11-16T06:47:42.000Z"
},
"outcome": {
"result": "tesSUCCESS",
"timestamp": "2015-11-16T06:43:00.000Z",
"fee": "0.000012",
"balanceChanges": {
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh": [
{
"currency": "XRP",
"value": "-0.000014"
}
]
},
"orderbookChanges": {},
"ledgerVersion": 15,
"indexInLedger": 0
}
}

View File

@@ -0,0 +1,34 @@
{
"type": "suspendedPaymentExecution",
"address": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"sequence": 6,
"id": "CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD1369931",
"specification": {
"owner": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"suspensionSequence": 5,
"method": 1,
"digest": "632F2F3E437AE720C397994A985B5D21FE186DE61523A9CA3E8709CC581671A1"
},
"outcome": {
"result": "tesSUCCESS",
"timestamp": "2015-11-17T01:47:40.000Z",
"fee": "0.000012",
"balanceChanges": {
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh": [
{
"currency": "XRP",
"value": "-0.000012"
}
],
"rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw": [
{
"currency": "XRP",
"value": "10.000043"
}
]
},
"orderbookChanges": {},
"ledgerVersion": 14,
"indexInLedger": 0
}
}

View File

@@ -0,0 +1,27 @@
[
{
"type": "settings",
"address": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
"sequence": 491,
"id": "D868CFF0DF8C8AAF205404460EA764ACB3B8862527FA414BC8C1CA9A45B1F276",
"specification": {
"domain": "ripple.com"
},
"outcome": {
"result": "tesSUCCESS",
"timestamp": "2015-10-23T02:07:00.000Z",
"fee": "0.012",
"balanceChanges": {
"r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b": [
{
"currency": "XRP",
"value": "-0.012"
}
]
},
"orderbookChanges": {},
"ledgerVersion": 16635149,
"indexInLedger": 4
}
}
]

View File

@@ -0,0 +1,333 @@
[
{
"specification": {
"limit": "0",
"currency": "ASP",
"counterparty": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z"
},
"counterparty": {
"limit": "10"
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "0",
"currency": "XAU",
"counterparty": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
"ripplingDisabled": true,
"frozen": true
},
"counterparty": {
"limit": "0",
"ripplingDisabled": true
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "5",
"currency": "USD",
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
"ripplingDisabled": true,
"frozen": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "2.497605752725159"
}
},
{
"specification": {
"limit": "1000",
"currency": "MXN",
"counterparty": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4"
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "481.992867407479"
}
},
{
"specification": {
"limit": "1",
"currency": "EUR",
"counterparty": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "0.793598266778297"
}
},
{
"specification": {
"limit": "3",
"currency": "CNY",
"counterparty": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "3",
"currency": "DYM",
"counterparty": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E"
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "1.294889190631542"
}
},
{
"specification": {
"limit": "0",
"currency": "CHF",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "0.3488146605801446"
}
},
{
"specification": {
"limit": "3",
"currency": "BTC",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "2.114103174931847"
}
},
{
"specification": {
"limit": "5000",
"currency": "USD",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "0",
"currency": "BTC",
"counterparty": "rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd"
},
"counterparty": {
"limit": "10"
},
"state": {
"balance": "-0.00111"
}
},
{
"specification": {
"limit": "0",
"currency": "BTC",
"counterparty": "rBJ3YjwXi2MGbg7GVLuTXUWQ8DjL7tDXh4"
},
"counterparty": {
"limit": "10"
},
"state": {
"balance": "-0.1010780000080207"
}
},
{
"specification": {
"limit": "1",
"currency": "USD",
"counterparty": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "1"
}
},
{
"specification": {
"limit": "100",
"currency": "CNY",
"counterparty": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "8.07619790068559"
}
},
{
"specification": {
"limit": "0",
"currency": "JPY",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "7.292695098901099"
}
},
{
"specification": {
"limit": "0",
"currency": "AUX",
"counterparty": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0",
"ripplingDisabled": true
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "1",
"currency": "USD",
"counterparty": "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "100",
"currency": "EUR",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "12.41688780720394"
}
},
{
"specification": {
"limit": "500",
"currency": "USD",
"counterparty": "rfF3PNkwkq1DygW2wum2HK3RGfgkJjdPVD",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "35"
}
},
{
"specification": {
"limit": "0",
"currency": "JOE",
"counterparty": "rwUVoVMSURqNyvocPCcvLu3ygJzZyw8qwp"
},
"counterparty": {
"limit": "50",
"ripplingDisabled": true
},
"state": {
"balance": "-5"
}
},
{
"specification": {
"limit": "0",
"currency": "USD",
"counterparty": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
},
"counterparty": {
"limit": "100",
"ripplingDisabled": true
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "0",
"currency": "JOE",
"counterparty": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2"
},
"counterparty": {
"limit": "100",
"ripplingDisabled": true
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "10.01037626125837",
"currency": "015841551A748AD2C1F76FF6ECB0CCCD00000000",
"counterparty": "rs9M85karFkCRjvc6KMWn8Coigm9cbcgcx",
"ripplingDisabled": true
},
"counterparty": {
"limit": "0"
},
"state": {
"balance": "0"
}
},
{
"specification": {
"limit": "0",
"currency": "USD",
"counterparty": "rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF",
"frozen": true
},
"counterparty": {
"limit": "1"
},
"state": {
"balance": "0"
}
}
]

View File

@@ -6,6 +6,7 @@ module.exports = {
getBalances: require('./get-balances.json'),
getBalanceSheet: require('./get-balance-sheet.json'),
getOrderbook: require('./get-orderbook.json'),
getOrderbookWithXRP: require('./get-orderbook-with-xrp.json'),
getOrders: require('./get-orders.json'),
getPaths: {
XrpToUsd: require('./get-paths.json'),
@@ -20,6 +21,8 @@ module.exports = {
orderWithExpirationCancellation:
require('./get-transaction-order-with-expiration-cancellation.json'),
order: require('./get-transaction-order.json'),
orderSell: require('./get-transaction-order-sell.json'),
noMeta: require('./get-transaction-no-meta.json'),
payment: require('./get-transaction-payment.json'),
settings: require('./get-transaction-settings.json'),
trustline: require('./get-transaction-trustline-set.json'),
@@ -31,26 +34,37 @@ module.exports = {
notValidated: require('./get-transaction-not-validated.json'),
suspendedPaymentCreation:
require('./get-transaction-suspended-payment-create.json'),
SuspendedPaymentCreationIOU:
require('./get-transaction-suspended-payment-create-iou.json'),
suspendedPaymentCancellation:
require('./get-transaction-suspended-payment-cancellation.json'),
suspendedPaymentExecution:
require('./get-transaction-suspended-payment-execution.json')
require('./get-transaction-suspended-payment-execution.json'),
suspendedPaymentExecutionSimple:
require('./get-transaction-suspended-payment-execution-simple.json')
},
getTransactions: require('./get-transactions.json'),
getTransactionsOne: require('./get-transactions-one.json'),
getTrustlines: require('./get-trustlines.json'),
getTrustlinesAll: require('./get-trustlines-all.json'),
getLedger: {
header: require('./get-ledger'),
full: require('./get-ledger-full'),
withSettingsTx: require('./get-ledger-with-settings-tx')
withSettingsTx: require('./get-ledger-with-settings-tx'),
withStateAsHashes: require('./get-ledger-with-state-as-hashes')
},
prepareOrderCancellation: require('./prepare-order-cancellation.json'),
prepareOrder: {
buy: require('./prepare-order.json'),
sell: require('./prepare-order-sell.json'),
expiration: require('./prepare-order-expiration')
expiration: require('./prepare-order-expiration'),
cancellation: require('./prepare-order-cancellation.json'),
cancellationNoInstructions:
require('./prepare-order-cancellation-no-instructions.json')
},
preparePayment: {
normal: require('./prepare-payment.json'),
minAmountXRP: require('./prepare-payment-min-amont-xrp.json'),
minAmountXRPXRP: require('./prepare-payment-min-amont-xrp-xrp.json'),
allOptions: require('./prepare-payment-all-options.json'),
noCounterparty: require('./prepare-payment-no-counterparty.json'),
minAmount: require('./prepare-payment-min-amount.json')
@@ -62,20 +76,28 @@ module.exports = {
flagSet: require('./prepare-settings-flag-set.json'),
flagClear: require('./prepare-settings-flag-clear.json'),
setTransferRate: require('./prepare-settings-set-transfer-rate.json'),
fieldClear: require('./prepare-settings-field-clear.json')
fieldClear: require('./prepare-settings-field-clear.json'),
noInstructions: require('./prepare-settings-no-instructions.json')
},
prepareSuspendedPaymentCreation:
require('./prepare-suspended-payment-creation'),
prepareSuspendedPaymentCreationFull:
require('./prepare-suspended-payment-creation-full'),
prepareSuspendedPaymentExecution:
require('./prepare-suspended-payment-execution'),
prepareSuspendedPaymentExecutionSimple:
require('./prepare-suspended-payment-execution-simple'),
prepareSuspendedPaymentCancellation:
require('./prepare-suspended-payment-cancellation'),
prepareSuspendedPaymentCancellationMemos:
require('./prepare-suspended-payment-cancellation-memos'),
prepareTrustline: {
simple: require('./prepare-trustline-simple.json'),
frozen: require('./prepare-trustline-frozen.json'),
complex: require('./prepare-trustline.json')
},
sign: require('./sign.json'),
signSuspended: require('./sign-suspended.json'),
submit: require('./submit.json'),
ledgerClosed: require('./ledger-closed.json')
ledgerEvent: require('./ledger-event.json')
};

View File

@@ -1,11 +1,10 @@
{
"feeBase": 10,
"feeReference": 10,
"baseFeeXRP": "0.00001",
"ledgerVersion": 14804627,
"ledgerHash": "9141FA171F2C0CE63E609466AF728FF66C12F7ACD4B4B50B0947A7F3409D593A",
"ledgerTimestamp": "2015-07-23T05:50:40.000Z",
"reserveBase": 20000000,
"reserveIncrement": 5000000,
"reserveBaseXRP": "20",
"reserveIncrementXRP": "5",
"transactionCount": 19,
"validatedLedgerVersions": "13983423-14804627"
}

View File

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

View File

@@ -1,8 +1,8 @@
{
"txJSON": "{\"Flags\":2147614720,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"txJSON": "{\"Flags\":2147811328,\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":\"2000000\",\"TakerPays\":{\"value\":\"10.1\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8820051
"maxLedgerVersion": 8819954
}
}

View File

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

View File

@@ -0,0 +1,8 @@
{
"txJSON": "{\"TransactionType\":\"Payment\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":\"100000000000000000\",\"Flags\":2147614720,\"SendMax\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"0.01\"},\"DeliverMin\":\"100000000000000000\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8820051
}
}

View File

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

View File

@@ -0,0 +1,8 @@
{
"txJSON": "{\"TransactionType\":\"SuspendedPaymentCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"Flags\":2147483648,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8819954
}
}

View File

@@ -0,0 +1,8 @@
{
"txJSON": "{\"TransactionType\":\"SuspendedPaymentCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"0.01\"},\"Digest\":\"8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4\",\"FinishAfter\":464908910,\"SourceTag\":1,\"DestinationTag\":2,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\"}}],\"Flags\":2147483648,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8819954
}
}

View File

@@ -0,0 +1,8 @@
{
"txJSON": "{\"TransactionType\":\"SuspendedPaymentFinish\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"Flags\":2147483648,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8819954
}
}

View File

@@ -0,0 +1,8 @@
{
"txJSON": "{\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"currency\":\"BTC\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"0.1\"},\"Flags\":2148859904,\"LastLedgerSequence\":8819954,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8819954
}
}

View File

@@ -24,6 +24,7 @@ module.exports = function(request, options = {}) {
'issuer': 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
'value': '17.70155237781915'
},
'quality': '63.44025128030504',
'taker_pays': {
'currency': 'USD',
'issuer': 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',

View File

@@ -0,0 +1,31 @@
{
"id": 0,
"result": {
"ledger_hash": "36783BEDBDEFC0402EB5347B8D9545AC69E70B0F14A95E0879CE2D3C2B4CE748",
"ledger_index": 13,
"offers": [
{
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"BookDirectory": "A118405CF7C2C89AB0CC084417187B86870DC14325C861A0561BB6E89EFF509C",
"BookNode": "0000000000000000",
"Flags": 131072,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "CFB5786459E568DFC504E7319C515658DED657A7F4EFB5957B33E5E3BD9A1353",
"PreviousTxnLgrSeq": 13,
"Sequence": 6,
"TakerPays": "134000000",
"TakerGets": {
"currency": "USD",
"issuer": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"value": "10453252347.1"
},
"index": "C72CDC1BA4DA529B062871F22C6D175A4D97D4F1160D0D7E646E60699278B5B5",
"quality": "78.0093458738806"
}
],
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,32 @@
{
"id": 3,
"result": {
"ledger_hash": "36783BEDBDEFC0402EB5347B8D9545AC69E70B0F14A95E0879CE2D3C2B4CE748",
"ledger_index": 13,
"offers": [
{
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"BookDirectory": "A118405CF7C2C89AB0CC084417187B86870DC14325C861A0470E1AEE5CBE20D9",
"BookNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "9DD36CC7338FEB9E501A33EAAA4C00DBE4ED3A692704C62DDBD1848EE1F6E762",
"PreviousTxnLgrSeq": 11,
"Sequence": 5,
"TakerGets": "254391353000000",
"TakerPays": {
"currency": "USD",
"issuer": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"value": "10.1"
},
"index": "BF656DABDD84E6128A45039F8D557C9477D4DA31F5B00868F2191F0A11FE3798",
"owner_funds": "99999998959999928",
"quality": "3970260734451929e-29"
}
],
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,58 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"account": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"ledger_index_max": 17207682,
"ledger_index_min": 16462279,
"limit": 400,
"transactions": [
{
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
"Balance": "71515076",
"Domain": "726970706C652E636F6D",
"Flags": 65536,
"OwnerCount": 3,
"RegularKey": "rsvEdWvfwzqkgvmaSEh9kgbcWiUc6s69ZC",
"Sequence": 492
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "4AD70690C6FF8A069F8AE00B09F70E9B732360026E8085050D314432091A59C9",
"PreviousFields": {
"Balance": "71527076",
"Sequence": 491
},
"PreviousTxnID": "9B093C92C94EC9E492631B21E2DF45A9142C1BC39B60F3E5C4018DBAA164A423",
"PreviousTxnLgrSeq": 16318991
}
}
],
"TransactionIndex": 4,
"TransactionResult": "tesSUCCESS"
},
"tx": {
"Account": "r9UHu5CWni1qRY7Q4CfFZLGvXo2pGQy96b",
"Domain": "726970706C652E636F6D",
"Fee": "12000",
"Flags": 2147483648,
"LastLedgerSequence": 16635157,
"Sequence": 491,
"SigningPubKey": "036A749E3B7187E43E8936E3D83A7030989325249E03803F12B7F64BAACABA6025",
"TransactionType": "AccountSet",
"TxnSignature": "3044022060C8F4CDD6092B539612790705B967E68111BC270B6B80AF23DF7B33E4C77137022059D9A8AA81052B7348F2728B263E2CCBEBE32880C54936D335F8125C6ED2F90E",
"date": 498881220,
"hash": "D868CFF0DF8C8AAF205404460EA764ACB3B8862527FA414BC8C1CA9A45B1F276",
"inLedger": 16635149,
"ledger_index": 16635149
},
"validated": true
}
]
}
}

View File

@@ -9,6 +9,7 @@ module.exports = {
ledgerNotFound: require('./ledger-not-found'),
ledgerWithoutCloseTime: require('./ledger-without-close-time'),
ledgerWithSettingsTx: require('./ledger-with-settings-tx'),
ledgerWithStateAsHashes: require('./ledger-with-state-as-hashes'),
subscribe: require('./subscribe'),
unsubscribe: require('./unsubscribe'),
account_info: {
@@ -17,8 +18,11 @@ module.exports = {
},
account_offers: require('./account-offers'),
account_tx: require('./account-tx'),
account_tx_one: require('./get-transactions-one'),
gateway_balances: require('./gateway-balances'),
book_offers: require('./book-offers'),
book_offers_1: require('./book-offers-1'),
book_offers_2: require('./book-offers-2'),
server_info: require('./server-info'),
server_info_error: require('./server-info-error'),
path_find: {
@@ -35,6 +39,7 @@ module.exports = {
AccountSetTrackingOff: require('./tx/account-set-tracking-off.json'),
RegularKey: require('./tx/set-regular-key.json'),
OfferCreate: require('./tx/offer-create.json'),
OfferCreateSell: require('./tx/offer-create-sell.json'),
OfferCancel: require('./tx/offer-cancel.json'),
TrustSet: require('./tx/trust-set.json'),
TrustSetFrozenOff: require('./tx/trust-set-frozen-off.json'),
@@ -46,8 +51,15 @@ module.exports = {
NotValidated: require('./tx/not-validated.json'),
OfferWithExpiration: require('./tx/order-with-expiration.json'),
SuspendedPaymentCreation: require('./tx/suspended-payment-creation.json'),
SuspendedPaymentCreationIOU:
require('./tx/suspended-payment-creation-iou.json'),
SuspendedPaymentCancellation:
require('./tx/suspended-payment-cancellation.json'),
SuspendedPaymentExecution: require('./tx/suspended-payment-execution.json')
SuspendedPaymentExecution: require('./tx/suspended-payment-execution.json'),
SuspendedPaymentExecutionSimple:
require('./tx/suspended-payment-execution-simple.json'),
Unrecognized: require('./tx/unrecognized.json'),
NoMeta: require('./tx/no-meta.json'),
LedgerZero: require('./tx/ledger-zero.json')
}
};

View File

@@ -23,6 +23,7 @@
{
"Account": "rEGy9CxMTFGXFgUHUMreTy2FbqArabGy38",
"Fee": "10",
"ledger_index": 4181996,
"Flags": 0,
"Sequence": 6478,
"SigningPubKey": "02CAB6F3A798712136DB5F105A98B0DE27C99AEDB68500181706B087CF1B6D0F2D",

View File

@@ -0,0 +1,33 @@
{
"id": 2,
"result": {
"ledger": {
"accepted": true,
"accountState": [
"2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
"8B24E55376A65D68542C17F3BF446231AC7062CB43BED28817570128A1849819",
"B4979A36CDC7F3D3D5C31A4EAE2AC7D7209DDA877588B9AFC66799692AB0D66B"
],
"account_hash": "8DBB7FA4036704D96AD32A4573BEE461FDDBDCB1B6F62CB17EDB5182F52AE9F1",
"close_flags": 0,
"close_time": 501159630,
"close_time_human": "2015-Nov-18 11:00:30",
"close_time_resolution": 30,
"closed": true,
"ledger_hash": "3D7115EDB5EC72FEF4ADDF46CA5B7770CBDECEAB3A97EA210BCC04E8C54A7CEE",
"parent_close_time": 501148381,
"parent_hash": "6D36AEFD3639EE22A27DDE0FA6C57525D103941F11D7FD6D91AC8D439DE2B3EE",
"seqNum": "6",
"totalCoins": "99999999999999964",
"transaction_hash": "B8D716B82BFFF4186BBBE7B7341AE0E1CBD2558952408B96E925EC0A51A6AEC2",
"transactions": [
"B22E27F35F3F7679F76A474E4FF8E71EFA21B313DF2FC6678037A053A00FD084"
]
},
"ledger_hash": "3D7115EDB5EC72FEF4ADDF46CA5B7770CBDECEAB3A97EA210BCC04E8C54A7CEE",
"ledger_index": 6,
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,46 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"Account": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe",
"Fee": "10",
"Flags": 2147483648,
"Sequence": 1,
"SetFlag": 2,
"SigningPubKey": "03EA3ADCA632F125EC2CC4F7F6A82DE0DCE2B65290CAC1F22242C5163F0DA9652D",
"TransactionType": "AccountSet",
"TxnSignature": "3045022100DE8B666B1A31EA65011B0F32130AB91A5747E32FA49B3054CEE8E8362DBAB98A022040CF0CF254677A8E5CD04C59CA2ED7F6F15F7E184641BAE169C561650967B226",
"date": 460832270,
"hash": "4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA13",
"inLedger": 0,
"ledger_index": 0,
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe",
"Balance": "29999990",
"Flags": 786432,
"OwnerCount": 0,
"Sequence": 2
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "3F5072C4875F32ED770DAF3610A716600ED7C7BB0348FADC7A98E011BB2CD36F",
"PreviousFields": {
"Balance": "30000000",
"Flags": 4194304,
"Sequence": 1
},
"PreviousTxnID": "3FB0350A3742BBCC0D8AA3C5247D1AEC01177D0A24D9C34762BAA2FEA8AD88B3",
"PreviousTxnLgrSeq": 8206397
}
}
],
"TransactionIndex": 5,
"TransactionResult": "tesSUCCESS"
},
"validated": true
}
}

44
test/fixtures/rippled/tx/no-meta.json vendored Normal file
View File

@@ -0,0 +1,44 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"Account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"Amount": {
"currency": "USD",
"issuer": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "0.001"
},
"Destination": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"Fee": "10",
"Flags": 0,
"Paths": [
[
{
"currency": "USD",
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"type": 48,
"type_hex": "0000000000000030"
},
{
"account": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"currency": "USD",
"issuer": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
"type": 49,
"type_hex": "0000000000000031"
}
]
],
"SendMax": "1112209",
"Sequence": 4,
"SigningPubKey": "02BC8C02199949B15C005B997E7C8594574E9B02BA2D0628902E0532989976CF9D",
"TransactionType": "Payment",
"TxnSignature": "304502204EE3E9D1B01D8959B08450FCA9E22025AF503DEF310E34A93863A85CAB3C0BC5022100B61F5B567F77026E8DEED89EED0B7CAF0E6C96C228A2A65216F0DC2D04D52083",
"date": 416447810,
"hash": "AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B",
"inLedger": 348860,
"ledger_index": 348860,
"validated": true,
"validated": true
}
}

View File

@@ -0,0 +1,51 @@
{
"id": 0,
"result": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Fee": "12",
"Flags": 2148007936,
"LastLedgerSequence": 105,
"Sequence": 2,
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
"TakerGets": {
"currency": "USD",
"issuer": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "10.1"
},
"TakerPays": "254391353000000",
"TransactionType": "OfferCreate",
"TxnSignature": "30440221008C13CA1BD56431B643FD145CDE7BE1805424B48FDF40E0D1A8C2FD53FAACA974021F6393721438C01B9E3138D55469049C8B72B4F6A4508ACA3C0036788C300459",
"date": 501195390,
"hash": "458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2",
"inLedger": 6,
"ledger_index": 6,
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Balance": "99999999259999976",
"Flags": 0,
"OwnerCount": 0,
"Sequence": 3
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
"PreviousFields": {
"Balance": "99999999259999988",
"Sequence": 2
},
"PreviousTxnID": "4BF785A253AB67875973EE79B3ED939DF371B435696D09F8BE2FB2DADA1BFAB7",
"PreviousTxnLgrSeq": 4
}
}
],
"TransactionIndex": 0,
"TransactionResult": "tecUNFUNDED_OFFER"
},
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,97 @@
{
"id": 0,
"result": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Amount": {"value": "2", "issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "currency": "USD"},
"CancelAfter": 500972022,
"Destination": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"DestinationTag": 2,
"Digest": "8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4",
"Fee": "12",
"FinishAfter": 500971662,
"Flags": 2147483648,
"LastLedgerSequence": 114,
"Memos": [
{
"Memo": {
"MemoData": "6D656D612064617461",
"MemoFormat": "746578742F706C61696E",
"MemoType": "7832"
}
}
],
"Sequence": 10,
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
"SourceTag": 1,
"TransactionType": "SuspendedPaymentCreate",
"TxnSignature": "3045022100EA1C5433AFA3F0BAAAF7C4146B032B86A0212EB4E2A3551DE9717651A538AE260220228C9E9FC857EC8143F01C2F959A8F134B285B67D8261B49E57BFF8DF76D2255",
"date": 500971380,
"hash": "144F272380BDB4F1BD92329A2178BABB70C20F59042C495E10BF72EBFB408EE2",
"inLedger": 15,
"ledger_index": 15,
"meta": {
"AffectedNodes": [
{
"CreatedNode": {
"LedgerEntryType": "SuspendedPayment",
"LedgerIndex": "0D7629A23BC20F25C48D9423E2485582255A74B76A25F26EDB46766982E4C2C4",
"NewFields": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Amount": "2",
"CancelAfter": 500972022,
"Destination": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"DestinationTag": 2,
"Digest": "8F434346648F6B96DF89DDA901C5176B10A6D83961DD3C1AC88B59B2DC327AA4",
"FinishAfter": 500971662,
"SourceTag": 1
}
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Balance": "99999997964999876",
"Flags": 0,
"OwnerCount": 3,
"Sequence": 11
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
"PreviousFields": {
"Balance": "99999997964999890",
"OwnerCount": 2,
"Sequence": 10
},
"PreviousTxnID": "F346E542FFB7A8398C30A87B952668DAB48B7D421094F8B71776DA19775A3B22",
"PreviousTxnLgrSeq": 14
}
},
{
"ModifiedNode": {
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "8B24E55376A65D68542C17F3BF446231AC7062CB43BED28817570128A1849819",
"PreviousTxnID": "F346E542FFB7A8398C30A87B952668DAB48B7D421094F8B71776DA19775A3B22",
"PreviousTxnLgrSeq": 14
}
},
{
"ModifiedNode": {
"FinalFields": {
"Flags": 0,
"Owner": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"RootIndex": "D8120FC732737A2CF2E9968FDF3797A43B457F2A81AA06D2653171A1EA635204"
},
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "D8120FC732737A2CF2E9968FDF3797A43B457F2A81AA06D2653171A1EA635204"
}
}
],
"TransactionIndex": 0,
"TransactionResult": "tesSUCCESS"
},
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,99 @@
{
"id": 0,
"result": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Digest": "632F2F3E437AE720C397994A985B5D21FE186DE61523A9CA3E8709CC581671A1",
"Fee": "12",
"Flags": 2147483648,
"LastLedgerSequence": 113,
"Method": 1,
"OfferSequence": 5,
"Owner": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Sequence": 6,
"SigningPubKey": "0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020",
"TransactionType": "SuspendedPaymentFinish",
"TxnSignature": "304402204E981802BA2F4C3677E69B26387CC157284D31886CF95B73A8AB3E717FE6A6490220519CD84CA01BA5D7A49809B041929F12D56F32E76FAE73F0FAFF7B5E7B8B110B",
"date": 501040060,
"hash": "CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD1369931",
"inLedger": 14,
"ledger_index": 14,
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Balance": "99999999239999842",
"Flags": 0,
"OwnerCount": 0,
"Sequence": 7
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8",
"PreviousFields": {
"Balance": "99999999239999854",
"OwnerCount": 1,
"Sequence": 6
},
"PreviousTxnID": "22E0E87BAD4832CFD2B49409D488E5F92DD38424FD1781602277585914120C1E",
"PreviousTxnLgrSeq": 12
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"Balance": "760000086",
"Flags": 0,
"OwnerCount": 0,
"Sequence": 1
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "8B24E55376A65D68542C17F3BF446231AC7062CB43BED28817570128A1849819",
"PreviousFields": {
"Balance": "750000043"
},
"PreviousTxnID": "22E0E87BAD4832CFD2B49409D488E5F92DD38424FD1781602277585914120C1E",
"PreviousTxnLgrSeq": 12
}
},
{
"DeletedNode": {
"FinalFields": {
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"Amount": "10000043",
"CancelAfter": 501079458,
"Destination": "rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw",
"DestinationTag": 2,
"Digest": "632F2F3E437AE720C397994A985B5D21FE186DE61523A9CA3E8709CC581671A1",
"FinishAfter": 501039918,
"Flags": 0,
"OwnerNode": "0000000000000000",
"PreviousTxnID": "22E0E87BAD4832CFD2B49409D488E5F92DD38424FD1781602277585914120C1E",
"PreviousTxnLgrSeq": 12,
"SourceTag": 1
},
"LedgerEntryType": "SuspendedPayment",
"LedgerIndex": "AA7D93BDB975252718205C98792BF8940E3FC6E6972213F451AB5D602E8AD971"
}
},
{
"DeletedNode": {
"FinalFields": {
"Flags": 0,
"Owner": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"RootIndex": "D8120FC732737A2CF2E9968FDF3797A43B457F2A81AA06D2653171A1EA635204"
},
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "D8120FC732737A2CF2E9968FDF3797A43B457F2A81AA06D2653171A1EA635204"
}
}
],
"TransactionIndex": 0,
"TransactionResult": "tesSUCCESS"
},
"validated": true
},
"status": "success",
"type": "response"
}

View File

@@ -0,0 +1,46 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"Account": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe",
"Fee": "10",
"Flags": 2147483648,
"Sequence": 1,
"SetFlag": 2,
"SigningPubKey": "03EA3ADCA632F125EC2CC4F7F6A82DE0DCE2B65290CAC1F22242C5163F0DA9652D",
"TransactionType": "Unrecognized",
"TxnSignature": "3045022100DE8B666B1A31EA65011B0F32130AB91A5747E32FA49B3054CEE8E8362DBAB98A022040CF0CF254677A8E5CD04C59CA2ED7F6F15F7E184641BAE169C561650967B226",
"date": 460832270,
"hash": "AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA11",
"inLedger": 8206418,
"ledger_index": 8206418,
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rLVKsA4F9iJBbA6rX2x4wCmkj6drgtqpQe",
"Balance": "29999990",
"Flags": 786432,
"OwnerCount": 0,
"Sequence": 2
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "3F5072C4875F32ED770DAF3610A716600ED7C7BB0348FADC7A98E011BB2CD36F",
"PreviousFields": {
"Balance": "30000000",
"Flags": 4194304,
"Sequence": 1
},
"PreviousTxnID": "3FB0350A3742BBCC0D8AA3C5247D1AEC01177D0A24D9C34762BAA2FEA8AD88B3",
"PreviousTxnLgrSeq": 8206397
}
}
],
"TransactionIndex": 5,
"TransactionResult": "tesSUCCESS"
},
"validated": true
}
}

View File

@@ -156,9 +156,9 @@ describe('integration tests', function() {
return txData;
});
}).then(txData => this.api.prepareOrderCancellation(
address, txData.Sequence, instructions).then(prepared =>
testTransaction(this, 'orderCancellation', ledgerVersion,
prepared))
address, {orderSequence: txData.Sequence}, instructions)
.then(prepared => testTransaction(this, 'orderCancellation',
ledgerVersion, prepared))
);
});
});

View File

@@ -70,7 +70,7 @@ module.exports = function(port) {
mock.expectedRequests = expectedRequests;
};
mock.once('connection', function(conn) {
mock.on('connection', function(conn) {
conn.on('message', function(requestJSON) {
const request = JSON.parse(requestJSON);
mock.emit('request_' + request.command, request, conn);
@@ -140,6 +140,8 @@ module.exports = function(port) {
assert.strictEqual(request.command, 'ledger');
if (request.ledger_index === 34) {
conn.send(createLedgerResponse(request, fixtures.ledgerNotFound));
} else if (request.ledger_index === 6) {
conn.send(createResponse(request, fixtures.ledgerWithStateAsHashes));
} else if (request.ledger_index === 9038215) {
conn.send(createLedgerResponse(request, fixtures.ledgerWithoutCloseTime));
} else if (request.ledger_index === 4181996) {
@@ -172,6 +174,9 @@ module.exports = function(port) {
} else if (request.transaction ===
'10A6FB4A66EE80BED46AAE4815D7DC43B97E944984CCD5B93BCF3F8538CABC51') {
conn.send(createResponse(request, fixtures.tx.OfferCreate));
} else if (request.transaction ===
'458101D51051230B1D56E9ACAFAA34451BF65FA000F95DF6F0FF5B3A62D83FC2') {
conn.send(createResponse(request, fixtures.tx.OfferCreateSell));
} else if (request.transaction ===
'809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E') {
conn.send(createResponse(request, fixtures.tx.OfferCancel));
@@ -204,6 +209,10 @@ module.exports = function(port) {
} else if (request.transaction ===
'144F272380BDB4F1BD92329A2178BABB70C20F59042C495E10BF72EBFB408EE1') {
conn.send(createResponse(request, fixtures.tx.SuspendedPaymentCreation));
} else if (request.transaction ===
'144F272380BDB4F1BD92329A2178BABB70C20F59042C495E10BF72EBFB408EE2') {
conn.send(createResponse(request,
fixtures.tx.SuspendedPaymentCreationIOU));
} else if (request.transaction ===
'F346E542FFB7A8398C30A87B952668DAB48B7D421094F8B71776DA19775A3B22') {
conn.send(createResponse(request,
@@ -211,6 +220,19 @@ module.exports = function(port) {
} else if (request.transaction ===
'CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD136993B') {
conn.send(createResponse(request, fixtures.tx.SuspendedPaymentExecution));
} else if (request.transaction ===
'CC5277137B3F25EE8B86259C83CB0EAADE818505E4E9BCBF19B1AC6FD1369931') {
conn.send(createResponse(request,
fixtures.tx.SuspendedPaymentExecutionSimple));
} else if (request.transaction ===
'AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA11') {
conn.send(createResponse(request, fixtures.tx.Unrecognized));
} else if (request.transaction ===
'AFB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B') {
conn.send(createResponse(request, fixtures.tx.NoMeta));
} else if (request.transaction ===
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA13') {
conn.send(createResponse(request, fixtures.tx.LedgerZero));
} else {
assert(false, 'Unrecognized transaction hash: ' + request.transaction);
}
@@ -240,6 +262,8 @@ module.exports = function(port) {
mock.on('request_account_tx', function(request, conn) {
if (request.account === addresses.ACCOUNT) {
conn.send(transactionsResponse(request));
} else if (request.account === addresses.OTHER_ACCOUNT) {
conn.send(createResponse(request, fixtures.account_tx_one));
} else {
assert(false, 'Unrecognized account address: ' + request.account);
}
@@ -254,7 +278,12 @@ module.exports = function(port) {
});
mock.on('request_book_offers', function(request, conn) {
if (isBTC(request.taker_gets.currency)
if (request.taker_pays.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
conn.send(createResponse(request, fixtures.book_offers_2));
} else if (request.taker_gets.issuer
=== 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
conn.send(createResponse(request, fixtures.book_offers_1));
} else if (isBTC(request.taker_gets.currency)
&& isUSD(request.taker_pays.currency)) {
conn.send(fixtures.book_offers.requestBookOffersBidsResponse(request));
} else if (isUSD(request.taker_gets.currency)
@@ -296,7 +325,11 @@ module.exports = function(port) {
});
mock.on('request_gateway_balances', function(request, conn) {
conn.send(createResponse(request, fixtures.gateway_balances));
if (request.ledger_index === 123456) {
conn.send(createResponse(request, fixtures.unsubscribe));
} else {
conn.send(createResponse(request, fixtures.gateway_balances));
}
});
return mock;

View File

@@ -25,7 +25,7 @@ function setupMockRippledConnection(testcase, port, done) {
testcase.mockRippled = createMockRippled(port);
testcase.api = new RippleAPI({servers: ['ws://localhost:' + port]});
testcase.api.connect().then(() => {
testcase.api.once('ledgerClosed', () => done());
testcase.api.once('ledger', () => done());
testcase.api.connection._ws.emit('message', JSON.stringify(ledgerClosed));
}).catch(done);
}