mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-04 21:15:47 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5564330f6 | ||
|
|
43ccb83f73 | ||
|
|
e2d92126c0 | ||
|
|
8c8eef45d5 | ||
|
|
a574e1158a | ||
|
|
af687a6aed | ||
|
|
016e82ab5d | ||
|
|
f300a412d7 | ||
|
|
75e2249cf3 | ||
|
|
1942bcb971 | ||
|
|
9393adf66f | ||
|
|
917aae9bf3 | ||
|
|
da36457d5c | ||
|
|
15a0ededc8 | ||
|
|
68d7864f93 | ||
|
|
1eddbf995f | ||
|
|
592385ac73 | ||
|
|
56d626f5b1 | ||
|
|
7a14300409 | ||
|
|
30fa8d658e | ||
|
|
c0101cb5e7 | ||
|
|
fd640cd65e | ||
|
|
11528eff92 | ||
|
|
3c9175459d |
@@ -30,7 +30,7 @@ Then see the [documentation](https://github.com/ripple/ripple-lib/blob/develop/d
|
||||
|
||||
##Generating Documentation
|
||||
|
||||
The continuous integration tests require that the documentation stays up-to-date. If you make changes the the JSON schemas, fixtures, or documentation sources, you must update the documentation by running `npm run docgen`.
|
||||
The continuous integration tests require that the documentation stays up-to-date. If you make changes to the JSON schemas, fixtures, or documentation sources, you must update the documentation by running `npm run docgen`.
|
||||
|
||||
##More Information
|
||||
|
||||
|
||||
421
docs/index.md
421
docs/index.md
@@ -24,9 +24,12 @@
|
||||
- [Order](#order)
|
||||
- [Order Cancellation](#order-cancellation)
|
||||
- [Settings](#settings)
|
||||
- [Suspended Payment Creation](#suspended-payment-creation)
|
||||
- [Suspended Payment Cancellation](#suspended-payment-cancellation)
|
||||
- [Suspended Payment Execution](#suspended-payment-execution)
|
||||
- [Escrow Creation](#escrow-creation)
|
||||
- [Escrow Cancellation](#escrow-cancellation)
|
||||
- [Escrow Execution](#escrow-execution)
|
||||
- [Payment Channel Create](#payment-channel-create)
|
||||
- [Payment Channel Fund](#payment-channel-fund)
|
||||
- [Payment Channel Claim](#payment-channel-claim)
|
||||
- [API Methods](#api-methods)
|
||||
- [connect](#connect)
|
||||
- [disconnect](#disconnect)
|
||||
@@ -50,9 +53,12 @@
|
||||
- [prepareOrder](#prepareorder)
|
||||
- [prepareOrderCancellation](#prepareordercancellation)
|
||||
- [prepareSettings](#preparesettings)
|
||||
- [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
- [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
- [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
- [prepareEscrowCreation](#prepareescrowcreation)
|
||||
- [prepareEscrowCancellation](#prepareescrowcancellation)
|
||||
- [prepareEscrowExecution](#prepareescrowexecution)
|
||||
- [preparePaymentChannelCreate](#preparepaymentchannelcreate)
|
||||
- [preparePaymentChannelClaim](#preparepaymentchannelclaim)
|
||||
- [preparePaymentChannelFund](#preparepaymentchannelfund)
|
||||
- [sign](#sign)
|
||||
- [combine](#combine)
|
||||
- [submit](#submit)
|
||||
@@ -180,9 +186,9 @@ Methods that depend on the state of the Ripple Consensus Ledger are unavailable
|
||||
* [prepareOrder](#prepareorder)
|
||||
* [prepareOrderCancellation](#prepareordercancellation)
|
||||
* [prepareSettings](#preparesettings)
|
||||
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
* [prepareEscrowCreation](#prepareescrowcreation)
|
||||
* [prepareEscrowCancellation](#prepareescrowcancellation)
|
||||
* [prepareEscrowExecution](#prepareescrowexecution)
|
||||
* [sign](#sign)
|
||||
* [generateAddress](#generateaddress)
|
||||
* [computeLedgerHash](#computeledgerhash)
|
||||
@@ -261,11 +267,11 @@ Type | Description
|
||||
[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.
|
||||
[settings](#settings) | A `settings` transaction modifies the settings of an account in the Ripple Consensus Ledger.
|
||||
[suspendedPaymentCreation](#suspended-payment-creation) | A `suspendedPaymentCreation` transaction creates a suspended payment on the ledger, which locks XRP until a cryptographic condition is met or it expires. It is like an escrow service where the Ripple network acts as the escrow agent.
|
||||
[suspendedPaymentCancellation](#suspended-payment-cancellation) | A `suspendedPaymentCancellation` transaction unlocks the funds in a suspended payment and sends them back to the creator of the suspended payment, but it will only work after the suspended payment expires.
|
||||
[suspendedPaymentExecution](#suspended-payment-execution) | A `suspendedPaymentExecution` transaction unlocks the funds in a suspended payment and sends them to the destination of the suspended payment, but it will only work if the cryptographic condition is provided.
|
||||
[escrowCreation](#escrow-creation) | An `escrowCreation` transaction creates an escrow on the ledger, which locks XRP until a cryptographic condition is met or it expires. It is like an escrow service where the Ripple network acts as the escrow agent.
|
||||
[escrowCancellation](#escrow-cancellation) | An `escrowCancellation` transaction unlocks the funds in an escrow and sends them back to the creator of the escrow, but it will only work after the escrow expires.
|
||||
[escrowExecution](#escrow-execution) | An `escrowExecution` transaction unlocks the funds in an escrow and sends them to the destination of the escrow, but it will only work if the cryptographic condition is provided.
|
||||
|
||||
The three "suspended payment" transaction types are not supported by the production Ripple peer-to-peer network at this time. They are available for testing purposes if you [configure RippleAPI](#boilerplate) to connect to the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) instead.
|
||||
The three "escrow" transaction types are not supported by the production Ripple peer-to-peer network at this time. They are available for testing purposes if you [configure RippleAPI](#boilerplate) to connect to the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) instead.
|
||||
|
||||
## Transaction Flow
|
||||
|
||||
@@ -277,9 +283,9 @@ Executing a transaction with `RippleAPI` requires the following four steps:
|
||||
* [prepareOrder](#prepareorder)
|
||||
* [prepareOrderCancellation](#prepareordercancellation)
|
||||
* [prepareSettings](#preparesettings)
|
||||
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
* [prepareEscrowCreation](#prepareescrowcreation)
|
||||
* [prepareEscrowCancellation](#prepareescrowcancellation)
|
||||
* [prepareEscrowExecution](#prepareescrowexecution)
|
||||
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place. For multisignature transactions, the `signedTransaction` fields returned by `sign` must be collected and passed to the [combine](#combine) method.
|
||||
3. [Submit](#submit) - Submit the transaction to the connected server.
|
||||
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
|
||||
@@ -518,59 +524,41 @@ transferRate | number,null | *Optional* The fee to charge when users transfer t
|
||||
```
|
||||
|
||||
|
||||
## Suspended Payment Creation
|
||||
## Escrow Creation
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
source | object | Fields pertaining to the source of the payment.
|
||||
*source.* address | [address](#ripple-address) | The address to send from.
|
||||
*source.* maxAmount | [laxAmount](#amount) | The maximum amount to send. (This field is exclusive with source.amount)
|
||||
*source.* tag | integer | *Optional* An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.
|
||||
destination | object | Fields pertaining to the destination of the payment.
|
||||
*destination.* address | [address](#ripple-address) | The address to receive at.
|
||||
*destination.* amount | [laxAmount](#amount) | An exact amount to deliver to the recipient. If the counterparty is not specified, amounts with any counterparty may be used. (This field is exclusive with destination.minAmount).
|
||||
*destination.* tag | integer | *Optional* An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.
|
||||
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.
|
||||
amount | [value](#value) | Amount of XRP for sender to escrow.
|
||||
destination | [address](#ripple-address) | Address to receive escrowed XRP.
|
||||
allowCancelAfter | date-time string | *Optional* If present, the escrow may be cancelled after this time.
|
||||
allowExecuteAfter | date-time string | *Optional* If present, the escrow can not be executed before this time.
|
||||
condition | string | *Optional* If present, fulfillment is required upon execution.
|
||||
destinationTag | integer | *Optional* Destination tag.
|
||||
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
|
||||
sourceTag | integer | *Optional* Source tag.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"maxAmount": {
|
||||
"value": "0.01",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"destination": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": "0.01",
|
||||
"allowCancelAfter": "2014-09-24T21:21:50.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Suspended Payment Cancellation
|
||||
## Escrow Cancellation
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
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.
|
||||
owner | [address](#ripple-address) | The address of the owner of the escrow to cancel.
|
||||
escrowSequence | [sequence](#account-sequence-number) | The [account sequence number](#account-sequence-number) of the [Escrow Creation](#escrow-creation) transaction for the escrow to cancel.
|
||||
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
|
||||
|
||||
### Example
|
||||
@@ -579,23 +567,22 @@ memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the
|
||||
```json
|
||||
{
|
||||
"owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"suspensionSequence": 1234
|
||||
"escrowSequence": 1234
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Suspended Payment Execution
|
||||
## Escrow Execution
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
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.
|
||||
owner | [address](#ripple-address) | The address of the owner of the escrow to execute.
|
||||
escrowSequence | [sequence](#account-sequence-number) | The [account sequence number](#account-sequence-number) of the [Escrow Creation](#escrow-creation) transaction for the escrow to execute.
|
||||
condition | string | *Optional* The original `condition` from the escrow creation transaction. This is sha256 hash of `fulfillment` 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 condition with the new condition.
|
||||
fulfillment | string | *Optional* A value that produces the condition when hashed. It must be 32 charaters long and contain only 8-bit characters.
|
||||
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.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -603,10 +590,81 @@ proof | string | *Optional* A value that produces the digest when hashed. It mus
|
||||
```json
|
||||
{
|
||||
"owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"suspensionSequence": 1234,
|
||||
"method": 1,
|
||||
"digest": "712C36933822AD3A3D136C5DF97AA863B69F9CE88B2D6CE6BDD11BFDE290C19D",
|
||||
"proof": "this must have 32 characters...."
|
||||
"escrowSequence": 1234,
|
||||
"condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
||||
"fulfillment": "A0028000"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Payment Channel Create
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
amount | [value](#value) | Amount of XRP for sender to set aside in this channel.
|
||||
destination | [address](#ripple-address) | Address to receive XRP claims against this channel.
|
||||
settleDelay | number | Amount of time the source address must wait before closing the channel if it has unclaimed XRP.
|
||||
publicKey | string | Public key of the key pair the source will use to sign claims against this channel.
|
||||
cancelAfter | date-time string | *Optional* Time when this channel expires.
|
||||
destinationTag | integer | *Optional* Destination tag.
|
||||
sourceTag | integer | *Optional* Source tag.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": "1",
|
||||
"destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"settleDelay": 86400,
|
||||
"publicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Payment Channel Fund
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
amount | [value](#value) | Amount of XRP to fund the channel with.
|
||||
channel | string | 256-bit hexadecimal channel identifier.
|
||||
expiration | date-time string | *Optional* New expiration for this channel.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198",
|
||||
"amount": "1"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Payment Channel Claim
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
channel | string | 256-bit hexadecimal channel identifier.
|
||||
amount | [value](#value) | *Optional* XRP balance of this channel after claim is processed.
|
||||
balance | [value](#value) | *Optional* Amount of XRP authorized by signature.
|
||||
close | boolean | *Optional* Request to close the channel.
|
||||
publicKey | string | *Optional* Public key of the channel's sender
|
||||
renew | boolean | *Optional* Clear the channel's expiration time.
|
||||
signature | string | *Optional* Signature of this claim.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -3132,20 +3190,20 @@ return api.prepareSettings(address, settings)
|
||||
```
|
||||
|
||||
|
||||
## prepareSuspendedPaymentCreation
|
||||
## prepareEscrowCreation
|
||||
|
||||
`prepareSuspendedPaymentCreation(address: string, suspendedPaymentCreation: Object, instructions: Object): Promise<Object>`
|
||||
`prepareEscrowCreation(address: string, escrowCreation: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a suspended payment creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
Prepare an escrow creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
**Caution:** Escrow is currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#ripple-address) | The address of the account that is creating the transaction.
|
||||
suspendedPaymentCreation | [suspendedPaymentCreation](#suspended-payment-creation) | The specification of the suspended payment creation to prepare.
|
||||
escrowCreation | [escrowCreation](#escrow-creation) | The specification of the escrow creation to prepare.
|
||||
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
|
||||
|
||||
### Return Value
|
||||
@@ -3168,33 +3226,19 @@ instructions | object | The instructions for how to execute the transaction afte
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const suspendedPaymentCreation = {
|
||||
"source": {
|
||||
"address": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"maxAmount": {
|
||||
"value": "0.01",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
"destination": {
|
||||
"address": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": {
|
||||
"value": "0.01",
|
||||
"currency": "USD",
|
||||
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM"
|
||||
}
|
||||
},
|
||||
const escrowCreation = {
|
||||
"destination": "rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo",
|
||||
"amount": "0.01",
|
||||
"allowCancelAfter": "2014-09-24T21:21:50.000Z"
|
||||
};
|
||||
return api.prepareSuspendedPaymentCreation(address, suspendedPaymentCreation).then(prepared =>
|
||||
return api.prepareEscrowCreation(address, escrowCreation).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":{\"value\":\"0.01\",\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"CancelAfter\":464908910,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"EscrowCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Destination\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"Amount\":\"10000\",\"CancelAfter\":464908910,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
@@ -3204,20 +3248,20 @@ return api.prepareSuspendedPaymentCreation(address, suspendedPaymentCreation).th
|
||||
```
|
||||
|
||||
|
||||
## prepareSuspendedPaymentCancellation
|
||||
## prepareEscrowCancellation
|
||||
|
||||
`prepareSuspendedPaymentCancellation(address: string, suspendedPaymentCancellation: Object, instructions: Object): Promise<Object>`
|
||||
`prepareEscrowCancellation(address: string, escrowCancellation: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a suspended payment cancellation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
Prepare an escrow cancellation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
**Caution:** Escrow is currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#ripple-address) | The address of the account that is creating the transaction.
|
||||
suspendedPaymentCancellation | [suspendedPaymentCancellation](#suspended-payment-cancellation) | The specification of the suspended payment cancellation to prepare.
|
||||
escrowCancellation | [escrowCancellation](#escrow-cancellation) | The specification of the escrow cancellation to prepare.
|
||||
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
|
||||
|
||||
### Return Value
|
||||
@@ -3240,18 +3284,18 @@ instructions | object | The instructions for how to execute the transaction afte
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const suspendedPaymentCancellation = {
|
||||
const escrowCancellation = {
|
||||
"owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"suspensionSequence": 1234
|
||||
"escrowSequence": 1234
|
||||
};
|
||||
return api.prepareSuspendedPaymentCancellation(address, suspendedPaymentCancellation).then(prepared =>
|
||||
return api.prepareEscrowCancellation(address, escrowCancellation).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"EscrowCancel\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
@@ -3261,20 +3305,20 @@ return api.prepareSuspendedPaymentCancellation(address, suspendedPaymentCancella
|
||||
```
|
||||
|
||||
|
||||
## prepareSuspendedPaymentExecution
|
||||
## prepareEscrowExecution
|
||||
|
||||
`prepareSuspendedPaymentExecution(address: string, suspendedPaymentExecution: Object, instructions: Object): Promise<Object>`
|
||||
`prepareEscrowExecution(address: string, escrowExecution: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a suspended payment execution transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
Prepare an escrow execution transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
**Caution:** Escrow is currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#ripple-address) | The address of the account that is creating the transaction.
|
||||
suspendedPaymentExecution | [suspendedPaymentExecution](#suspended-payment-execution) | The specification of the suspended payment execution to prepare.
|
||||
escrowExecution | [escrowExecution](#escrow-execution) | The specification of the escrow execution to prepare.
|
||||
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
|
||||
|
||||
### Return Value
|
||||
@@ -3297,21 +3341,192 @@ instructions | object | The instructions for how to execute the transaction afte
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const suspendedPaymentExecution = {
|
||||
const escrowExecution = {
|
||||
"owner": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"suspensionSequence": 1234,
|
||||
"method": 1,
|
||||
"digest": "712C36933822AD3A3D136C5DF97AA863B69F9CE88B2D6CE6BDD11BFDE290C19D",
|
||||
"proof": "this must have 32 characters...."
|
||||
"escrowSequence": 1234,
|
||||
"condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
|
||||
"fulfillment": "A0028000"
|
||||
};
|
||||
return api.prepareSuspendedPaymentExecution(address, suspendedPaymentExecution).then(prepared =>
|
||||
return api.prepareEscrowExecution(address, escrowExecution).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"SuspendedPaymentFinish\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Method\":1,\"Digest\":\"712C36933822AD3A3D136C5DF97AA863B69F9CE88B2D6CE6BDD11BFDE290C19D\",\"Proof\":\"74686973206D757374206861766520333220636861726163746572732E2E2E2E\",\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"EscrowFinish\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Owner\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"OfferSequence\":1234,\"Condition\":\"A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100\",\"Fulfillment\":\"A0028000\",\"LastLedgerSequence\":8820051,\"Fee\":\"396\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000396",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## preparePaymentChannelCreate
|
||||
|
||||
`preparePaymentChannelCreate(address: string, paymentChannelCreate: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a payment channel creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Payment channels are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#ripple-address) | The address of the account that is creating the transaction.
|
||||
paymentChannelCreate | [paymentChannelCreate](#payment-channel-create) | The specification of the payment channel to create.
|
||||
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
txJSON | string | The prepared transaction in rippled JSON format.
|
||||
instructions | object | The instructions for how to execute the transaction after adding automatic defaults.
|
||||
*instructions.* fee | [value](#value) | An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.
|
||||
*instructions.* sequence | [sequence](#account-sequence-number) | The initiating account's sequence number for this transaction.
|
||||
*instructions.* maxLedgerVersion | integer,null | The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const paymentChannelCreate = {
|
||||
"amount": "1",
|
||||
"destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
|
||||
"settleDelay": 86400,
|
||||
"publicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A"
|
||||
};
|
||||
return api.preparePaymentChannelCreate(address, paymentChannelCreate).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON":"{\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransactionType\":\"PaymentChannelCreate\",\"Amount\":\"1000000\",\"Destination\":\"rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW\",\"SettleDelay\":86400,\"PublicKey\":\"32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A\",\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## preparePaymentChannelClaim
|
||||
|
||||
`preparePaymentChannelClaim(address: string, paymentChannelClaim: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a payment channel claim transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Payment channels are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#ripple-address) | The address of the account that is creating the transaction.
|
||||
paymentChannelClaim | [paymentChannelClaim](#payment-channel-claim) | Details of the channel and claim.
|
||||
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
txJSON | string | The prepared transaction in rippled JSON format.
|
||||
instructions | object | The instructions for how to execute the transaction after adding automatic defaults.
|
||||
*instructions.* fee | [value](#value) | An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.
|
||||
*instructions.* sequence | [sequence](#account-sequence-number) | The initiating account's sequence number for this transaction.
|
||||
*instructions.* maxLedgerVersion | integer,null | The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const paymentChannelClaim = {
|
||||
"channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198"
|
||||
};
|
||||
return api.preparePaymentChannelClaim(address, paymentChannelClaim).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON": "{\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransactionType\":\"PaymentChannelClaim\",\"Channel\":\"C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198\",\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
"maxLedgerVersion": 8820051
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## preparePaymentChannelFund
|
||||
|
||||
`preparePaymentChannelFund(address: string, paymentChannelFund: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a payment channel fund transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Payment channels are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
address | [address](#ripple-address) | The address of the account that is creating the transaction.
|
||||
paymentChannelFund | [paymentChannelFund](#payment-channel-fund) | The channel to fund, and the details of how to fund it.
|
||||
instructions | [instructions](#transaction-instructions) | *Optional* Instructions for executing the transaction
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
Name | Type | Description
|
||||
---- | ---- | -----------
|
||||
txJSON | string | The prepared transaction in rippled JSON format.
|
||||
instructions | object | The instructions for how to execute the transaction after adding automatic defaults.
|
||||
*instructions.* fee | [value](#value) | An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.
|
||||
*instructions.* sequence | [sequence](#account-sequence-number) | The initiating account's sequence number for this transaction.
|
||||
*instructions.* maxLedgerVersion | integer,null | The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const paymentChannelFund = {
|
||||
"channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198",
|
||||
"amount": "1"
|
||||
};
|
||||
return api.preparePaymentChannelFund(address, paymentChannelFund).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"txJSON":"{\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TransactionType\":\"PaymentChannelFund\",\"Channel\":\"C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198\",\"Amount\":\"1000000\",\"Flags\":2147483648,\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
|
||||
"instructions": {
|
||||
"fee": "0.000012",
|
||||
"sequence": 23,
|
||||
|
||||
@@ -27,9 +27,12 @@
|
||||
<% include prepareOrder.md.ejs %>
|
||||
<% include prepareOrderCancellation.md.ejs %>
|
||||
<% include prepareSettings.md.ejs %>
|
||||
<% include prepareSuspendedPaymentCreation.md.ejs %>
|
||||
<% include prepareSuspendedPaymentCancellation.md.ejs %>
|
||||
<% include prepareSuspendedPaymentExecution.md.ejs %>
|
||||
<% include prepareEscrowCreation.md.ejs %>
|
||||
<% include prepareEscrowCancellation.md.ejs %>
|
||||
<% include prepareEscrowExecution.md.ejs %>
|
||||
<% include preparePaymentChannelCreate.md.ejs %>
|
||||
<% include preparePaymentChannelClaim.md.ejs %>
|
||||
<% include preparePaymentChannelFund.md.ejs %>
|
||||
<% include sign.md.ejs %>
|
||||
<% include combine.md.ejs %>
|
||||
<% include submit.md.ejs %>
|
||||
|
||||
@@ -18,9 +18,9 @@ Methods that depend on the state of the Ripple Consensus Ledger are unavailable
|
||||
* [prepareOrder](#prepareorder)
|
||||
* [prepareOrderCancellation](#prepareordercancellation)
|
||||
* [prepareSettings](#preparesettings)
|
||||
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
* [prepareEscrowCreation](#prepareescrowcreation)
|
||||
* [prepareEscrowCancellation](#prepareescrowcancellation)
|
||||
* [prepareEscrowExecution](#prepareescrowexecution)
|
||||
* [sign](#sign)
|
||||
* [generateAddress](#generateaddress)
|
||||
* [computeLedgerHash](#computeledgerhash)
|
||||
|
||||
32
docs/src/prepareEscrowCancellation.md.ejs
Normal file
32
docs/src/prepareEscrowCancellation.md.ejs
Normal file
@@ -0,0 +1,32 @@
|
||||
## prepareEscrowCancellation
|
||||
|
||||
`prepareEscrowCancellation(address: string, escrowCancellation: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare an escrow cancellation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Escrow is currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-escrow-cancellation.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const escrowCancellation = <%- importFile('test/fixtures/requests/prepare-escrow-cancellation.json') %>;
|
||||
return api.prepareEscrowCancellation(address, escrowCancellation).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-escrow-cancellation.json') %>
|
||||
32
docs/src/prepareEscrowCreation.md.ejs
Normal file
32
docs/src/prepareEscrowCreation.md.ejs
Normal file
@@ -0,0 +1,32 @@
|
||||
## prepareEscrowCreation
|
||||
|
||||
`prepareEscrowCreation(address: string, escrowCreation: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare an escrow creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Escrow is currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-escrow-creation.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const escrowCreation = <%- importFile('test/fixtures/requests/prepare-escrow-creation.json') %>;
|
||||
return api.prepareEscrowCreation(address, escrowCreation).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-escrow-creation.json') %>
|
||||
32
docs/src/prepareEscrowExecution.md.ejs
Normal file
32
docs/src/prepareEscrowExecution.md.ejs
Normal file
@@ -0,0 +1,32 @@
|
||||
## prepareEscrowExecution
|
||||
|
||||
`prepareEscrowExecution(address: string, escrowExecution: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare an escrow execution transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Escrow is currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-escrow-execution.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const escrowExecution = <%- importFile('test/fixtures/requests/prepare-escrow-execution.json') %>;
|
||||
return api.prepareEscrowExecution(address, escrowExecution).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-escrow-execution.json') %>
|
||||
32
docs/src/preparePaymentChannelClaim.md.ejs
Normal file
32
docs/src/preparePaymentChannelClaim.md.ejs
Normal file
@@ -0,0 +1,32 @@
|
||||
## preparePaymentChannelClaim
|
||||
|
||||
`preparePaymentChannelClaim(address: string, paymentChannelClaim: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a payment channel claim transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Payment channels are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-payment-channel-claim.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const paymentChannelClaim = <%- importFile('test/fixtures/requests/prepare-payment-channel-claim.json') %>;
|
||||
return api.preparePaymentChannelClaim(address, paymentChannelClaim).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-payment-channel-claim.json') %>
|
||||
32
docs/src/preparePaymentChannelCreate.md.ejs
Normal file
32
docs/src/preparePaymentChannelCreate.md.ejs
Normal file
@@ -0,0 +1,32 @@
|
||||
## preparePaymentChannelCreate
|
||||
|
||||
`preparePaymentChannelCreate(address: string, paymentChannelCreate: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a payment channel creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Payment channels are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-payment-channel-create.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const paymentChannelCreate = <%- importFile('test/fixtures/requests/prepare-payment-channel-create.json') %>;
|
||||
return api.preparePaymentChannelCreate(address, paymentChannelCreate).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-payment-channel-create.json') %>
|
||||
32
docs/src/preparePaymentChannelFund.md.ejs
Normal file
32
docs/src/preparePaymentChannelFund.md.ejs
Normal file
@@ -0,0 +1,32 @@
|
||||
## preparePaymentChannelFund
|
||||
|
||||
`preparePaymentChannelFund(address: string, paymentChannelFund: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a payment channel fund transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Payment channels are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-payment-channel-fund.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const paymentChannelFund = <%- importFile('test/fixtures/requests/prepare-payment-channel-fund.json') %>;
|
||||
return api.preparePaymentChannelFund(address, paymentChannelFund).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-payment-channel-fund.json') %>
|
||||
@@ -1,32 +0,0 @@
|
||||
## prepareSuspendedPaymentCancellation
|
||||
|
||||
`prepareSuspendedPaymentCancellation(address: string, suspendedPaymentCancellation: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a suspended payment cancellation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-suspended-payment-cancellation.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const suspendedPaymentCancellation = <%- importFile('test/fixtures/requests/prepare-suspended-payment-cancellation.json') %>;
|
||||
return api.prepareSuspendedPaymentCancellation(address, suspendedPaymentCancellation).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-suspended-payment-cancellation.json') %>
|
||||
@@ -1,32 +0,0 @@
|
||||
## prepareSuspendedPaymentCreation
|
||||
|
||||
`prepareSuspendedPaymentCreation(address: string, suspendedPaymentCreation: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a suspended payment creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-suspended-payment-creation.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const suspendedPaymentCreation = <%- importFile('test/fixtures/requests/prepare-suspended-payment-creation.json') %>;
|
||||
return api.prepareSuspendedPaymentCreation(address, suspendedPaymentCreation).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-suspended-payment-creation.json') %>
|
||||
@@ -1,32 +0,0 @@
|
||||
## prepareSuspendedPaymentExecution
|
||||
|
||||
`prepareSuspendedPaymentExecution(address: string, suspendedPaymentExecution: Object, instructions: Object): Promise<Object>`
|
||||
|
||||
Prepare a suspended payment execution transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
|
||||
|
||||
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
|
||||
|
||||
### Parameters
|
||||
|
||||
<%- renderSchema('input/prepare-suspended-payment-execution.json') %>
|
||||
|
||||
### Return Value
|
||||
|
||||
This method returns a promise that resolves with an object with the following structure:
|
||||
|
||||
<aside class="notice">
|
||||
All "prepare*" methods have the same return type.
|
||||
</aside>
|
||||
|
||||
<%- renderSchema('output/prepare.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
const suspendedPaymentExecution = <%- importFile('test/fixtures/requests/prepare-suspended-payment-execution.json') %>;
|
||||
return api.prepareSuspendedPaymentExecution(address, suspendedPaymentExecution).then(prepared =>
|
||||
{/* ... */});
|
||||
```
|
||||
|
||||
<%- renderFixture('responses/prepare-suspended-payment-execution.json') %>
|
||||
@@ -52,32 +52,62 @@ See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderFixture('requests/prepare-settings.json') %>
|
||||
|
||||
## Suspended Payment Creation
|
||||
## Escrow Creation
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderSchema('specifications/suspended-payment-creation.json') %>
|
||||
<%- renderSchema('specifications/escrow-creation.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
<%- renderFixture('requests/prepare-suspended-payment-creation.json') %>
|
||||
<%- renderFixture('requests/prepare-escrow-creation.json') %>
|
||||
|
||||
## Suspended Payment Cancellation
|
||||
## Escrow Cancellation
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderSchema('specifications/suspended-payment-cancellation.json') %>
|
||||
<%- renderSchema('specifications/escrow-cancellation.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
<%- renderFixture('requests/prepare-suspended-payment-cancellation.json') %>
|
||||
<%- renderFixture('requests/prepare-escrow-cancellation.json') %>
|
||||
|
||||
## Suspended Payment Execution
|
||||
## Escrow Execution
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderSchema('specifications/suspended-payment-execution.json') %>
|
||||
<%- renderSchema('specifications/escrow-execution.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
<%- renderFixture('requests/prepare-suspended-payment-execution.json') %>
|
||||
<%- renderFixture('requests/prepare-escrow-execution.json') %>
|
||||
|
||||
## Payment Channel Create
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderSchema('specifications/payment-channel-create.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
<%- renderFixture('requests/prepare-payment-channel-create.json') %>
|
||||
|
||||
## Payment Channel Fund
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderSchema('specifications/payment-channel-fund.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
<%- renderFixture('requests/prepare-payment-channel-fund.json') %>
|
||||
|
||||
## Payment Channel Claim
|
||||
|
||||
See [Transaction Types](#transaction-types) for a description.
|
||||
|
||||
<%- renderSchema('specifications/payment-channel-claim.json') %>
|
||||
|
||||
### Example
|
||||
|
||||
<%- renderFixture('requests/prepare-payment-channel-claim.json') %>
|
||||
|
||||
@@ -11,11 +11,11 @@ Type | Description
|
||||
[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.
|
||||
[settings](#settings) | A `settings` transaction modifies the settings of an account in the Ripple Consensus Ledger.
|
||||
[suspendedPaymentCreation](#suspended-payment-creation) | A `suspendedPaymentCreation` transaction creates a suspended payment on the ledger, which locks XRP until a cryptographic condition is met or it expires. It is like an escrow service where the Ripple network acts as the escrow agent.
|
||||
[suspendedPaymentCancellation](#suspended-payment-cancellation) | A `suspendedPaymentCancellation` transaction unlocks the funds in a suspended payment and sends them back to the creator of the suspended payment, but it will only work after the suspended payment expires.
|
||||
[suspendedPaymentExecution](#suspended-payment-execution) | A `suspendedPaymentExecution` transaction unlocks the funds in a suspended payment and sends them to the destination of the suspended payment, but it will only work if the cryptographic condition is provided.
|
||||
[escrowCreation](#escrow-creation) | An `escrowCreation` transaction creates an escrow on the ledger, which locks XRP until a cryptographic condition is met or it expires. It is like an escrow service where the Ripple network acts as the escrow agent.
|
||||
[escrowCancellation](#escrow-cancellation) | An `escrowCancellation` transaction unlocks the funds in an escrow and sends them back to the creator of the escrow, but it will only work after the escrow expires.
|
||||
[escrowExecution](#escrow-execution) | An `escrowExecution` transaction unlocks the funds in an escrow and sends them to the destination of the escrow, but it will only work if the cryptographic condition is provided.
|
||||
|
||||
The three "suspended payment" transaction types are not supported by the production Ripple peer-to-peer network at this time. They are available for testing purposes if you [configure RippleAPI](#boilerplate) to connect to the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) instead.
|
||||
The three "escrow" transaction types are not supported by the production Ripple peer-to-peer network at this time. They are available for testing purposes if you [configure RippleAPI](#boilerplate) to connect to the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) instead.
|
||||
|
||||
## Transaction Flow
|
||||
|
||||
@@ -27,9 +27,9 @@ Executing a transaction with `RippleAPI` requires the following four steps:
|
||||
* [prepareOrder](#prepareorder)
|
||||
* [prepareOrderCancellation](#prepareordercancellation)
|
||||
* [prepareSettings](#preparesettings)
|
||||
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
|
||||
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
|
||||
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
|
||||
* [prepareEscrowCreation](#prepareescrowcreation)
|
||||
* [prepareEscrowCancellation](#prepareescrowcancellation)
|
||||
* [prepareEscrowExecution](#prepareescrowexecution)
|
||||
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place. For multisignature transactions, the `signedTransaction` fields returned by `sign` must be collected and passed to the [combine](#combine) method.
|
||||
3. [Submit](#submit) - Submit the transaction to the connected server.
|
||||
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
|
||||
|
||||
12
npm-shrinkwrap.json
generated
12
npm-shrinkwrap.json
generated
@@ -3249,9 +3249,9 @@
|
||||
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz"
|
||||
},
|
||||
"ripple-binary-codec": {
|
||||
"version": "0.1.5",
|
||||
"from": "ripple-binary-codec@>=0.1.5 <0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.5.tgz",
|
||||
"version": "0.1.9",
|
||||
"from": "ripple-binary-codec@>=0.1.8 <0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.1.9.tgz",
|
||||
"dependencies": {
|
||||
"lodash": {
|
||||
"version": "4.13.1",
|
||||
@@ -3261,9 +3261,9 @@
|
||||
}
|
||||
},
|
||||
"ripple-hashes": {
|
||||
"version": "0.2.0",
|
||||
"from": "ripple-hashes@>=0.2.0 <0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ripple-hashes/-/ripple-hashes-0.2.0.tgz"
|
||||
"version": "0.3.0",
|
||||
"from": "ripple-hashes@>=0.3.0 <0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ripple-hashes/-/ripple-hashes-0.3.0.tgz"
|
||||
},
|
||||
"ripple-keypairs": {
|
||||
"version": "0.10.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.17.4",
|
||||
"version": "0.17.6",
|
||||
"license": "ISC",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
@@ -24,8 +24,8 @@
|
||||
"jayson": "^1.2.2",
|
||||
"lodash": "^3.1.0",
|
||||
"ripple-address-codec": "^2.0.1",
|
||||
"ripple-binary-codec": "^0.1.5",
|
||||
"ripple-hashes": "^0.2.0",
|
||||
"ripple-binary-codec": "^0.1.9",
|
||||
"ripple-hashes": "^0.3.0",
|
||||
"ripple-keypairs": "^0.10.0",
|
||||
"ripple-lib-transactionparser": "^0.6.0",
|
||||
"ws": "^1.0.1"
|
||||
|
||||
135
src/api.js
135
src/api.js
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict'; // eslint-disable-line
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
/* eslint-disable max-len */
|
||||
// Enable core-js polyfills. This allows use of ES6/7 extensions listed here:
|
||||
@@ -9,48 +9,54 @@
|
||||
// In node.js env, polyfill might be already loaded (from any npm package),
|
||||
// that's why we do this check.
|
||||
if (!global._babelPolyfill) {
|
||||
require('babel-polyfill');
|
||||
require('babel-polyfill')
|
||||
}
|
||||
|
||||
const _ = require('lodash');
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const common = require('./common');
|
||||
const server = require('./server/server');
|
||||
const connect = server.connect;
|
||||
const disconnect = server.disconnect;
|
||||
const getServerInfo = server.getServerInfo;
|
||||
const getFee = server.getFee;
|
||||
const isConnected = server.isConnected;
|
||||
const getLedgerVersion = server.getLedgerVersion;
|
||||
const getTransaction = require('./ledger/transaction');
|
||||
const getTransactions = require('./ledger/transactions');
|
||||
const getTrustlines = require('./ledger/trustlines');
|
||||
const getBalances = require('./ledger/balances');
|
||||
const getBalanceSheet = require('./ledger/balance-sheet');
|
||||
const getPaths = require('./ledger/pathfind');
|
||||
const getOrders = require('./ledger/orders');
|
||||
const getOrderbook = require('./ledger/orderbook');
|
||||
const getSettings = require('./ledger/settings');
|
||||
const getAccountInfo = require('./ledger/accountinfo');
|
||||
const preparePayment = require('./transaction/payment');
|
||||
const prepareTrustline = require('./transaction/trustline');
|
||||
const prepareOrder = require('./transaction/order');
|
||||
const prepareOrderCancellation = require('./transaction/ordercancellation');
|
||||
const prepareSuspendedPaymentCreation =
|
||||
require('./transaction/suspended-payment-creation');
|
||||
const prepareSuspendedPaymentExecution =
|
||||
require('./transaction/suspended-payment-execution');
|
||||
const prepareSuspendedPaymentCancellation =
|
||||
require('./transaction/suspended-payment-cancellation');
|
||||
const prepareSettings = require('./transaction/settings');
|
||||
const sign = require('./transaction/sign');
|
||||
const combine = require('./transaction/combine');
|
||||
const submit = require('./transaction/submit');
|
||||
const errors = require('./common').errors;
|
||||
const _ = require('lodash')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const common = require('./common')
|
||||
const server = require('./server/server')
|
||||
const connect = server.connect
|
||||
const disconnect = server.disconnect
|
||||
const getServerInfo = server.getServerInfo
|
||||
const getFee = server.getFee
|
||||
const isConnected = server.isConnected
|
||||
const getLedgerVersion = server.getLedgerVersion
|
||||
const getTransaction = require('./ledger/transaction')
|
||||
const getTransactions = require('./ledger/transactions')
|
||||
const getTrustlines = require('./ledger/trustlines')
|
||||
const getBalances = require('./ledger/balances')
|
||||
const getBalanceSheet = require('./ledger/balance-sheet')
|
||||
const getPaths = require('./ledger/pathfind')
|
||||
const getOrders = require('./ledger/orders')
|
||||
const getOrderbook = require('./ledger/orderbook')
|
||||
const getSettings = require('./ledger/settings')
|
||||
const getAccountInfo = require('./ledger/accountinfo')
|
||||
const preparePayment = require('./transaction/payment')
|
||||
const prepareTrustline = require('./transaction/trustline')
|
||||
const prepareOrder = require('./transaction/order')
|
||||
const prepareOrderCancellation = require('./transaction/ordercancellation')
|
||||
const prepareEscrowCreation =
|
||||
require('./transaction/escrow-creation')
|
||||
const prepareEscrowExecution =
|
||||
require('./transaction/escrow-execution')
|
||||
const prepareEscrowCancellation =
|
||||
require('./transaction/escrow-cancellation')
|
||||
const preparePaymentChannelCreate =
|
||||
require('./transaction/payment-channel-create')
|
||||
const preparePaymentChannelFund =
|
||||
require('./transaction/payment-channel-fund')
|
||||
const preparePaymentChannelClaim =
|
||||
require('./transaction/payment-channel-claim')
|
||||
const prepareSettings = require('./transaction/settings')
|
||||
const sign = require('./transaction/sign')
|
||||
const combine = require('./transaction/combine')
|
||||
const submit = require('./transaction/submit')
|
||||
const errors = require('./common').errors
|
||||
const generateAddress =
|
||||
require('./offline/generate-address').generateAddressAPI;
|
||||
const computeLedgerHash = require('./offline/ledgerhash');
|
||||
const getLedger = require('./ledger/ledger');
|
||||
require('./offline/generate-address').generateAddressAPI
|
||||
const computeLedgerHash = require('./offline/ledgerhash')
|
||||
const getLedger = require('./ledger/ledger')
|
||||
|
||||
type APIOptions = {
|
||||
server?: string,
|
||||
@@ -63,42 +69,42 @@ type APIOptions = {
|
||||
// prevent access to non-validated ledger versions
|
||||
class RestrictedConnection extends common.Connection {
|
||||
request(request, timeout) {
|
||||
const ledger_index = request.ledger_index;
|
||||
const ledger_index = request.ledger_index
|
||||
if (ledger_index !== undefined && ledger_index !== 'validated') {
|
||||
if (!_.isNumber(ledger_index) || ledger_index > this._ledgerVersion) {
|
||||
return Promise.reject(new errors.LedgerVersionError(
|
||||
`ledgerVersion ${ledger_index} is greater than server\'s ` +
|
||||
`most recent validated ledger: ${this._ledgerVersion}`));
|
||||
`most recent validated ledger: ${this._ledgerVersion}`))
|
||||
}
|
||||
}
|
||||
return super.request(request, timeout);
|
||||
return super.request(request, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
class RippleAPI extends EventEmitter {
|
||||
constructor(options: APIOptions = {}) {
|
||||
common.validate.apiOptions(options);
|
||||
super();
|
||||
this._feeCushion = options.feeCushion || 1.2;
|
||||
const serverURL = options.server;
|
||||
common.validate.apiOptions(options)
|
||||
super()
|
||||
this._feeCushion = options.feeCushion || 1.2
|
||||
const serverURL = options.server
|
||||
if (serverURL !== undefined) {
|
||||
this.connection = new RestrictedConnection(serverURL, options);
|
||||
this.connection = new RestrictedConnection(serverURL, options)
|
||||
this.connection.on('ledgerClosed', message => {
|
||||
this.emit('ledger', server.formatLedgerClose(message));
|
||||
});
|
||||
this.emit('ledger', server.formatLedgerClose(message))
|
||||
})
|
||||
this.connection.on('error', (errorCode, errorMessage, data) => {
|
||||
this.emit('error', errorCode, errorMessage, data);
|
||||
});
|
||||
this.emit('error', errorCode, errorMessage, data)
|
||||
})
|
||||
this.connection.on('connected', () => {
|
||||
this.emit('connected');
|
||||
});
|
||||
this.emit('connected')
|
||||
})
|
||||
this.connection.on('disconnected', code => {
|
||||
this.emit('disconnected', code);
|
||||
});
|
||||
this.emit('disconnected', code)
|
||||
})
|
||||
} else {
|
||||
// use null object pattern to provide better error message if user
|
||||
// tries to call a method that requires a connection
|
||||
this.connection = new RestrictedConnection(null, options);
|
||||
this.connection = new RestrictedConnection(null, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,9 +133,12 @@ _.assign(RippleAPI.prototype, {
|
||||
prepareTrustline,
|
||||
prepareOrder,
|
||||
prepareOrderCancellation,
|
||||
prepareSuspendedPaymentCreation,
|
||||
prepareSuspendedPaymentExecution,
|
||||
prepareSuspendedPaymentCancellation,
|
||||
prepareEscrowCreation,
|
||||
prepareEscrowExecution,
|
||||
prepareEscrowCancellation,
|
||||
preparePaymentChannelCreate,
|
||||
preparePaymentChannelFund,
|
||||
preparePaymentChannelClaim,
|
||||
prepareSettings,
|
||||
sign,
|
||||
combine,
|
||||
@@ -138,7 +147,7 @@ _.assign(RippleAPI.prototype, {
|
||||
generateAddress,
|
||||
computeLedgerHash,
|
||||
errors
|
||||
});
|
||||
})
|
||||
|
||||
// these are exposed only for use by unit tests; they are not part of the API
|
||||
RippleAPI._PRIVATE = {
|
||||
@@ -146,8 +155,8 @@ RippleAPI._PRIVATE = {
|
||||
RangeSet: require('./common/rangeset').RangeSet,
|
||||
ledgerUtils: require('./ledger/utils'),
|
||||
schemaValidator: require('./common/schema-validator')
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RippleAPI
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const RippleAPI = require('./api').RippleAPI;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const RippleAPI = require('./api').RippleAPI
|
||||
|
||||
class RippleAPIBroadcast extends RippleAPI {
|
||||
constructor(servers, options) {
|
||||
super(options);
|
||||
this.ledgerVersion = 0;
|
||||
super(options)
|
||||
this.ledgerVersion = 0
|
||||
|
||||
const apis = servers.map(server => new RippleAPI(
|
||||
_.assign({}, options, {server})
|
||||
));
|
||||
))
|
||||
|
||||
// exposed for testing
|
||||
this._apis = apis;
|
||||
this._apis = apis
|
||||
|
||||
this.getMethodNames().forEach(name => {
|
||||
this[name] = function() { // eslint-disable-line no-loop-func
|
||||
return Promise.race(apis.map(api => api[name].apply(api, arguments)));
|
||||
};
|
||||
});
|
||||
return Promise.race(apis.map(api => api[name](...arguments)))
|
||||
}
|
||||
})
|
||||
|
||||
// connection methods must be overridden to apply to all api instances
|
||||
this.connect = function() {
|
||||
return Promise.all(apis.map(api => api.connect()));
|
||||
};
|
||||
return Promise.all(apis.map(api => api.connect()))
|
||||
}
|
||||
this.disconnect = function() {
|
||||
return Promise.all(apis.map(api => api.disconnect()));
|
||||
};
|
||||
return Promise.all(apis.map(api => api.disconnect()))
|
||||
}
|
||||
this.isConnected = function() {
|
||||
return _.every(apis.map(api => api.isConnected()));
|
||||
};
|
||||
return _.every(apis.map(api => api.isConnected()))
|
||||
}
|
||||
|
||||
// synchronous methods are all passed directly to the first api instance
|
||||
const defaultAPI = apis[0];
|
||||
const syncMethods = ['sign', 'generateAddress', 'computeLedgerHash'];
|
||||
const defaultAPI = apis[0]
|
||||
const syncMethods = ['sign', 'generateAddress', 'computeLedgerHash']
|
||||
syncMethods.forEach(name => {
|
||||
this[name] = defaultAPI[name].bind(defaultAPI);
|
||||
});
|
||||
this[name] = defaultAPI[name].bind(defaultAPI)
|
||||
})
|
||||
|
||||
apis.forEach(api => {
|
||||
api.on('ledger', this.onLedgerEvent.bind(this));
|
||||
api.on('ledger', this.onLedgerEvent.bind(this))
|
||||
api.on('error', (errorCode, errorMessage, data) =>
|
||||
this.emit('error', errorCode, errorMessage, data));
|
||||
});
|
||||
this.emit('error', errorCode, errorMessage, data))
|
||||
})
|
||||
}
|
||||
|
||||
onLedgerEvent(ledger) {
|
||||
if (ledger.ledgerVersion > this.ledgerVersion) {
|
||||
this.ledgerVersion = ledger.ledgerVersion;
|
||||
this.emit('ledger', ledger);
|
||||
this.ledgerVersion = ledger.ledgerVersion
|
||||
this.emit('ledger', ledger)
|
||||
}
|
||||
}
|
||||
|
||||
getMethodNames() {
|
||||
const methodNames = [];
|
||||
const methodNames = []
|
||||
for (const name in RippleAPI.prototype) {
|
||||
if (RippleAPI.prototype.hasOwnProperty(name)) {
|
||||
if (typeof RippleAPI.prototype[name] === 'function') {
|
||||
methodNames.push(name);
|
||||
methodNames.push(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodNames;
|
||||
return methodNames
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RippleAPIBroadcast
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
function setPrototypeOf(object, prototype) {
|
||||
// Object.setPrototypeOf not supported on Internet Explorer 9
|
||||
@@ -12,10 +12,10 @@ function getConstructorName(object) {
|
||||
// hack for internet explorer
|
||||
return process.browser ?
|
||||
object.constructor.toString().match(/^function\s+([^(]*)/)[1] :
|
||||
object.constructor.name;
|
||||
object.constructor.name
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getConstructorName,
|
||||
setPrototypeOf
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,125 +1,133 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
const _ = require('lodash');
|
||||
const {EventEmitter} = require('events');
|
||||
const WebSocket = require('ws');
|
||||
const parseURL = require('url').parse;
|
||||
const RangeSet = require('./rangeset').RangeSet;
|
||||
const _ = require('lodash')
|
||||
const {EventEmitter} = require('events')
|
||||
const WebSocket = require('ws')
|
||||
const parseURL = require('url').parse
|
||||
const RangeSet = require('./rangeset').RangeSet
|
||||
const {RippledError, DisconnectedError, NotConnectedError,
|
||||
TimeoutError, ResponseFormatError, ConnectionError,
|
||||
RippledNotInitializedError} = require('./errors');
|
||||
RippledNotInitializedError} = require('./errors')
|
||||
|
||||
function isStreamMessageType(type) {
|
||||
return type === 'ledgerClosed' ||
|
||||
type === 'transaction' ||
|
||||
type === 'path_find';
|
||||
type === 'path_find'
|
||||
}
|
||||
|
||||
class Connection extends EventEmitter {
|
||||
constructor(url, options = {}) {
|
||||
super();
|
||||
this.setMaxListeners(Infinity);
|
||||
this._url = url;
|
||||
this._trace = options.trace;
|
||||
super()
|
||||
this.setMaxListeners(Infinity)
|
||||
this._url = url
|
||||
this._trace = options.trace
|
||||
if (this._trace) {
|
||||
// for easier unit testing
|
||||
this._console = console;
|
||||
this._console = console
|
||||
}
|
||||
this._proxyURL = options.proxy;
|
||||
this._proxyAuthorization = options.proxyAuthorization;
|
||||
this._authorization = options.authorization;
|
||||
this._trustedCertificates = options.trustedCertificates;
|
||||
this._key = options.key;
|
||||
this._passphrase = options.passphrase;
|
||||
this._certificate = options.certificate;
|
||||
this._timeout = options.timeout || (20 * 1000);
|
||||
this._isReady = false;
|
||||
this._ws = null;
|
||||
this._ledgerVersion = null;
|
||||
this._availableLedgerVersions = new RangeSet();
|
||||
this._nextRequestID = 1;
|
||||
this._retry = 0;
|
||||
this._retryTimer = null;
|
||||
this._onOpenErrorBound = null;
|
||||
this._onUnexpectedCloseBound = null;
|
||||
this._proxyURL = options.proxy
|
||||
this._proxyAuthorization = options.proxyAuthorization
|
||||
this._authorization = options.authorization
|
||||
this._trustedCertificates = options.trustedCertificates
|
||||
this._key = options.key
|
||||
this._passphrase = options.passphrase
|
||||
this._certificate = options.certificate
|
||||
this._timeout = options.timeout || (20 * 1000)
|
||||
this._isReady = false
|
||||
this._ws = null
|
||||
this._ledgerVersion = null
|
||||
this._availableLedgerVersions = new RangeSet()
|
||||
this._nextRequestID = 1
|
||||
this._retry = 0
|
||||
this._retryTimer = null
|
||||
this._onOpenErrorBound = null
|
||||
this._onUnexpectedCloseBound = null
|
||||
this._fee_base = null
|
||||
this._fee_ref = null
|
||||
}
|
||||
|
||||
_updateLedgerVersions(data) {
|
||||
this._ledgerVersion = Number(data.ledger_index);
|
||||
this._ledgerVersion = Number(data.ledger_index)
|
||||
if (data.validated_ledgers) {
|
||||
this._availableLedgerVersions.reset();
|
||||
this._availableLedgerVersions.reset()
|
||||
this._availableLedgerVersions.parseAndAddRanges(
|
||||
data.validated_ledgers);
|
||||
data.validated_ledgers)
|
||||
} else {
|
||||
this._availableLedgerVersions.addValue(this._ledgerVersion);
|
||||
this._availableLedgerVersions.addValue(this._ledgerVersion)
|
||||
}
|
||||
}
|
||||
|
||||
_updateFees(data) {
|
||||
this._fee_base = Number(data.fee_base)
|
||||
this._fee_ref = Number(data.fee_ref)
|
||||
}
|
||||
|
||||
// return value is array of arguments to Connection.emit
|
||||
_parseMessage(message) {
|
||||
const data = JSON.parse(message);
|
||||
const data = JSON.parse(message)
|
||||
if (data.type === 'response') {
|
||||
if (!(Number.isInteger(data.id) && data.id >= 0)) {
|
||||
throw new ResponseFormatError('valid id not found in response');
|
||||
throw new ResponseFormatError('valid id not found in response')
|
||||
}
|
||||
return [data.id.toString(), data];
|
||||
return [data.id.toString(), data]
|
||||
} else if (isStreamMessageType(data.type)) {
|
||||
if (data.type === 'ledgerClosed') {
|
||||
this._updateLedgerVersions(data);
|
||||
this._updateLedgerVersions(data)
|
||||
this._updateFees(data)
|
||||
}
|
||||
return [data.type, data];
|
||||
return [data.type, data]
|
||||
} else if (data.type === undefined && data.error) {
|
||||
return ['error', data.error, data.error_message, data]; // e.g. slowDown
|
||||
return ['error', data.error, data.error_message, data] // e.g. slowDown
|
||||
}
|
||||
throw new ResponseFormatError('unrecognized message type: ' + data.type);
|
||||
throw new ResponseFormatError('unrecognized message type: ' + data.type)
|
||||
}
|
||||
|
||||
_onMessage(message) {
|
||||
let parameters;
|
||||
let parameters
|
||||
if (this._trace) {
|
||||
this._console.log(message);
|
||||
this._console.log(message)
|
||||
}
|
||||
try {
|
||||
parameters = this._parseMessage(message);
|
||||
parameters = this._parseMessage(message)
|
||||
} catch (error) {
|
||||
this.emit('error', 'badMessage', error.message, message);
|
||||
return;
|
||||
this.emit('error', 'badMessage', error.message, message)
|
||||
return
|
||||
}
|
||||
// we don't want this inside the try/catch or exceptions in listener
|
||||
// will be caught
|
||||
this.emit(...parameters);
|
||||
this.emit(...parameters)
|
||||
}
|
||||
|
||||
get _state() {
|
||||
return this._ws ? this._ws.readyState : WebSocket.CLOSED;
|
||||
return this._ws ? this._ws.readyState : WebSocket.CLOSED
|
||||
}
|
||||
|
||||
get _shouldBeConnected() {
|
||||
return this._ws !== null;
|
||||
return this._ws !== null
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return this._state === WebSocket.OPEN && this._isReady;
|
||||
return this._state === WebSocket.OPEN && this._isReady
|
||||
}
|
||||
|
||||
_onUnexpectedClose(beforeOpen, resolve, reject, code) {
|
||||
if (this._onOpenErrorBound) {
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
this._ws.removeListener('error', this._onOpenErrorBound)
|
||||
this._onOpenErrorBound = null
|
||||
}
|
||||
// just in case
|
||||
this._ws.removeAllListeners('open');
|
||||
this._ws = null;
|
||||
this._isReady = false;
|
||||
this._ws.removeAllListeners('open')
|
||||
this._ws = null
|
||||
this._isReady = false
|
||||
if (beforeOpen) {
|
||||
// connection was closed before it was properly opened, so we must return
|
||||
// error to connect's caller
|
||||
this.connect().then(resolve, reject);
|
||||
this.connect().then(resolve, reject)
|
||||
} else {
|
||||
// if first parameter ws lib sends close code,
|
||||
// but sometimes it forgots about it, so default to 1006 - CLOSE_ABNORMAL
|
||||
this.emit('disconnected', code || 1006);
|
||||
this._retryConnect();
|
||||
this.emit('disconnected', code || 1006)
|
||||
this._retryConnect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,91 +142,92 @@ class Connection extends EventEmitter {
|
||||
// Then, for 10 minutes: once every 10 seconds
|
||||
? (10 * 1000)
|
||||
// Then: once every 30 seconds
|
||||
: (30 * 1000);
|
||||
: (30 * 1000)
|
||||
}
|
||||
|
||||
_retryConnect() {
|
||||
this._retry += 1;
|
||||
const retryTimeout = this._calculateTimeout(this._retry);
|
||||
this._retry += 1
|
||||
const retryTimeout = this._calculateTimeout(this._retry)
|
||||
this._retryTimer = setTimeout(() => {
|
||||
this.emit('reconnecting', this._retry);
|
||||
this.connect().catch(this._retryConnect.bind(this));
|
||||
}, retryTimeout);
|
||||
this.emit('reconnecting', this._retry)
|
||||
this.connect().catch(this._retryConnect.bind(this))
|
||||
}, retryTimeout)
|
||||
}
|
||||
|
||||
_clearReconnectTimer() {
|
||||
clearTimeout(this._retryTimer);
|
||||
this._retryTimer = null;
|
||||
clearTimeout(this._retryTimer)
|
||||
this._retryTimer = null
|
||||
}
|
||||
|
||||
_onOpen() {
|
||||
if (!this._ws) {
|
||||
return Promise.reject(new DisconnectedError());
|
||||
return Promise.reject(new DisconnectedError())
|
||||
}
|
||||
if (this._onOpenErrorBound) {
|
||||
this._ws.removeListener('error', this._onOpenErrorBound);
|
||||
this._onOpenErrorBound = null;
|
||||
this._ws.removeListener('error', this._onOpenErrorBound)
|
||||
this._onOpenErrorBound = null
|
||||
}
|
||||
|
||||
const request = {
|
||||
command: 'subscribe',
|
||||
streams: ['ledger']
|
||||
};
|
||||
}
|
||||
return this.request(request).then(data => {
|
||||
if (_.isEmpty(data) || !data.ledger_index) {
|
||||
// rippled instance doesn't have validated ledgers
|
||||
return this._disconnect(false).then(() => {
|
||||
throw new RippledNotInitializedError('Rippled not initialized');
|
||||
});
|
||||
throw new RippledNotInitializedError('Rippled not initialized')
|
||||
})
|
||||
}
|
||||
|
||||
this._updateLedgerVersions(data);
|
||||
this._rebindOnUnxpectedClose();
|
||||
this._updateLedgerVersions(data)
|
||||
this._updateFees(data)
|
||||
this._rebindOnUnxpectedClose()
|
||||
|
||||
this._retry = 0;
|
||||
this._retry = 0
|
||||
this._ws.on('error', error => {
|
||||
if (process.browser && error && error.type === 'error') {
|
||||
// we are in browser, ignore error - `close` event will be fired
|
||||
// after error
|
||||
return;
|
||||
return
|
||||
}
|
||||
this.emit('error', 'websocket', error.message, error);
|
||||
});
|
||||
this.emit('error', 'websocket', error.message, error)
|
||||
})
|
||||
|
||||
this._isReady = true;
|
||||
this.emit('connected');
|
||||
this._isReady = true
|
||||
this.emit('connected')
|
||||
|
||||
return undefined;
|
||||
});
|
||||
return undefined
|
||||
})
|
||||
}
|
||||
|
||||
_rebindOnUnxpectedClose() {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound)
|
||||
}
|
||||
this._onUnexpectedCloseBound =
|
||||
this._onUnexpectedClose.bind(this, false, null, null);
|
||||
this._ws.once('close', this._onUnexpectedCloseBound);
|
||||
this._onUnexpectedClose.bind(this, false, null, null)
|
||||
this._ws.once('close', this._onUnexpectedCloseBound)
|
||||
}
|
||||
|
||||
_unbindOnUnxpectedClose() {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound)
|
||||
}
|
||||
this._onUnexpectedCloseBound = null;
|
||||
this._onUnexpectedCloseBound = null
|
||||
}
|
||||
|
||||
_onOpenError(reject, error) {
|
||||
this._onOpenErrorBound = null;
|
||||
this._unbindOnUnxpectedClose();
|
||||
reject(new NotConnectedError(error && error.message));
|
||||
this._onOpenErrorBound = null
|
||||
this._unbindOnUnxpectedClose()
|
||||
reject(new NotConnectedError(error && error.message))
|
||||
}
|
||||
|
||||
_createWebSocket() {
|
||||
const options = {};
|
||||
const options = {}
|
||||
if (this._proxyURL !== undefined) {
|
||||
const parsedURL = parseURL(this._url);
|
||||
const parsedProxyURL = parseURL(this._proxyURL);
|
||||
const parsedURL = parseURL(this._url)
|
||||
const parsedProxyURL = parseURL(this._proxyURL)
|
||||
const proxyOverrides = _.omit({
|
||||
secureEndpoint: (parsedURL.protocol === 'wss:'),
|
||||
secureProxy: (parsedProxyURL.protocol === 'https:'),
|
||||
@@ -227,49 +236,49 @@ class Connection extends EventEmitter {
|
||||
key: this._key,
|
||||
passphrase: this._passphrase,
|
||||
cert: this._certificate
|
||||
}, _.isUndefined);
|
||||
const proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides);
|
||||
let HttpsProxyAgent;
|
||||
}, _.isUndefined)
|
||||
const proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides)
|
||||
let HttpsProxyAgent
|
||||
try {
|
||||
HttpsProxyAgent = require('https-proxy-agent');
|
||||
HttpsProxyAgent = require('https-proxy-agent')
|
||||
} catch (error) {
|
||||
throw new Error('"proxy" option is not supported in the browser');
|
||||
throw new Error('"proxy" option is not supported in the browser')
|
||||
}
|
||||
options.agent = new HttpsProxyAgent(proxyOptions);
|
||||
options.agent = new HttpsProxyAgent(proxyOptions)
|
||||
}
|
||||
if (this._authorization !== undefined) {
|
||||
const base64 = new Buffer(this._authorization).toString('base64');
|
||||
options.headers = {Authorization: `Basic ${base64}`};
|
||||
const base64 = new Buffer(this._authorization).toString('base64')
|
||||
options.headers = {Authorization: `Basic ${base64}`}
|
||||
}
|
||||
const optionsOverrides = _.omit({
|
||||
ca: this._trustedCertificates,
|
||||
key: this._key,
|
||||
passphrase: this._passphrase,
|
||||
cert: this._certificate
|
||||
}, _.isUndefined);
|
||||
const websocketOptions = _.assign({}, options, optionsOverrides);
|
||||
const websocket = new WebSocket(this._url, null, websocketOptions);
|
||||
}, _.isUndefined)
|
||||
const websocketOptions = _.assign({}, options, optionsOverrides)
|
||||
const websocket = new WebSocket(this._url, null, websocketOptions)
|
||||
// we will have a listener for each outstanding request,
|
||||
// so we have to raise the limit (the default is 10)
|
||||
if (typeof websocket.setMaxListeners === 'function') {
|
||||
websocket.setMaxListeners(Infinity);
|
||||
websocket.setMaxListeners(Infinity)
|
||||
}
|
||||
return websocket;
|
||||
return websocket
|
||||
}
|
||||
|
||||
connect() {
|
||||
this._clearReconnectTimer();
|
||||
this._clearReconnectTimer()
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._url) {
|
||||
reject(new ConnectionError(
|
||||
'Cannot connect because no server was specified'));
|
||||
'Cannot connect because no server was specified'))
|
||||
}
|
||||
if (this._state === WebSocket.OPEN) {
|
||||
resolve();
|
||||
resolve()
|
||||
} else if (this._state === WebSocket.CONNECTING) {
|
||||
this._ws.once('open', resolve);
|
||||
this._ws.once('open', resolve)
|
||||
} else {
|
||||
this._ws = this._createWebSocket();
|
||||
this._ws = this._createWebSocket()
|
||||
// when an error causes the connection to close, the close event
|
||||
// should still be emitted; the "ws" documentation says: "The close
|
||||
// event is also emitted when then underlying net.Socket closes the
|
||||
@@ -277,156 +286,164 @@ class Connection extends EventEmitter {
|
||||
// In case if there is connection error (say, server is not responding)
|
||||
// we must return this error to connection's caller. After successful
|
||||
// opening, we will forward all errors to main api object.
|
||||
this._onOpenErrorBound = this._onOpenError.bind(this, reject);
|
||||
this._ws.once('error', this._onOpenErrorBound);
|
||||
this._ws.on('message', this._onMessage.bind(this));
|
||||
this._onOpenErrorBound = this._onOpenError.bind(this, reject)
|
||||
this._ws.once('error', this._onOpenErrorBound)
|
||||
this._ws.on('message', this._onMessage.bind(this))
|
||||
// in browser close event can came before open event, so we must
|
||||
// resolve connect's promise after reconnect in that case.
|
||||
// after open event we will rebound _onUnexpectedCloseBound
|
||||
// without resolve and reject functions
|
||||
this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(this, true,
|
||||
resolve, reject);
|
||||
this._ws.once('close', this._onUnexpectedCloseBound);
|
||||
this._ws.once('open', () => this._onOpen().then(resolve, reject));
|
||||
resolve, reject)
|
||||
this._ws.once('close', this._onUnexpectedCloseBound)
|
||||
this._ws.once('open', () => this._onOpen().then(resolve, reject))
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
return this._disconnect(true);
|
||||
return this._disconnect(true)
|
||||
}
|
||||
|
||||
_disconnect(calledByUser) {
|
||||
if (calledByUser) {
|
||||
this._clearReconnectTimer();
|
||||
this._retry = 0;
|
||||
this._clearReconnectTimer()
|
||||
this._retry = 0
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
if (this._state === WebSocket.CLOSED) {
|
||||
resolve();
|
||||
resolve()
|
||||
} else if (this._state === WebSocket.CLOSING) {
|
||||
this._ws.once('close', resolve);
|
||||
this._ws.once('close', resolve)
|
||||
} else {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound);
|
||||
this._onUnexpectedCloseBound = null;
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound)
|
||||
this._onUnexpectedCloseBound = null
|
||||
}
|
||||
this._ws.once('close', code => {
|
||||
this._ws = null;
|
||||
this._isReady = false;
|
||||
this._ws = null
|
||||
this._isReady = false
|
||||
if (calledByUser) {
|
||||
this.emit('disconnected', code || 1000); // 1000 - CLOSE_NORMAL
|
||||
this.emit('disconnected', code || 1000) // 1000 - CLOSE_NORMAL
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
this._ws.close();
|
||||
resolve()
|
||||
})
|
||||
this._ws.close()
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
reconnect() {
|
||||
return this.disconnect().then(() => this.connect());
|
||||
return this.disconnect().then(() => this.connect())
|
||||
}
|
||||
|
||||
_whenReady(promise) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._shouldBeConnected) {
|
||||
reject(new NotConnectedError());
|
||||
reject(new NotConnectedError())
|
||||
} else if (this._state === WebSocket.OPEN && this._isReady) {
|
||||
promise.then(resolve, reject);
|
||||
promise.then(resolve, reject)
|
||||
} else {
|
||||
this.once('connected', () => promise.then(resolve, reject));
|
||||
this.once('connected', () => promise.then(resolve, reject))
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
getLedgerVersion() {
|
||||
return this._whenReady(Promise.resolve(this._ledgerVersion));
|
||||
return this._whenReady(Promise.resolve(this._ledgerVersion))
|
||||
}
|
||||
|
||||
hasLedgerVersions(lowLedgerVersion, highLedgerVersion) {
|
||||
return this._whenReady(Promise.resolve(
|
||||
this._availableLedgerVersions.containsRange(
|
||||
lowLedgerVersion, highLedgerVersion || this._ledgerVersion)));
|
||||
lowLedgerVersion, highLedgerVersion || this._ledgerVersion)))
|
||||
}
|
||||
|
||||
hasLedgerVersion(ledgerVersion) {
|
||||
return this.hasLedgerVersions(ledgerVersion, ledgerVersion);
|
||||
return this.hasLedgerVersions(ledgerVersion, ledgerVersion)
|
||||
}
|
||||
|
||||
getFeeBase() {
|
||||
return this._whenReady(Promise.resolve(Number(this._fee_base)))
|
||||
}
|
||||
|
||||
getFeeRef() {
|
||||
return this._whenReady(Promise.resolve(Number(this._fee_ref)))
|
||||
}
|
||||
|
||||
_send(message) {
|
||||
if (this._trace) {
|
||||
this._console.log(message);
|
||||
this._console.log(message)
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
this._ws.send(message, undefined, (error, result) => {
|
||||
if (error) {
|
||||
reject(new DisconnectedError(error.message));
|
||||
reject(new DisconnectedError(error.message))
|
||||
} else {
|
||||
resolve(result);
|
||||
resolve(result)
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
request(request, timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this._shouldBeConnected) {
|
||||
reject(new NotConnectedError());
|
||||
reject(new NotConnectedError())
|
||||
}
|
||||
|
||||
let timer = null;
|
||||
const self = this;
|
||||
const id = this._nextRequestID;
|
||||
this._nextRequestID += 1;
|
||||
const eventName = id.toString();
|
||||
let timer = null
|
||||
const self = this
|
||||
const id = this._nextRequestID
|
||||
this._nextRequestID += 1
|
||||
const eventName = id.toString()
|
||||
|
||||
function onDisconnect() {
|
||||
clearTimeout(timer);
|
||||
self.removeAllListeners(eventName);
|
||||
reject(new DisconnectedError());
|
||||
clearTimeout(timer)
|
||||
self.removeAllListeners(eventName)
|
||||
reject(new DisconnectedError())
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
clearTimeout(timer);
|
||||
self.removeAllListeners(eventName);
|
||||
clearTimeout(timer)
|
||||
self.removeAllListeners(eventName)
|
||||
if (self._ws !== null) {
|
||||
self._ws.removeListener('close', onDisconnect);
|
||||
self._ws.removeListener('close', onDisconnect)
|
||||
}
|
||||
}
|
||||
|
||||
function _resolve(response) {
|
||||
cleanup();
|
||||
resolve(response);
|
||||
cleanup()
|
||||
resolve(response)
|
||||
}
|
||||
|
||||
function _reject(error) {
|
||||
cleanup();
|
||||
reject(error);
|
||||
cleanup()
|
||||
reject(error)
|
||||
}
|
||||
|
||||
this.once(eventName, response => {
|
||||
if (response.status === 'error') {
|
||||
_reject(new RippledError(response.error));
|
||||
_reject(new RippledError(response.error))
|
||||
} else if (response.status === 'success') {
|
||||
_resolve(response.result);
|
||||
_resolve(response.result)
|
||||
} else {
|
||||
_reject(new ResponseFormatError(
|
||||
'unrecognized status: ' + response.status));
|
||||
'unrecognized status: ' + response.status))
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
this._ws.once('close', onDisconnect);
|
||||
this._ws.once('close', onDisconnect)
|
||||
|
||||
// JSON.stringify automatically removes keys with value of 'undefined'
|
||||
const message = JSON.stringify(Object.assign({}, request, {id}));
|
||||
const message = JSON.stringify(Object.assign({}, request, {id}))
|
||||
|
||||
this._whenReady(this._send(message)).then(() => {
|
||||
const delay = timeout || this._timeout;
|
||||
timer = setTimeout(() => _reject(new TimeoutError()), delay);
|
||||
}).catch(_reject);
|
||||
});
|
||||
const delay = timeout || this._timeout
|
||||
timer = setTimeout(() => _reject(new TimeoutError()), delay)
|
||||
}).catch(_reject)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Connection;
|
||||
module.exports = Connection
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
const flagIndices = require('./txflags').txFlagIndices.AccountSet;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const flagIndices = require('./txflags').txFlagIndices.AccountSet
|
||||
|
||||
const accountRootFlags = {
|
||||
PasswordSpent: 0x00010000, // password set fee is spent
|
||||
@@ -10,7 +10,7 @@ const accountRootFlags = {
|
||||
NoFreeze: 0x00200000, // permanently disallowed freezing trustlines
|
||||
GlobalFreeze: 0x00400000, // trustlines globally frozen
|
||||
DefaultRipple: 0x00800000
|
||||
};
|
||||
}
|
||||
|
||||
const AccountFlags = {
|
||||
passwordSpent: accountRootFlags.PasswordSpent,
|
||||
@@ -21,7 +21,7 @@ const AccountFlags = {
|
||||
noFreeze: accountRootFlags.NoFreeze,
|
||||
globalFreeze: accountRootFlags.GlobalFreeze,
|
||||
defaultRipple: accountRootFlags.DefaultRipple
|
||||
};
|
||||
}
|
||||
|
||||
const AccountFlagIndices = {
|
||||
requireDestinationTag: flagIndices.asfRequireDest,
|
||||
@@ -32,7 +32,7 @@ const AccountFlagIndices = {
|
||||
noFreeze: flagIndices.asfNoFreeze,
|
||||
globalFreeze: flagIndices.asfGlobalFreeze,
|
||||
defaultRipple: flagIndices.asfDefaultRipple
|
||||
};
|
||||
}
|
||||
|
||||
const AccountFields = {
|
||||
EmailHash: {name: 'emailHash', encoding: 'hex',
|
||||
@@ -40,10 +40,10 @@ const AccountFields = {
|
||||
MessageKey: {name: 'messageKey'},
|
||||
Domain: {name: 'domain', encoding: 'hex'},
|
||||
TransferRate: {name: 'transferRate', defaults: 0, shift: 9}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AccountFields,
|
||||
AccountFlagIndices,
|
||||
AccountFlags
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
const util = require('util');
|
||||
const browserHacks = require('./browser-hacks');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const util = require('util')
|
||||
const browserHacks = require('./browser-hacks')
|
||||
|
||||
// this is needed because extending builtins doesn't work in babel 6.x
|
||||
function extendableBuiltin(cls) {
|
||||
function ExtendableBuiltin() {
|
||||
cls.apply(this, arguments);
|
||||
cls.apply(this, arguments)
|
||||
}
|
||||
ExtendableBuiltin.prototype = Object.create(cls.prototype);
|
||||
browserHacks.setPrototypeOf(ExtendableBuiltin, cls);
|
||||
return ExtendableBuiltin;
|
||||
ExtendableBuiltin.prototype = Object.create(cls.prototype)
|
||||
browserHacks.setPrototypeOf(ExtendableBuiltin, cls)
|
||||
return ExtendableBuiltin
|
||||
}
|
||||
|
||||
class RippleError extends extendableBuiltin(Error) {
|
||||
constructor(message, data) {
|
||||
super(message);
|
||||
super(message)
|
||||
|
||||
this.name = browserHacks.getConstructorName(this);
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
this.name = browserHacks.getConstructorName(this)
|
||||
this.message = message
|
||||
this.data = data
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor.name);
|
||||
Error.captureStackTrace(this, this.constructor.name)
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
let result = '[' + this.name + '(' + this.message;
|
||||
let result = '[' + this.name + '(' + this.message
|
||||
if (this.data) {
|
||||
result += ', ' + util.inspect(this.data);
|
||||
result += ', ' + util.inspect(this.data)
|
||||
}
|
||||
result += ')]';
|
||||
return result;
|
||||
result += ')]'
|
||||
return result
|
||||
}
|
||||
|
||||
/* console.log in node uses util.inspect on object, and util.inspect allows
|
||||
us to cutomize its output:
|
||||
https://nodejs.org/api/util.html#util_custom_inspect_function_on_objects */
|
||||
inspect() {
|
||||
return this.toString();
|
||||
return this.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,20 +63,20 @@ class ValidationError extends RippleError {}
|
||||
|
||||
class NotFoundError extends RippleError {
|
||||
constructor(message) {
|
||||
super(message || 'Not found');
|
||||
super(message || 'Not found')
|
||||
}
|
||||
}
|
||||
|
||||
class MissingLedgerHistoryError extends RippleError {
|
||||
constructor(message) {
|
||||
super(message || 'Server is missing ledger history in the specified range');
|
||||
super(message || 'Server is missing ledger history in the specified range')
|
||||
}
|
||||
}
|
||||
|
||||
class PendingLedgerVersionError extends RippleError {
|
||||
constructor(message) {
|
||||
super(message || 'maxLedgerVersion is greater than server\'s'
|
||||
+ ' most recent validated ledger');
|
||||
+ ' most recent validated ledger')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,4 +95,4 @@ module.exports = {
|
||||
PendingLedgerVersionError,
|
||||
MissingLedgerHistoryError,
|
||||
LedgerVersionError
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('./utils')
|
||||
|
||||
module.exports = {
|
||||
Connection: require('./connection'),
|
||||
@@ -19,4 +19,4 @@ module.exports = {
|
||||
iso8601ToRippleTime: utils.iso8601ToRippleTime,
|
||||
rippleTimeToISO8601: utils.rippleTimeToISO8601,
|
||||
isValidSecret: utils.isValidSecret
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const ranges = Symbol();
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const assert = require('assert')
|
||||
const ranges = Symbol()
|
||||
|
||||
function mergeIntervals(intervals: Array<[number, number]>) {
|
||||
const stack = [[-Infinity, -Infinity]];
|
||||
const stack = [[-Infinity, -Infinity]]
|
||||
_.forEach(_.sortBy(intervals, x => x[0]), interval => {
|
||||
const lastInterval = stack.pop();
|
||||
const lastInterval = stack.pop()
|
||||
if (interval[0] <= lastInterval[1] + 1) {
|
||||
stack.push([lastInterval[0], Math.max(interval[1], lastInterval[1])]);
|
||||
stack.push([lastInterval[0], Math.max(interval[1], lastInterval[1])])
|
||||
} else {
|
||||
stack.push(lastInterval);
|
||||
stack.push(interval);
|
||||
stack.push(lastInterval)
|
||||
stack.push(interval)
|
||||
}
|
||||
});
|
||||
return stack.slice(1);
|
||||
})
|
||||
return stack.slice(1)
|
||||
}
|
||||
|
||||
class RangeSet {
|
||||
constructor() {
|
||||
this.reset();
|
||||
this.reset()
|
||||
}
|
||||
|
||||
reset() {
|
||||
this[ranges] = [];
|
||||
this[ranges] = []
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return this[ranges].map(range =>
|
||||
range[0].toString() + '-' + range[1].toString()).join(',');
|
||||
range[0].toString() + '-' + range[1].toString()).join(',')
|
||||
}
|
||||
|
||||
addRange(start: number, end: number) {
|
||||
assert(start <= end, 'invalid range');
|
||||
this[ranges] = mergeIntervals(this[ranges].concat([[start, end]]));
|
||||
assert(start <= end, 'invalid range')
|
||||
this[ranges] = mergeIntervals(this[ranges].concat([[start, end]]))
|
||||
}
|
||||
|
||||
addValue(value: number) {
|
||||
this.addRange(value, value);
|
||||
this.addRange(value, value)
|
||||
}
|
||||
|
||||
parseAndAddRanges(rangesString: string) {
|
||||
const rangeStrings = rangesString.split(',');
|
||||
const rangeStrings = rangesString.split(',')
|
||||
_.forEach(rangeStrings, rangeString => {
|
||||
const range = rangeString.split('-').map(Number);
|
||||
this.addRange(range[0], range.length === 1 ? range[0] : range[1]);
|
||||
});
|
||||
const range = rangeString.split('-').map(Number)
|
||||
this.addRange(range[0], range.length === 1 ? range[0] : range[1])
|
||||
})
|
||||
}
|
||||
|
||||
containsRange(start: number, end: number) {
|
||||
return _.some(this[ranges], range => range[0] <= start && range[1] >= end);
|
||||
return _.some(this[ranges], range => range[0] <= start && range[1] >= end)
|
||||
}
|
||||
|
||||
containsValue(value: number) {
|
||||
return this.containsRange(value, value);
|
||||
return this.containsRange(value, value)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.RangeSet = RangeSet;
|
||||
module.exports.RangeSet = RangeSet
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// flow is disabled for this file until support for requiring json is added:
|
||||
// https://github.com/facebook/flow/issues/167
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const Ajv = require('ajv');
|
||||
const ValidationError = require('./errors').ValidationError;
|
||||
const {isValidAddress} = require('ripple-address-codec');
|
||||
const {isValidSecret} = require('./utils');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const assert = require('assert')
|
||||
const Ajv = require('ajv')
|
||||
const ValidationError = require('./errors').ValidationError
|
||||
const {isValidAddress} = require('ripple-address-codec')
|
||||
const {isValidSecret} = require('./utils')
|
||||
|
||||
function loadSchemas() {
|
||||
// listed explicitly for webpack (instead of scanning schemas directory)
|
||||
@@ -16,11 +16,13 @@ function loadSchemas() {
|
||||
require('./schemas/objects/hash128.json'),
|
||||
require('./schemas/objects/hash256.json'),
|
||||
require('./schemas/objects/sequence.json'),
|
||||
require('./schemas/objects/signature.json'),
|
||||
require('./schemas/objects/issue.json'),
|
||||
require('./schemas/objects/ledgerversion.json'),
|
||||
require('./schemas/objects/max-adjustment.json'),
|
||||
require('./schemas/objects/memo.json'),
|
||||
require('./schemas/objects/memos.json'),
|
||||
require('./schemas/objects/public-key.json'),
|
||||
require('./schemas/objects/uint32.json'),
|
||||
require('./schemas/objects/value.json'),
|
||||
require('./schemas/objects/source-adjustment.json'),
|
||||
@@ -46,17 +48,20 @@ function loadSchemas() {
|
||||
require('./schemas/objects/settings.json'),
|
||||
require('./schemas/specifications/settings.json'),
|
||||
require('./schemas/specifications/payment.json'),
|
||||
require('./schemas/specifications/suspended-payment-cancellation.json'),
|
||||
require('./schemas/specifications/escrow-cancellation.json'),
|
||||
require('./schemas/specifications/order-cancellation.json'),
|
||||
require('./schemas/specifications/order.json'),
|
||||
require('./schemas/specifications/suspended-payment-execution.json'),
|
||||
require('./schemas/specifications/suspended-payment-creation.json'),
|
||||
require('./schemas/specifications/escrow-execution.json'),
|
||||
require('./schemas/specifications/escrow-creation.json'),
|
||||
require('./schemas/specifications/payment-channel-create.json'),
|
||||
require('./schemas/specifications/payment-channel-fund.json'),
|
||||
require('./schemas/specifications/payment-channel-claim.json'),
|
||||
require('./schemas/specifications/trustline.json'),
|
||||
require('./schemas/output/sign.json'),
|
||||
require('./schemas/output/submit.json'),
|
||||
require('./schemas/output/get-account-info.json'),
|
||||
require('./schemas/output/get-balances.json'),
|
||||
require('./schemas/output/get-balance-sheet'),
|
||||
require('./schemas/output/get-balance-sheet.json'),
|
||||
require('./schemas/output/get-ledger.json'),
|
||||
require('./schemas/output/get-orderbook.json'),
|
||||
require('./schemas/output/get-orders.json'),
|
||||
@@ -88,35 +93,38 @@ function loadSchemas() {
|
||||
require('./schemas/input/prepare-trustline.json'),
|
||||
require('./schemas/input/prepare-order-cancellation.json'),
|
||||
require('./schemas/input/prepare-settings.json'),
|
||||
require('./schemas/input/prepare-suspended-payment-creation.json'),
|
||||
require('./schemas/input/prepare-suspended-payment-cancellation.json'),
|
||||
require('./schemas/input/prepare-suspended-payment-execution.json'),
|
||||
require('./schemas/input/compute-ledger-hash'),
|
||||
require('./schemas/input/prepare-escrow-creation.json'),
|
||||
require('./schemas/input/prepare-escrow-cancellation.json'),
|
||||
require('./schemas/input/prepare-escrow-execution.json'),
|
||||
require('./schemas/input/prepare-payment-channel-create.json'),
|
||||
require('./schemas/input/prepare-payment-channel-fund.json'),
|
||||
require('./schemas/input/prepare-payment-channel-claim.json'),
|
||||
require('./schemas/input/compute-ledger-hash.json'),
|
||||
require('./schemas/input/sign.json'),
|
||||
require('./schemas/input/submit.json'),
|
||||
require('./schemas/input/generate-address.json'),
|
||||
require('./schemas/input/combine.json')
|
||||
];
|
||||
const titles = _.map(schemas, schema => schema.title);
|
||||
const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1));
|
||||
assert(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates);
|
||||
const ajv = new Ajv();
|
||||
_.forEach(schemas, schema => ajv.addSchema(schema, schema.title));
|
||||
ajv.addFormat('address', isValidAddress);
|
||||
ajv.addFormat('secret', isValidSecret);
|
||||
return ajv;
|
||||
]
|
||||
const titles = _.map(schemas, schema => schema.title)
|
||||
const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1))
|
||||
assert(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates)
|
||||
const ajv = new Ajv()
|
||||
_.forEach(schemas, schema => ajv.addSchema(schema, schema.title))
|
||||
ajv.addFormat('address', isValidAddress)
|
||||
ajv.addFormat('secret', isValidSecret)
|
||||
return ajv
|
||||
}
|
||||
|
||||
const ajv = loadSchemas();
|
||||
const ajv = loadSchemas()
|
||||
|
||||
function schemaValidate(schemaName: string, object: any): void {
|
||||
const isValid = ajv.validate(schemaName, object);
|
||||
const isValid = ajv.validate(schemaName, object)
|
||||
if (!isValid) {
|
||||
throw new ValidationError(ajv.errorsText());
|
||||
throw new ValidationError(ajv.errorsText())
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
schemaValidate,
|
||||
isValidSecret
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "prepareSuspendedPaymentCreationParameters",
|
||||
"title": "prepareEscrowCancellationParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account that is creating the transaction."
|
||||
},
|
||||
"suspendedPaymentCreation": {
|
||||
"$ref": "suspendedPaymentCreation",
|
||||
"description": "The specification of the suspended payment creation to prepare."
|
||||
"escrowCancellation": {
|
||||
"$ref": "escrowCancellation",
|
||||
"description": "The specification of the escrow cancellation to prepare."
|
||||
},
|
||||
"instructions": {"$ref": "instructions"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["address", "suspendedPaymentCreation"]
|
||||
"required": ["address", "escrowCancellation"]
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "prepareSuspendedPaymentExecutionParameters",
|
||||
"title": "prepareEscrowCreationParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account that is creating the transaction."
|
||||
},
|
||||
"suspendedPaymentExecution": {
|
||||
"$ref": "suspendedPaymentExecution",
|
||||
"description": "The specification of the suspended payment execution to prepare."
|
||||
"escrowCreation": {
|
||||
"$ref": "escrowCreation",
|
||||
"description": "The specification of the escrow creation to prepare."
|
||||
},
|
||||
"instructions": {"$ref": "instructions"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["address", "suspendedPaymentExecution"]
|
||||
"required": ["address", "escrowCreation"]
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "prepareSuspendedPaymentCancellationParameters",
|
||||
"title": "prepareEscrowExecutionParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account that is creating the transaction."
|
||||
},
|
||||
"suspendedPaymentCancellation": {
|
||||
"$ref": "suspendedPaymentCancellation",
|
||||
"description": "The specification of the suspended payment cancellation to prepare."
|
||||
"escrowExecution": {
|
||||
"$ref": "escrowExecution",
|
||||
"description": "The specification of the escrow execution to prepare."
|
||||
},
|
||||
"instructions": {"$ref": "instructions"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["address", "suspendedPaymentCancellation"]
|
||||
"required": ["address", "escrowExecution"]
|
||||
}
|
||||
18
src/common/schemas/input/prepare-payment-channel-claim.json
Normal file
18
src/common/schemas/input/prepare-payment-channel-claim.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "preparePaymentChannelClaimParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account that is creating the transaction."
|
||||
},
|
||||
"paymentChannelClaim": {
|
||||
"$ref": "paymentChannelClaim",
|
||||
"description": "Details of the channel and claim."
|
||||
},
|
||||
"instructions": {"$ref": "instructions"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["address", "paymentChannelClaim"]
|
||||
}
|
||||
18
src/common/schemas/input/prepare-payment-channel-create.json
Normal file
18
src/common/schemas/input/prepare-payment-channel-create.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "preparePaymentChannelCreateParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account that is creating the transaction."
|
||||
},
|
||||
"paymentChannelCreate": {
|
||||
"$ref": "paymentChannelCreate",
|
||||
"description": "The specification of the payment channel to create."
|
||||
},
|
||||
"instructions": {"$ref": "instructions"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["address", "paymentChannelCreate"]
|
||||
}
|
||||
18
src/common/schemas/input/prepare-payment-channel-fund.json
Normal file
18
src/common/schemas/input/prepare-payment-channel-fund.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "preparePaymentChannelFundParameters",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the account that is creating the transaction."
|
||||
},
|
||||
"paymentChannelFund": {
|
||||
"$ref": "paymentChannelFund",
|
||||
"description": "The channel to fund, and the details of how to fund it."
|
||||
},
|
||||
"instructions": {"$ref": "instructions"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["address", "paymentChannelFund"]
|
||||
}
|
||||
7
src/common/schemas/objects/public-key.json
Normal file
7
src/common/schemas/objects/public-key.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "publicKey",
|
||||
"description": "The hexadecimal representation of a secp256k1 or Ed25519 public key.",
|
||||
"type": "string",
|
||||
"pattern": "^[A-F0-9]+$"
|
||||
}
|
||||
7
src/common/schemas/objects/signature.json
Normal file
7
src/common/schemas/objects/signature.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "signature",
|
||||
"description": "The hexadecimal representation of a signature.",
|
||||
"type": "string",
|
||||
"pattern": "^[A-F0-9]+$"
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
"description": "The type of the transaction.",
|
||||
"type": "string",
|
||||
"enum": ["payment", "order", "orderCancellation", "trustline", "settings",
|
||||
"suspendedPaymentCreation", "suspendedPaymentCancellation",
|
||||
"suspendedPaymentExecution"]
|
||||
"escrowCreation", "escrowCancellation",
|
||||
"escrowExecution", "paymentChannelCreate",
|
||||
"paymentChannelFund", "paymentChannelClaim"]
|
||||
}
|
||||
|
||||
@@ -59,20 +59,38 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {"enum": ["suspendedPaymentCreation"]},
|
||||
"specification": {"$ref": "suspendedPaymentCreation"}
|
||||
"type": {"enum": ["escrowCreation"]},
|
||||
"specification": {"$ref": "escrowCreation"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {"enum": ["suspendedPaymentCancellation"]},
|
||||
"specification": {"$ref": "suspendedPaymentCancellation"}
|
||||
"type": {"enum": ["escrowCancellation"]},
|
||||
"specification": {"$ref": "escrowCancellation"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {"enum": ["suspendedPaymentExecution"]},
|
||||
"specification": {"$ref": "suspendedPaymentExecution"}
|
||||
"type": {"enum": ["escrowExecution"]},
|
||||
"specification": {"$ref": "escrowExecution"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {"enum": ["paymentChannelCreate"]},
|
||||
"specification": {"$ref": "paymentChannelCreate"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {"enum": ["paymentChannelFund"]},
|
||||
"specification": {"$ref": "paymentChannelFund"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {"enum": ["paymentChannelClaim"]},
|
||||
"specification": {"$ref": "paymentChannelClaim"}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
19
src/common/schemas/specifications/escrow-cancellation.json
Normal file
19
src/common/schemas/specifications/escrow-cancellation.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "escrowCancellation",
|
||||
"link": "escrow-cancellation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memos": {"$ref": "memos"},
|
||||
"owner": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the owner of the escrow to cancel."
|
||||
},
|
||||
"escrowSequence": {
|
||||
"$ref": "sequence",
|
||||
"description": "The [account sequence number](#account-sequence-number) of the [Escrow Creation](#escrow-creation) transaction for the escrow to cancel."
|
||||
}
|
||||
},
|
||||
"required": ["owner", "escrowSequence"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
42
src/common/schemas/specifications/escrow-creation.json
Normal file
42
src/common/schemas/specifications/escrow-creation.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "escrowCreation",
|
||||
"link": "escrow-creation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amount": {
|
||||
"$ref": "value",
|
||||
"description": "Amount of XRP for sender to escrow."
|
||||
},
|
||||
"destination": {
|
||||
"$ref": "address",
|
||||
"description": "Address to receive escrowed XRP."
|
||||
},
|
||||
"memos": {"$ref": "memos"},
|
||||
"condition": {
|
||||
"type": "string",
|
||||
"description": "If present, fulfillment is required upon execution.",
|
||||
"pattern": "^[A-F0-9]{0,256}$"
|
||||
},
|
||||
"allowCancelAfter": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "If present, the escrow may be cancelled after this time."
|
||||
},
|
||||
"allowExecuteAfter": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "If present, the escrow can not be executed before this time."
|
||||
},
|
||||
"sourceTag": {
|
||||
"$ref": "tag",
|
||||
"description": "Source tag."
|
||||
},
|
||||
"destinationTag": {
|
||||
"$ref": "tag",
|
||||
"description": "Destination tag."
|
||||
}
|
||||
},
|
||||
"required": ["amount", "destination"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
29
src/common/schemas/specifications/escrow-execution.json
Normal file
29
src/common/schemas/specifications/escrow-execution.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "escrowExecution",
|
||||
"link": "escrow-execution",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memos": {"$ref": "memos"},
|
||||
"owner": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the owner of the escrow to execute."
|
||||
},
|
||||
"escrowSequence": {
|
||||
"$ref": "sequence",
|
||||
"description": "The [account sequence number](#account-sequence-number) of the [Escrow Creation](#escrow-creation) transaction for the escrow to execute."
|
||||
},
|
||||
"condition": {
|
||||
"type": "string",
|
||||
"description": "The original `condition` from the escrow creation transaction. This is sha256 hash of `fulfillment` 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 condition with the new condition.",
|
||||
"pattern": "^[A-F0-9]{0,256}$"
|
||||
},
|
||||
"fulfillment": {
|
||||
"type": "string",
|
||||
"description": "A value that produces the condition when hashed. It must be 32 charaters long and contain only 8-bit characters.",
|
||||
"pattern": "^[A-F0-9]+$"
|
||||
}
|
||||
},
|
||||
"required": ["owner", "escrowSequence"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
38
src/common/schemas/specifications/payment-channel-claim.json
Normal file
38
src/common/schemas/specifications/payment-channel-claim.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "paymentChannelClaim",
|
||||
"link": "payment-channel-claim",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"channel": {
|
||||
"$ref": "hash256",
|
||||
"description": "256-bit hexadecimal channel identifier."
|
||||
},
|
||||
"amount": {
|
||||
"$ref": "value",
|
||||
"description": "XRP balance of this channel after claim is processed."
|
||||
},
|
||||
"balance": {
|
||||
"$ref": "value",
|
||||
"description": "Amount of XRP authorized by signature."
|
||||
},
|
||||
"signature": {
|
||||
"$ref": "signature",
|
||||
"description": "Signature of this claim."
|
||||
},
|
||||
"publicKey": {
|
||||
"$ref": "publicKey",
|
||||
"description": "Public key of the channel's sender"
|
||||
},
|
||||
"renew": {
|
||||
"type": "boolean",
|
||||
"description": "Clear the channel's expiration time."
|
||||
},
|
||||
"close": {
|
||||
"type": "boolean",
|
||||
"description": "Request to close the channel."
|
||||
}
|
||||
},
|
||||
"required": ["channel"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "paymentChannelCreate",
|
||||
"link": "payment-channel-create",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amount": {
|
||||
"$ref": "value",
|
||||
"description": "Amount of XRP for sender to set aside in this channel."
|
||||
},
|
||||
"destination": {
|
||||
"$ref": "address",
|
||||
"description": "Address to receive XRP claims against this channel."
|
||||
},
|
||||
"settleDelay": {
|
||||
"type": "number",
|
||||
"description": "Amount of time the source address must wait before closing the channel if it has unclaimed XRP."
|
||||
},
|
||||
"publicKey": {
|
||||
"$ref": "publicKey",
|
||||
"description": "Public key of the key pair the source will use to sign claims against this channel."
|
||||
},
|
||||
"cancelAfter": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Time when this channel expires."
|
||||
},
|
||||
"sourceTag": {
|
||||
"$ref": "tag",
|
||||
"description": "Source tag."
|
||||
},
|
||||
"destinationTag": {
|
||||
"$ref": "tag",
|
||||
"description": "Destination tag."
|
||||
}
|
||||
},
|
||||
"required": ["amount", "destination", "settleDelay", "publicKey"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
23
src/common/schemas/specifications/payment-channel-fund.json
Normal file
23
src/common/schemas/specifications/payment-channel-fund.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "paymentChannelFund",
|
||||
"link": "payment-channel-fund",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amount": {
|
||||
"$ref": "value",
|
||||
"description": "Amount of XRP to fund the channel with."
|
||||
},
|
||||
"channel": {
|
||||
"$ref": "hash256",
|
||||
"description": "256-bit hexadecimal channel identifier."
|
||||
},
|
||||
"expiration": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "New expiration for this channel."
|
||||
}
|
||||
},
|
||||
"required": ["amount", "channel"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "suspendedPaymentCancellation",
|
||||
"link": "suspended-payment-cancellation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memos": {"$ref": "memos"},
|
||||
"owner": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the owner of the suspended payment to cancel."
|
||||
},
|
||||
"suspensionSequence": {
|
||||
"$ref": "sequence",
|
||||
"description": "The [account sequence number](#account-sequence-number) of the [Suspended Payment Creation](#suspended-payment-creation) transaction for the suspended payment to cancel."
|
||||
}
|
||||
},
|
||||
"required": ["owner", "suspensionSequence"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "suspendedPaymentCreation",
|
||||
"link": "suspended-payment-creation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"source": {
|
||||
"$ref": "maxAdjustment",
|
||||
"description": "Fields pertaining to the source of the payment."
|
||||
},
|
||||
"destination": {
|
||||
"$ref": "destinationExactAdjustment",
|
||||
"description": "Fields pertaining to the destination of the payment."
|
||||
},
|
||||
"memos": {"$ref": "memos"},
|
||||
"digest": {
|
||||
"$ref": "hash256",
|
||||
"description": "If present, proof is required upon execution."
|
||||
},
|
||||
"allowCancelAfter": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "If present, the suspended payment may be cancelled after this time."
|
||||
},
|
||||
"allowExecuteAfter": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "If present, the suspended payment can not be executed before this time."
|
||||
}
|
||||
},
|
||||
"required": ["source", "destination"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "suspendedPaymentExecution",
|
||||
"link": "suspended-payment-execution",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memos": {"$ref": "memos"},
|
||||
"owner": {
|
||||
"$ref": "address",
|
||||
"description": "The address of the owner of the suspended payment to execute."
|
||||
},
|
||||
"suspensionSequence": {
|
||||
"$ref": "sequence",
|
||||
"description": "The [account sequence number](#account-sequence-number) of the [Suspended Payment Creation](#suspended-payment-creation) transaction for the suspended payment to execute."
|
||||
},
|
||||
"method": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"description": "The method for verifying the proof; only method `1` is supported."
|
||||
},
|
||||
"digest": {
|
||||
"$ref": "hash256",
|
||||
"description": "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."
|
||||
},
|
||||
"proof": {
|
||||
"type": "string",
|
||||
"description": "A value that produces the digest when hashed. It must be 32 charaters long and contain only 8-bit characters.",
|
||||
"pattern": "^[\\x00-\\xFF]{32}$"
|
||||
}
|
||||
},
|
||||
"required": ["owner", "suspensionSequence"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const {convertKeysFromSnakeCaseToCamelCase} = require('./utils');
|
||||
import type {Connection} from './connection';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const {convertKeysFromSnakeCaseToCamelCase} = require('./utils')
|
||||
import type {Connection} from './connection'
|
||||
|
||||
export type GetServerInfoResponse = {
|
||||
buildVersion: string,
|
||||
@@ -34,46 +34,46 @@ export type GetServerInfoResponse = {
|
||||
|
||||
function renameKeys(object, mapping) {
|
||||
_.forEach(mapping, (to, from) => {
|
||||
object[to] = object[from];
|
||||
delete object[from];
|
||||
});
|
||||
object[to] = object[from]
|
||||
delete object[from]
|
||||
})
|
||||
}
|
||||
|
||||
function getServerInfo(connection: Connection): Promise<GetServerInfoResponse> {
|
||||
return connection.request({command: 'server_info'}).then(response => {
|
||||
const info = convertKeysFromSnakeCaseToCamelCase(response.info);
|
||||
renameKeys(info, {hostid: 'hostID'});
|
||||
const info = convertKeysFromSnakeCaseToCamelCase(response.info)
|
||||
renameKeys(info, {hostid: 'hostID'})
|
||||
if (info.validatedLedger) {
|
||||
renameKeys(info.validatedLedger, {
|
||||
baseFeeXrp: 'baseFeeXRP',
|
||||
reserveBaseXrp: 'reserveBaseXRP',
|
||||
reserveIncXrp: 'reserveIncrementXRP',
|
||||
seq: 'ledgerVersion'
|
||||
});
|
||||
})
|
||||
info.validatedLedger.baseFeeXRP =
|
||||
info.validatedLedger.baseFeeXRP.toString();
|
||||
info.validatedLedger.baseFeeXRP.toString()
|
||||
info.validatedLedger.reserveBaseXRP =
|
||||
info.validatedLedger.reserveBaseXRP.toString();
|
||||
info.validatedLedger.reserveBaseXRP.toString()
|
||||
info.validatedLedger.reserveIncrementXRP =
|
||||
info.validatedLedger.reserveIncrementXRP.toString();
|
||||
info.validatedLedger.reserveIncrementXRP.toString()
|
||||
}
|
||||
return info;
|
||||
});
|
||||
return info
|
||||
})
|
||||
}
|
||||
|
||||
function computeFeeFromServerInfo(cushion: number,
|
||||
serverInfo: GetServerInfoResponse
|
||||
): number {
|
||||
return (Number(serverInfo.validatedLedger.baseFeeXRP)
|
||||
* Number(serverInfo.loadFactor) * cushion).toString();
|
||||
* Number(serverInfo.loadFactor) * cushion).toString()
|
||||
}
|
||||
|
||||
function getFee(connection: Connection, cushion: number) {
|
||||
return getServerInfo(connection).then(
|
||||
_.partial(computeFeeFromServerInfo, cushion));
|
||||
_.partial(computeFeeFromServerInfo, cushion))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getServerInfo,
|
||||
getFee
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
const txFlags = {
|
||||
// Universal flags can apply to any transaction type
|
||||
@@ -35,8 +35,13 @@ const txFlags = {
|
||||
NoRippleDirect: 0x00010000,
|
||||
PartialPayment: 0x00020000,
|
||||
LimitQuality: 0x00040000
|
||||
},
|
||||
|
||||
PaymentChannelClaim: {
|
||||
Renew: 0x00010000,
|
||||
Close: 0x00020000
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// The following are integer (as opposed to bit) flags
|
||||
// that can be set for particular transactions in the
|
||||
@@ -52,9 +57,9 @@ const txFlagIndices = {
|
||||
asfGlobalFreeze: 7,
|
||||
asfDefaultRipple: 8
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
txFlags,
|
||||
txFlagIndices
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
export type RippledAmountIOU = {
|
||||
currency: string,
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const {deriveKeypair} = require('ripple-keypairs');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const {deriveKeypair} = require('ripple-keypairs')
|
||||
|
||||
import type {Amount, RippledAmount} from './types.js';
|
||||
import type {Amount, RippledAmount} from './types.js'
|
||||
|
||||
function isValidSecret(secret: string): boolean {
|
||||
try {
|
||||
deriveKeypair(secret);
|
||||
return true;
|
||||
deriveKeypair(secret)
|
||||
return true
|
||||
} catch (err) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function dropsToXrp(drops: string): string {
|
||||
return (new BigNumber(drops)).dividedBy(1000000.0).toString();
|
||||
return (new BigNumber(drops)).dividedBy(1000000.0).toString()
|
||||
}
|
||||
|
||||
function xrpToDrops(xrp: string): string {
|
||||
return (new BigNumber(xrp)).times(1000000.0).floor().toString();
|
||||
return (new BigNumber(xrp)).times(1000000.0).floor().toString()
|
||||
}
|
||||
|
||||
function toRippledAmount(amount: Amount): RippledAmount {
|
||||
if (amount.currency === 'XRP') {
|
||||
return xrpToDrops(amount.value);
|
||||
return xrpToDrops(amount.value)
|
||||
}
|
||||
return {
|
||||
currency: amount.currency,
|
||||
issuer: amount.counterparty ? amount.counterparty :
|
||||
(amount.issuer ? amount.issuer : undefined),
|
||||
value: amount.value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
|
||||
if (typeof obj === 'object') {
|
||||
let newKey;
|
||||
let newKey
|
||||
return _.reduce(obj, (result, value, key) => {
|
||||
newKey = key;
|
||||
newKey = key
|
||||
// taking this out of function leads to error in PhantomJS
|
||||
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g;
|
||||
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g
|
||||
if (FINDSNAKE.test(key)) {
|
||||
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase());
|
||||
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase())
|
||||
}
|
||||
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value);
|
||||
return result;
|
||||
}, {});
|
||||
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value)
|
||||
return result
|
||||
}, {})
|
||||
}
|
||||
return obj;
|
||||
return obj
|
||||
}
|
||||
|
||||
function removeUndefined(obj: Object): Object {
|
||||
return _.omit(obj, _.isUndefined);
|
||||
return _.omit(obj, _.isUndefined)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@ function removeUndefined(obj: Object): Object {
|
||||
*
|
||||
*/
|
||||
function rippleToUnixTimestamp(rpepoch: number): number {
|
||||
return (rpepoch + 0x386D4380) * 1000;
|
||||
return (rpepoch + 0x386D4380) * 1000
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,15 +70,15 @@ function rippleToUnixTimestamp(rpepoch: number): number {
|
||||
* @return {Number} seconds since ripple epoch ( 1/1/2000 GMT)
|
||||
*/
|
||||
function unixToRippleTimestamp(timestamp: number): number {
|
||||
return Math.round(timestamp / 1000) - 0x386D4380;
|
||||
return Math.round(timestamp / 1000) - 0x386D4380
|
||||
}
|
||||
|
||||
function rippleTimeToISO8601(rippleTime: number): string {
|
||||
return new Date(rippleToUnixTimestamp(rippleTime)).toISOString();
|
||||
return new Date(rippleToUnixTimestamp(rippleTime)).toISOString()
|
||||
}
|
||||
|
||||
function iso8601ToRippleTime(iso8601: string): number {
|
||||
return unixToRippleTimestamp(Date.parse(iso8601));
|
||||
return unixToRippleTimestamp(Date.parse(iso8601))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -90,4 +90,4 @@ module.exports = {
|
||||
rippleTimeToISO8601,
|
||||
iso8601ToRippleTime,
|
||||
isValidSecret
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const ValidationError = require('./errors').ValidationError;
|
||||
const schemaValidate = require('./schema-validator').schemaValidate;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const ValidationError = require('./errors').ValidationError
|
||||
const schemaValidate = require('./schema-validator').schemaValidate
|
||||
|
||||
function error(text) {
|
||||
return new ValidationError(text);
|
||||
return new ValidationError(text)
|
||||
}
|
||||
|
||||
function validateLedgerRange(options) {
|
||||
if (!_.isUndefined(options) && !_.isUndefined(options.minLedgerVersion)
|
||||
&& !_.isUndefined(options.maxLedgerVersion)) {
|
||||
if (Number(options.minLedgerVersion) > Number(options.maxLedgerVersion)) {
|
||||
throw error('minLedgerVersion must not be greater than maxLedgerVersion');
|
||||
throw error('minLedgerVersion must not be greater than maxLedgerVersion')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateOptions(schema, instance) {
|
||||
schemaValidate(schema, instance);
|
||||
validateLedgerRange(instance.options);
|
||||
schemaValidate(schema, instance)
|
||||
validateLedgerRange(instance.options)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -40,12 +40,18 @@ module.exports = {
|
||||
_.partial(schemaValidate, 'prepareOrderCancellationParameters'),
|
||||
prepareTrustline: _.partial(schemaValidate, 'prepareTrustlineParameters'),
|
||||
prepareSettings: _.partial(schemaValidate, 'prepareSettingsParameters'),
|
||||
prepareSuspendedPaymentCreation: _.partial(schemaValidate,
|
||||
'prepareSuspendedPaymentCreationParameters'),
|
||||
prepareSuspendedPaymentCancellation: _.partial(schemaValidate,
|
||||
'prepareSuspendedPaymentCancellationParameters'),
|
||||
prepareSuspendedPaymentExecution: _.partial(schemaValidate,
|
||||
'prepareSuspendedPaymentExecutionParameters'),
|
||||
prepareEscrowCreation: _.partial(schemaValidate,
|
||||
'prepareEscrowCreationParameters'),
|
||||
prepareEscrowCancellation: _.partial(schemaValidate,
|
||||
'prepareEscrowCancellationParameters'),
|
||||
prepareEscrowExecution: _.partial(schemaValidate,
|
||||
'prepareEscrowExecutionParameters'),
|
||||
preparePaymentChannelCreate: _.partial(schemaValidate,
|
||||
'preparePaymentChannelCreateParameters'),
|
||||
preparePaymentChannelFund: _.partial(schemaValidate,
|
||||
'preparePaymentChannelFundParameters'),
|
||||
preparePaymentChannelClaim: _.partial(schemaValidate,
|
||||
'preparePaymentChannelClaimParameters'),
|
||||
sign: _.partial(schemaValidate, 'signParameters'),
|
||||
combine: _.partial(schemaValidate, 'combineParameters'),
|
||||
submit: _.partial(schemaValidate, 'submitParameters'),
|
||||
@@ -53,4 +59,4 @@ module.exports = {
|
||||
generateAddress: _.partial(schemaValidate, 'generateAddressParameters'),
|
||||
apiOptions: _.partial(schemaValidate, 'api-options'),
|
||||
instructions: _.partial(schemaValidate, 'instructions')
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
const {EventEmitter} = require('events');
|
||||
const {EventEmitter} = require('events')
|
||||
|
||||
function unsused() {}
|
||||
|
||||
@@ -10,50 +10,50 @@ function unsused() {}
|
||||
*/
|
||||
class WSWrapper extends EventEmitter {
|
||||
constructor(url, protocols = null, websocketOptions = {}) {
|
||||
super();
|
||||
unsused(protocols);
|
||||
unsused(websocketOptions);
|
||||
this.setMaxListeners(Infinity);
|
||||
super()
|
||||
unsused(protocols)
|
||||
unsused(websocketOptions)
|
||||
this.setMaxListeners(Infinity)
|
||||
|
||||
this._ws = new WebSocket(url);
|
||||
this._ws = new WebSocket(url)
|
||||
|
||||
this._ws.onclose = () => {
|
||||
this.emit('close');
|
||||
};
|
||||
this.emit('close')
|
||||
}
|
||||
|
||||
this._ws.onopen = () => {
|
||||
this.emit('open');
|
||||
};
|
||||
this.emit('open')
|
||||
}
|
||||
|
||||
this._ws.onerror = error => {
|
||||
this.emit('error', error);
|
||||
};
|
||||
this.emit('error', error)
|
||||
}
|
||||
|
||||
this._ws.onmessage = message => {
|
||||
this.emit('message', message.data);
|
||||
};
|
||||
this.emit('message', message.data)
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.readyState === 1) {
|
||||
this._ws.close();
|
||||
this._ws.close()
|
||||
}
|
||||
}
|
||||
|
||||
send(message) {
|
||||
this._ws.send(message);
|
||||
this._ws.send(message)
|
||||
}
|
||||
|
||||
get readyState() {
|
||||
return this._ws.readyState;
|
||||
return this._ws.readyState
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WSWrapper.CONNECTING = 0;
|
||||
WSWrapper.OPEN = 1;
|
||||
WSWrapper.CLOSING = 2;
|
||||
WSWrapper.CLOSED = 3;
|
||||
WSWrapper.CONNECTING = 0
|
||||
WSWrapper.OPEN = 1
|
||||
WSWrapper.CLOSING = 2
|
||||
WSWrapper.CLOSED = 3
|
||||
|
||||
module.exports = WSWrapper;
|
||||
module.exports = WSWrapper
|
||||
|
||||
|
||||
78
src/http.js
78
src/http.js
@@ -1,86 +1,86 @@
|
||||
/* eslint-disable new-cap */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
const assert = require('assert');
|
||||
const _ = require('lodash');
|
||||
const jayson = require('jayson');
|
||||
const assert = require('assert')
|
||||
const _ = require('lodash')
|
||||
const jayson = require('jayson')
|
||||
|
||||
const RippleAPI = require('./api').RippleAPI;
|
||||
const RippleAPI = require('./api').RippleAPI
|
||||
|
||||
|
||||
/* istanbul ignore next */
|
||||
function createHTTPServer(options, httpPort) {
|
||||
const rippleAPI = new RippleAPI(options);
|
||||
const rippleAPI = new RippleAPI(options)
|
||||
|
||||
const methodNames = _.filter(_.keys(RippleAPI.prototype), k => {
|
||||
return typeof RippleAPI.prototype[k] === 'function'
|
||||
&& k !== 'connect'
|
||||
&& k !== 'disconnect'
|
||||
&& k !== 'constructor'
|
||||
&& k !== 'RippleAPI';
|
||||
});
|
||||
&& k !== 'RippleAPI'
|
||||
})
|
||||
|
||||
function applyPromiseWithCallback(fnName, callback, args_) {
|
||||
try {
|
||||
let args = args_;
|
||||
let args = args_
|
||||
if (!_.isArray(args_)) {
|
||||
const fnParameters = jayson.Utils.getParameterNames(rippleAPI[fnName]);
|
||||
args = fnParameters.map(name => args_[name]);
|
||||
const defaultArgs = _.omit(args_, fnParameters);
|
||||
const fnParameters = jayson.Utils.getParameterNames(rippleAPI[fnName])
|
||||
args = fnParameters.map(name => args_[name])
|
||||
const defaultArgs = _.omit(args_, fnParameters)
|
||||
assert(_.size(defaultArgs) <= 1,
|
||||
'Function must have no more than one default argument');
|
||||
'Function must have no more than one default argument')
|
||||
if (_.size(defaultArgs) > 0) {
|
||||
args.push(defaultArgs[_.keys(defaultArgs)[0]]);
|
||||
args.push(defaultArgs[_.keys(defaultArgs)[0]])
|
||||
}
|
||||
}
|
||||
Promise.resolve(rippleAPI[fnName].apply(rippleAPI, args))
|
||||
Promise.resolve(rippleAPI[fnName](...args))
|
||||
.then(res => callback(null, res))
|
||||
.catch(err => {
|
||||
callback({code: 99, message: err.message, data: {name: err.name}});
|
||||
});
|
||||
callback({code: 99, message: err.message, data: {name: err.name}})
|
||||
})
|
||||
} catch (err) {
|
||||
callback({code: 99, message: err.message, data: {name: err.name}});
|
||||
callback({code: 99, message: err.message, data: {name: err.name}})
|
||||
}
|
||||
}
|
||||
|
||||
const methods = {};
|
||||
const methods = {}
|
||||
_.forEach(methodNames, fn => {
|
||||
methods[fn] = jayson.Method((args, cb) => {
|
||||
applyPromiseWithCallback(fn, cb, args);
|
||||
}, {collect: true});
|
||||
});
|
||||
applyPromiseWithCallback(fn, cb, args)
|
||||
}, {collect: true})
|
||||
})
|
||||
|
||||
const server = jayson.server(methods);
|
||||
let httpServer = null;
|
||||
const server = jayson.server(methods)
|
||||
let httpServer = null
|
||||
|
||||
return {
|
||||
server: server,
|
||||
start: function() {
|
||||
if (httpServer !== null) {
|
||||
return Promise.reject('Already started');
|
||||
return Promise.reject('Already started')
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
rippleAPI.connect().then(() => {
|
||||
httpServer = server.http();
|
||||
httpServer.listen(httpPort, resolve);
|
||||
});
|
||||
});
|
||||
httpServer = server.http()
|
||||
httpServer.listen(httpPort, resolve)
|
||||
})
|
||||
})
|
||||
},
|
||||
stop: function() {
|
||||
if (httpServer === null) {
|
||||
return Promise.reject('Not started');
|
||||
return Promise.reject('Not started')
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
rippleAPI.disconnect();
|
||||
return new Promise(resolve => {
|
||||
rippleAPI.disconnect()
|
||||
httpServer.close(() => {
|
||||
httpServer = null;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
httpServer = null
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createHTTPServer
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
module.exports = {
|
||||
RippleAPI: require('./api').RippleAPI,
|
||||
@@ -6,4 +6,4 @@ module.exports = {
|
||||
RippleAPIBroadcast: require('./broadcast').RippleAPIBroadcast,
|
||||
// HTTP server is experimental
|
||||
createHTTPServer: require('./http').createHTTPServer
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* @flow */
|
||||
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
const {validate, removeUndefined} = utils.common;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('./utils')
|
||||
const {validate, removeUndefined} = utils.common
|
||||
|
||||
type AccountData = {
|
||||
Sequence: number,
|
||||
@@ -39,7 +39,7 @@ type AccountInfoResponse = {
|
||||
}
|
||||
|
||||
function formatAccountInfo(response: AccountDataResponse) {
|
||||
const data = response.account_data;
|
||||
const data = response.account_data
|
||||
return removeUndefined({
|
||||
sequence: data.Sequence,
|
||||
xrpBalance: utils.common.dropsToXrp(data.Balance),
|
||||
@@ -47,20 +47,20 @@ function formatAccountInfo(response: AccountDataResponse) {
|
||||
previousInitiatedTransactionID: data.AccountTxnID,
|
||||
previousAffectingTransactionID: data.PreviousTxnID,
|
||||
previousAffectingTransactionLedgerVersion: data.PreviousTxnLgrSeq
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function getAccountInfo(address: string, options: AccountInfoOptions = {}
|
||||
): Promise<AccountInfoResponse> {
|
||||
validate.getAccountInfo({address, options});
|
||||
validate.getAccountInfo({address, options})
|
||||
|
||||
const request = {
|
||||
command: 'account_info',
|
||||
account: address,
|
||||
ledger_index: options.ledgerVersion || 'validated'
|
||||
};
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(formatAccountInfo);
|
||||
return this.connection.request(request).then(formatAccountInfo)
|
||||
}
|
||||
|
||||
module.exports = getAccountInfo;
|
||||
module.exports = getAccountInfo
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
import type {Amount} from '../common/types.js';
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const {validate} = utils.common
|
||||
import type {Amount} from '../common/types.js'
|
||||
|
||||
type BalanceSheetOptions = {
|
||||
excludeAddresses?: Array<string>,
|
||||
@@ -21,35 +21,35 @@ type GetBalanceSheet = {
|
||||
}
|
||||
|
||||
function formatBalanceSheet(balanceSheet): GetBalanceSheet {
|
||||
const result = {};
|
||||
const result = {}
|
||||
|
||||
if (!_.isUndefined(balanceSheet.balances)) {
|
||||
result.balances = [];
|
||||
result.balances = []
|
||||
_.forEach(balanceSheet.balances, (balances, counterparty) => {
|
||||
_.forEach(balances, (balance) => {
|
||||
result.balances.push(Object.assign({counterparty}, balance));
|
||||
});
|
||||
});
|
||||
_.forEach(balances, balance => {
|
||||
result.balances.push(Object.assign({counterparty}, balance))
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!_.isUndefined(balanceSheet.assets)) {
|
||||
result.assets = [];
|
||||
result.assets = []
|
||||
_.forEach(balanceSheet.assets, (assets, counterparty) => {
|
||||
_.forEach(assets, (balance) => {
|
||||
result.assets.push(Object.assign({counterparty}, balance));
|
||||
});
|
||||
});
|
||||
_.forEach(assets, balance => {
|
||||
result.assets.push(Object.assign({counterparty}, balance))
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!_.isUndefined(balanceSheet.obligations)) {
|
||||
result.obligations = _.map(balanceSheet.obligations, (value, currency) =>
|
||||
({currency, value}));
|
||||
({currency, value}))
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function getBalanceSheet(address: string, options: BalanceSheetOptions = {}
|
||||
): Promise<GetBalanceSheet> {
|
||||
validate.getBalanceSheet({address, options});
|
||||
validate.getBalanceSheet({address, options})
|
||||
|
||||
return utils.ensureLedgerVersion.call(this, options).then(_options => {
|
||||
const request = {
|
||||
@@ -58,10 +58,10 @@ function getBalanceSheet(address: string, options: BalanceSheetOptions = {}
|
||||
strict: true,
|
||||
hotwallet: _options.excludeAddresses,
|
||||
ledger_index: _options.ledgerVersion
|
||||
};
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(formatBalanceSheet);
|
||||
});
|
||||
return this.connection.request(request).then(formatBalanceSheet)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = getBalanceSheet;
|
||||
module.exports = getBalanceSheet
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
import type {Connection} from '../common/connection.js';
|
||||
import type {TrustlinesOptions, Trustline} from './trustlines-types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('./utils')
|
||||
const {validate} = utils.common
|
||||
import type {Connection} from '../common/connection.js'
|
||||
import type {TrustlinesOptions, Trustline} from './trustlines-types.js'
|
||||
|
||||
|
||||
type Balance = {
|
||||
@@ -19,38 +19,38 @@ function getTrustlineBalanceAmount(trustline: Trustline) {
|
||||
currency: trustline.specification.currency,
|
||||
counterparty: trustline.specification.counterparty,
|
||||
value: trustline.state.balance
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function formatBalances(options, balances) {
|
||||
const result = balances.trustlines.map(getTrustlineBalanceAmount);
|
||||
const result = balances.trustlines.map(getTrustlineBalanceAmount)
|
||||
if (!(options.counterparty ||
|
||||
(options.currency && options.currency !== 'XRP')
|
||||
)) {
|
||||
const xrpBalance = {
|
||||
currency: 'XRP',
|
||||
value: balances.xrp
|
||||
};
|
||||
result.unshift(xrpBalance);
|
||||
}
|
||||
result.unshift(xrpBalance)
|
||||
}
|
||||
if (options.limit && result.length > options.limit) {
|
||||
const toRemove = result.length - options.limit;
|
||||
result.splice(-toRemove, toRemove);
|
||||
const toRemove = result.length - options.limit
|
||||
result.splice(-toRemove, toRemove)
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function getLedgerVersionHelper(connection: Connection, optionValue?: number
|
||||
): Promise<number> {
|
||||
if (optionValue !== undefined && optionValue !== null) {
|
||||
return Promise.resolve(optionValue);
|
||||
return Promise.resolve(optionValue)
|
||||
}
|
||||
return connection.getLedgerVersion();
|
||||
return connection.getLedgerVersion()
|
||||
}
|
||||
|
||||
function getBalances(address: string, options: TrustlinesOptions = {}
|
||||
): Promise<GetBalances> {
|
||||
validate.getTrustlines({address, options});
|
||||
validate.getTrustlines({address, options})
|
||||
|
||||
return Promise.all([
|
||||
getLedgerVersionHelper(this.connection, options.ledgerVersion).then(
|
||||
@@ -58,7 +58,7 @@ function getBalances(address: string, options: TrustlinesOptions = {}
|
||||
utils.getXRPBalance(this.connection, address, ledgerVersion)),
|
||||
this.getTrustlines(address, options)
|
||||
]).then(results =>
|
||||
formatBalances(options, {xrp: results[0], trustlines: results[1]}));
|
||||
formatBalances(options, {xrp: results[0], trustlines: results[1]}))
|
||||
}
|
||||
|
||||
module.exports = getBalances;
|
||||
module.exports = getBalances
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
const parseLedger = require('./parse/ledger');
|
||||
import type {GetLedger} from './types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('./utils')
|
||||
const {validate} = utils.common
|
||||
const parseLedger = require('./parse/ledger')
|
||||
import type {GetLedger} from './types.js'
|
||||
|
||||
type LedgerOptions = {
|
||||
ledgerVersion?: number,
|
||||
@@ -14,7 +14,7 @@ type LedgerOptions = {
|
||||
|
||||
|
||||
function getLedger(options: LedgerOptions = {}): Promise<GetLedger> {
|
||||
validate.getLedger({options});
|
||||
validate.getLedger({options})
|
||||
|
||||
const request = {
|
||||
command: 'ledger',
|
||||
@@ -22,10 +22,10 @@ function getLedger(options: LedgerOptions = {}): Promise<GetLedger> {
|
||||
expand: options.includeAllData,
|
||||
transactions: options.includeTransactions,
|
||||
accounts: options.includeState
|
||||
};
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(response =>
|
||||
parseLedger(response.ledger));
|
||||
parseLedger(response.ledger))
|
||||
}
|
||||
|
||||
module.exports = getLedger;
|
||||
module.exports = getLedger
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
const parseOrderbookOrder = require('./parse/orderbook-order');
|
||||
import type {Connection} from '../common/connection.js';
|
||||
import type {OrdersOptions, OrderSpecification} from './types.js';
|
||||
import type {Amount, Issue} from '../common/types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const {validate} = utils.common
|
||||
const parseOrderbookOrder = require('./parse/orderbook-order')
|
||||
import type {Connection} from '../common/connection.js'
|
||||
import type {OrdersOptions, OrderSpecification} from './types.js'
|
||||
import type {Amount, Issue} from '../common/types.js'
|
||||
|
||||
type Orderbook = {
|
||||
base: Issue,
|
||||
@@ -46,31 +46,31 @@ function getBookOffers(connection: Connection, account: string,
|
||||
ledger_index: ledgerVersion || 'validated',
|
||||
limit: limit,
|
||||
taker: account
|
||||
})).then(data => data.offers);
|
||||
})).then(data => data.offers)
|
||||
}
|
||||
|
||||
function isSameIssue(a: Amount, b: Amount) {
|
||||
return a.currency === b.currency && a.counterparty === b.counterparty;
|
||||
return a.currency === b.currency && a.counterparty === b.counterparty
|
||||
}
|
||||
|
||||
function directionFilter(direction: string, order: OrderbookItem) {
|
||||
return order.specification.direction === direction;
|
||||
return order.specification.direction === direction
|
||||
}
|
||||
|
||||
function flipOrder(order: OrderbookItem) {
|
||||
const specification = order.specification;
|
||||
const specification = order.specification
|
||||
const flippedSpecification = {
|
||||
quantity: specification.totalPrice,
|
||||
totalPrice: specification.quantity,
|
||||
direction: specification.direction === 'buy' ? 'sell' : 'buy'
|
||||
};
|
||||
const newSpecification = _.merge({}, specification, flippedSpecification);
|
||||
return _.merge({}, order, {specification: newSpecification});
|
||||
}
|
||||
const newSpecification = _.merge({}, specification, flippedSpecification)
|
||||
return _.merge({}, order, {specification: newSpecification})
|
||||
}
|
||||
|
||||
function alignOrder(base: Amount, order: OrderbookItem) {
|
||||
const quantity = order.specification.quantity;
|
||||
return isSameIssue(quantity, base) ? order : flipOrder(order);
|
||||
const quantity = order.specification.quantity
|
||||
return isSameIssue(quantity, base) ? order : flipOrder(order)
|
||||
}
|
||||
|
||||
function formatBidsAndAsks(orderbook: Orderbook, offers) {
|
||||
@@ -84,24 +84,24 @@ function formatBidsAndAsks(orderbook: Orderbook, offers) {
|
||||
// for asks: lowest quality => lowest totalPrice/quantity => lowest price
|
||||
// for both bids and asks, lowest quality is closest to mid-market
|
||||
// we sort the orders so that earlier orders are closer to mid-market
|
||||
const orders = _.sortBy(offers, 'quality').map(parseOrderbookOrder);
|
||||
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base));
|
||||
const bids = alignedOrders.filter(_.partial(directionFilter, 'buy'));
|
||||
const asks = alignedOrders.filter(_.partial(directionFilter, 'sell'));
|
||||
return {bids, asks};
|
||||
const orders = _.sortBy(offers, 'quality').map(parseOrderbookOrder)
|
||||
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base))
|
||||
const bids = alignedOrders.filter(_.partial(directionFilter, 'buy'))
|
||||
const asks = alignedOrders.filter(_.partial(directionFilter, 'sell'))
|
||||
return {bids, asks}
|
||||
}
|
||||
|
||||
function getOrderbook(address: string, orderbook: Orderbook,
|
||||
options: OrdersOptions = {}
|
||||
): Promise<GetOrderbook> {
|
||||
validate.getOrderbook({address, orderbook, options});
|
||||
validate.getOrderbook({address, orderbook, options})
|
||||
|
||||
const getter = _.partial(getBookOffers, this.connection, address,
|
||||
options.ledgerVersion, options.limit);
|
||||
const getOffers = _.partial(getter, orderbook.base, orderbook.counter);
|
||||
const getReverseOffers = _.partial(getter, orderbook.counter, orderbook.base);
|
||||
options.ledgerVersion, options.limit)
|
||||
const getOffers = _.partial(getter, orderbook.base, orderbook.counter)
|
||||
const getReverseOffers = _.partial(getter, orderbook.counter, orderbook.base)
|
||||
return Promise.all([getOffers(), getReverseOffers()]).then(data =>
|
||||
formatBidsAndAsks(orderbook, _.flatten(data)));
|
||||
formatBidsAndAsks(orderbook, _.flatten(data)))
|
||||
}
|
||||
|
||||
module.exports = getOrderbook;
|
||||
module.exports = getOrderbook
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
const parseAccountOrder = require('./parse/account-order');
|
||||
import type {Connection} from '../common/connection.js';
|
||||
import type {OrdersOptions, Order} from './types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const {validate} = utils.common
|
||||
const parseAccountOrder = require('./parse/account-order')
|
||||
import type {Connection} from '../common/connection.js'
|
||||
import type {OrdersOptions, Order} from './types.js'
|
||||
|
||||
type GetOrders = Array<Order>
|
||||
|
||||
@@ -22,20 +22,20 @@ function requestAccountOffers(connection: Connection, address: string,
|
||||
return {
|
||||
marker: data.marker,
|
||||
results: data.offers.map(_.partial(parseAccountOrder, address))
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getOrders(address: string, options: OrdersOptions = {}
|
||||
): Promise<GetOrders> {
|
||||
validate.getOrders({address, options});
|
||||
validate.getOrders({address, options})
|
||||
|
||||
return utils.ensureLedgerVersion.call(this, options).then(_options => {
|
||||
const getter = _.partial(requestAccountOffers, this.connection, address,
|
||||
_options.ledgerVersion);
|
||||
_options.ledgerVersion)
|
||||
return utils.getRecursive(getter, _options.limit).then(orders =>
|
||||
_.sortBy(orders, (order) => order.properties.sequence));
|
||||
});
|
||||
_.sortBy(orders, order => order.properties.sequence))
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = getOrders;
|
||||
module.exports = getOrders
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/* @flow */
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const utils = require('./utils');
|
||||
const flags = require('./flags').orderFlags;
|
||||
const parseAmount = require('./amount');
|
||||
const BigNumber = require('bignumber.js');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('./utils')
|
||||
const flags = require('./flags').orderFlags
|
||||
const parseAmount = require('./amount')
|
||||
const BigNumber = require('bignumber.js')
|
||||
|
||||
// TODO: remove this function once rippled provides quality directly
|
||||
function computeQuality(takerGets, takerPays) {
|
||||
const quotient = new BigNumber(takerPays.value).dividedBy(takerGets.value);
|
||||
return quotient.toDigits(16, BigNumber.ROUND_HALF_UP).toString();
|
||||
const quotient = new BigNumber(takerPays.value).dividedBy(takerGets.value)
|
||||
return quotient.toDigits(16, BigNumber.ROUND_HALF_UP).toString()
|
||||
}
|
||||
|
||||
// rippled 'account_offers' returns a different format for orders than 'tx'
|
||||
// the flags are also different
|
||||
function parseAccountOrder(address: string, order: Object): Object {
|
||||
const direction = (order.flags & flags.Sell) === 0 ? 'buy' : 'sell';
|
||||
const takerGetsAmount = parseAmount(order.taker_gets);
|
||||
const takerPaysAmount = parseAmount(order.taker_pays);
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
|
||||
const direction = (order.flags & flags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(order.taker_gets)
|
||||
const takerPaysAmount = parseAmount(order.taker_pays)
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount
|
||||
|
||||
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
||||
// so we can omit those flags here
|
||||
@@ -29,19 +29,19 @@ function parseAccountOrder(address: string, order: Object): Object {
|
||||
passive: ((order.flags & flags.Passive) !== 0) || undefined,
|
||||
// rippled currently does not provide "expiration" in account_offers
|
||||
expirationTime: utils.parseTimestamp(order.expiration)
|
||||
});
|
||||
})
|
||||
|
||||
const makerExchangeRate = order.quality ?
|
||||
utils.adjustQualityForXRP(order.quality.toString(),
|
||||
takerGetsAmount.currency, takerPaysAmount.currency) :
|
||||
computeQuality(takerGetsAmount, takerPaysAmount);
|
||||
computeQuality(takerGetsAmount, takerPaysAmount)
|
||||
const properties = {
|
||||
maker: address,
|
||||
sequence: order.seq,
|
||||
makerExchangeRate: makerExchangeRate
|
||||
};
|
||||
}
|
||||
|
||||
return {specification, properties};
|
||||
return {specification, properties}
|
||||
}
|
||||
|
||||
module.exports = parseAccountOrder;
|
||||
module.exports = parseAccountOrder
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const utils = require('./utils');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('./utils')
|
||||
|
||||
type Trustline = {
|
||||
account: string, limit: number, currency: string, quality_in: ?number,
|
||||
@@ -29,18 +29,18 @@ function parseAccountTrustline(trustline: Trustline): AccountTrustline {
|
||||
ripplingDisabled: trustline.no_ripple || undefined,
|
||||
frozen: trustline.freeze || undefined,
|
||||
authorized: trustline.authorized || undefined
|
||||
});
|
||||
})
|
||||
// rippled doesn't provide the counterparty's qualities
|
||||
const counterparty = utils.removeUndefined({
|
||||
limit: trustline.limit_peer,
|
||||
ripplingDisabled: trustline.no_ripple_peer || undefined,
|
||||
frozen: trustline.freeze_peer || undefined,
|
||||
authorized: trustline.peer_authorized || undefined
|
||||
});
|
||||
})
|
||||
const state = {
|
||||
balance: trustline.balance
|
||||
};
|
||||
return {specification, counterparty, state};
|
||||
}
|
||||
return {specification, counterparty, state}
|
||||
}
|
||||
|
||||
module.exports = parseAccountTrustline;
|
||||
module.exports = parseAccountTrustline
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
function parseAmendment(tx: Object) {
|
||||
return {
|
||||
amendment: tx.Amendment
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = parseAmendment;
|
||||
module.exports = parseAmendment
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const utils = require('../utils');
|
||||
import type {Amount, RippledAmount} from '../../common/types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const utils = require('../utils')
|
||||
import type {Amount, RippledAmount} from '../../common/types.js'
|
||||
|
||||
|
||||
function parseAmount(amount: RippledAmount): Amount {
|
||||
@@ -9,13 +9,13 @@ function parseAmount(amount: RippledAmount): Amount {
|
||||
return {
|
||||
currency: 'XRP',
|
||||
value: utils.common.dropsToXrp(amount)
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
currency: amount.currency,
|
||||
value: amount.value,
|
||||
counterparty: amount.issuer
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = parseAmount;
|
||||
module.exports = parseAmount
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
|
||||
function parseOrderCancellation(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'OfferCancel');
|
||||
assert(tx.TransactionType === 'OfferCancel')
|
||||
return {
|
||||
orderSequence: tx.OfferSequence
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = parseOrderCancellation;
|
||||
module.exports = parseOrderCancellation
|
||||
|
||||
16
src/ledger/parse/escrow-cancellation.js
Normal file
16
src/ledger/parse/escrow-cancellation.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
|
||||
function parseEscrowCancellation(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'EscrowCancel')
|
||||
|
||||
return utils.removeUndefined({
|
||||
memos: utils.parseMemos(tx),
|
||||
owner: tx.Owner,
|
||||
escrowSequence: tx.OfferSequence
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parseEscrowCancellation
|
||||
23
src/ledger/parse/escrow-creation.js
Normal file
23
src/ledger/parse/escrow-creation.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parseAmount = require('./amount')
|
||||
|
||||
function parseEscrowCreation(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'EscrowCreate')
|
||||
|
||||
return utils.removeUndefined({
|
||||
amount: parseAmount(tx.Amount).value,
|
||||
destination: tx.Destination,
|
||||
memos: utils.parseMemos(tx),
|
||||
condition: tx.Condition,
|
||||
allowCancelAfter: utils.parseTimestamp(tx.CancelAfter),
|
||||
allowExecuteAfter: utils.parseTimestamp(tx.FinishAfter),
|
||||
sourceTag: tx.SourceTag,
|
||||
destinationTag: tx.DestinationTag
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parseEscrowCreation
|
||||
18
src/ledger/parse/escrow-execution.js
Normal file
18
src/ledger/parse/escrow-execution.js
Normal file
@@ -0,0 +1,18 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
|
||||
function parseEscrowExecution(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'EscrowFinish')
|
||||
|
||||
return utils.removeUndefined({
|
||||
memos: utils.parseMemos(tx),
|
||||
owner: tx.Owner,
|
||||
escrowSequence: tx.OfferSequence,
|
||||
condition: tx.Condition,
|
||||
fulfillment: tx.Fulfillment
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parseEscrowExecution
|
||||
@@ -1,15 +1,15 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const BigNumber = require('bignumber.js');
|
||||
const {dropsToXrp} = require('./utils');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const BigNumber = require('bignumber.js')
|
||||
const {dropsToXrp} = require('./utils')
|
||||
|
||||
function parseFeeUpdate(tx: Object) {
|
||||
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString();
|
||||
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString()
|
||||
return {
|
||||
baseFeeXRP: dropsToXrp(baseFeeDrops),
|
||||
referenceFeeUnits: tx.ReferenceFeeUnits,
|
||||
reserveBaseXRP: dropsToXrp(tx.ReserveBase),
|
||||
reserveIncrementXRP: dropsToXrp(tx.ReserveIncrement)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = parseFeeUpdate;
|
||||
module.exports = parseFeeUpdate
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const AccountFields = require('./utils').constants.AccountFields;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const AccountFields = require('./utils').constants.AccountFields
|
||||
|
||||
function parseField(info, value) {
|
||||
if (info.encoding === 'hex' && !info.length) { // e.g. "domain"
|
||||
return new Buffer(value, 'hex').toString('ascii');
|
||||
return new Buffer(value, 'hex').toString('ascii')
|
||||
}
|
||||
if (info.shift) {
|
||||
return (new BigNumber(value)).shift(-info.shift).toNumber();
|
||||
return (new BigNumber(value)).shift(-info.shift).toNumber()
|
||||
}
|
||||
return value;
|
||||
return value
|
||||
}
|
||||
|
||||
function parseFields(data: Object): Object {
|
||||
const settings = {};
|
||||
const settings = {}
|
||||
for (const fieldName in AccountFields) {
|
||||
const fieldValue = data[fieldName];
|
||||
const fieldValue = data[fieldName]
|
||||
if (fieldValue !== undefined) {
|
||||
const info = AccountFields[fieldName];
|
||||
settings[info.name] = parseField(info, fieldValue);
|
||||
const info = AccountFields[fieldName]
|
||||
settings[info.name] = parseField(info, fieldValue)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.RegularKey) {
|
||||
settings.regularKey = data.RegularKey;
|
||||
settings.regularKey = data.RegularKey
|
||||
}
|
||||
|
||||
// TODO: this isn't implemented in rippled yet, may have to change this later
|
||||
if (data.SignerQuorum || data.SignerEntries) {
|
||||
settings.signers = {};
|
||||
settings.signers = {}
|
||||
if (data.SignerQuorum) {
|
||||
settings.signers.threshold = data.SignerQuorum;
|
||||
settings.signers.threshold = data.SignerQuorum
|
||||
}
|
||||
if (data.SignerEntries) {
|
||||
settings.signers.weights = _.map(data.SignerEntries, entry => {
|
||||
return {
|
||||
address: entry.SignerEntry.Account,
|
||||
weight: entry.SignerEntry.SignerWeight
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
return settings
|
||||
}
|
||||
|
||||
module.exports = parseFields;
|
||||
module.exports = parseFields
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
const orderFlags = {
|
||||
Passive: 0x00010000,
|
||||
Sell: 0x00020000 // offer was placed as a sell
|
||||
};
|
||||
}
|
||||
|
||||
const trustlineFlags = {
|
||||
LowReserve: 0x00010000, // entry counts toward reserve
|
||||
@@ -14,9 +14,9 @@ const trustlineFlags = {
|
||||
HighNoRipple: 0x00200000,
|
||||
LowFreeze: 0x00400000,
|
||||
HighFreeze: 0x00800000
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
orderFlags,
|
||||
trustlineFlags
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
/* @flow */
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const {removeUndefined, rippleTimeToISO8601} = require('./utils');
|
||||
const parseTransaction = require('./transaction');
|
||||
import type {GetLedger} from '../types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const {removeUndefined, rippleTimeToISO8601} = require('./utils')
|
||||
const parseTransaction = require('./transaction')
|
||||
import type {GetLedger} from '../types.js'
|
||||
|
||||
function parseTransactionWrapper(ledgerVersion, tx) {
|
||||
const transaction = _.assign({}, _.omit(tx, 'metaData'), {
|
||||
meta: tx.metaData,
|
||||
ledger_index: ledgerVersion
|
||||
});
|
||||
const result = parseTransaction(transaction);
|
||||
})
|
||||
const result = parseTransaction(transaction)
|
||||
if (!result.outcome.ledgerVersion) {
|
||||
result.outcome.ledgerVersion = ledgerVersion;
|
||||
result.outcome.ledgerVersion = ledgerVersion
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function parseTransactions(transactions, ledgerVersion) {
|
||||
if (_.isEmpty(transactions)) {
|
||||
return {};
|
||||
return {}
|
||||
}
|
||||
if (_.isString(transactions[0])) {
|
||||
return {transactionHashes: transactions};
|
||||
return {transactionHashes: transactions}
|
||||
}
|
||||
return {
|
||||
transactions: _.map(transactions,
|
||||
_.partial(parseTransactionWrapper, ledgerVersion)),
|
||||
rawTransactions: JSON.stringify(transactions)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function parseState(state) {
|
||||
if (_.isEmpty(state)) {
|
||||
return {};
|
||||
return {}
|
||||
}
|
||||
if (_.isString(state[0])) {
|
||||
return {stateHashes: state};
|
||||
return {stateHashes: state}
|
||||
}
|
||||
return {rawState: JSON.stringify(state)};
|
||||
return {rawState: JSON.stringify(state)}
|
||||
}
|
||||
|
||||
function parseLedger(ledger: Object): GetLedger {
|
||||
const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10);
|
||||
const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10)
|
||||
return removeUndefined(_.assign({
|
||||
stateHash: ledger.account_hash,
|
||||
closeTime: rippleTimeToISO8601(ledger.close_time),
|
||||
@@ -57,7 +57,7 @@ function parseLedger(ledger: Object): GetLedger {
|
||||
},
|
||||
parseTransactions(ledger.transactions, ledgerVersion),
|
||||
parseState(ledger.accountState)
|
||||
));
|
||||
))
|
||||
}
|
||||
|
||||
module.exports = parseLedger;
|
||||
module.exports = parseLedger
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parseAmount = require('./amount');
|
||||
const flags = utils.txFlags.OfferCreate;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parseAmount = require('./amount')
|
||||
const flags = utils.txFlags.OfferCreate
|
||||
|
||||
function parseOrder(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'OfferCreate');
|
||||
assert(tx.TransactionType === 'OfferCreate')
|
||||
|
||||
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell';
|
||||
const takerGetsAmount = parseAmount(tx.TakerGets);
|
||||
const takerPaysAmount = parseAmount(tx.TakerPays);
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
|
||||
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(tx.TakerGets)
|
||||
const takerPaysAmount = parseAmount(tx.TakerPays)
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount
|
||||
|
||||
return utils.removeUndefined({
|
||||
direction: direction,
|
||||
@@ -23,7 +23,7 @@ function parseOrder(tx: Object): Object {
|
||||
|| undefined,
|
||||
fillOrKill: ((tx.Flags & flags.FillOrKill) !== 0) || undefined,
|
||||
expirationTime: utils.parseTimestamp(tx.Expiration)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parseOrder;
|
||||
module.exports = parseOrder
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const flags = require('./flags').orderFlags;
|
||||
const parseAmount = require('./amount');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const flags = require('./flags').orderFlags
|
||||
const parseAmount = require('./amount')
|
||||
|
||||
function parseOrderbookOrder(order: Object): Object {
|
||||
const direction = (order.Flags & flags.Sell) === 0 ? 'buy' : 'sell';
|
||||
const takerGetsAmount = parseAmount(order.TakerGets);
|
||||
const takerPaysAmount = parseAmount(order.TakerPays);
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
|
||||
const direction = (order.Flags & flags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(order.TakerGets)
|
||||
const takerPaysAmount = parseAmount(order.TakerPays)
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount
|
||||
|
||||
// note: immediateOrCancel and fillOrKill orders cannot enter the order book
|
||||
// so we can omit those flags here
|
||||
@@ -20,25 +20,25 @@ function parseOrderbookOrder(order: Object): Object {
|
||||
totalPrice: totalPrice,
|
||||
passive: ((order.Flags & flags.Passive) !== 0) || undefined,
|
||||
expirationTime: utils.parseTimestamp(order.Expiration)
|
||||
});
|
||||
})
|
||||
|
||||
const properties = {
|
||||
maker: order.Account,
|
||||
sequence: order.Sequence,
|
||||
makerExchangeRate: utils.adjustQualityForXRP(order.quality,
|
||||
takerGetsAmount.currency, takerPaysAmount.currency)
|
||||
};
|
||||
}
|
||||
|
||||
const takerGetsFunded = order.taker_gets_funded ?
|
||||
parseAmount(order.taker_gets_funded) : undefined;
|
||||
parseAmount(order.taker_gets_funded) : undefined
|
||||
const takerPaysFunded = order.taker_pays_funded ?
|
||||
parseAmount(order.taker_pays_funded) : undefined;
|
||||
parseAmount(order.taker_pays_funded) : undefined
|
||||
const available = utils.removeUndefined({
|
||||
fundedAmount: takerGetsFunded,
|
||||
priceOfFundedAmount: takerPaysFunded
|
||||
});
|
||||
const state = _.isEmpty(available) ? undefined : available;
|
||||
return utils.removeUndefined({specification, properties, state});
|
||||
})
|
||||
const state = _.isEmpty(available) ? undefined : available
|
||||
return utils.removeUndefined({specification, properties, state})
|
||||
}
|
||||
|
||||
module.exports = parseOrderbookOrder;
|
||||
module.exports = parseOrderbookOrder
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const parseAmount = require('./amount');
|
||||
import type {Amount, RippledAmount} from '../../common/types.js';
|
||||
import type {GetPaths, RippledPathsResponse} from '../pathfind-types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const parseAmount = require('./amount')
|
||||
import type {Amount, RippledAmount} from '../../common/types.js'
|
||||
import type {GetPaths, RippledPathsResponse} from '../pathfind-types.js'
|
||||
|
||||
function parsePaths(paths) {
|
||||
return paths.map(steps => steps.map(step =>
|
||||
_.omit(step, ['type', 'type_hex'])));
|
||||
_.omit(step, ['type', 'type_hex'])))
|
||||
}
|
||||
|
||||
function removeAnyCounterpartyEncoding(address: string, amount: Amount) {
|
||||
return amount.counterparty === address ?
|
||||
_.omit(amount, 'counterparty') : amount;
|
||||
_.omit(amount, 'counterparty') : amount
|
||||
}
|
||||
|
||||
function createAdjustment(address: string, adjustmentWithoutAddress: Object) {
|
||||
const amountKey = _.keys(adjustmentWithoutAddress)[0];
|
||||
const amount = adjustmentWithoutAddress[amountKey];
|
||||
const amountKey = _.keys(adjustmentWithoutAddress)[0]
|
||||
const amount = adjustmentWithoutAddress[amountKey]
|
||||
return _.set({address: address}, amountKey,
|
||||
removeAnyCounterpartyEncoding(address, amount));
|
||||
removeAnyCounterpartyEncoding(address, amount))
|
||||
}
|
||||
|
||||
function parseAlternative(sourceAddress: string, destinationAddress: string,
|
||||
@@ -31,21 +31,21 @@ function parseAlternative(sourceAddress: string, destinationAddress: string,
|
||||
{source: {amount: parseAmount(alternative.source_amount)},
|
||||
destination: {minAmount: parseAmount(alternative.destination_amount)}} :
|
||||
{source: {maxAmount: parseAmount(alternative.source_amount)},
|
||||
destination: {amount: parseAmount(destinationAmount)}};
|
||||
destination: {amount: parseAmount(destinationAmount)}}
|
||||
|
||||
return {
|
||||
source: createAdjustment(sourceAddress, amounts.source),
|
||||
destination: createAdjustment(destinationAddress, amounts.destination),
|
||||
paths: JSON.stringify(parsePaths(alternative.paths_computed))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function parsePathfind(pathfindResult: RippledPathsResponse): GetPaths {
|
||||
const sourceAddress = pathfindResult.source_account;
|
||||
const destinationAddress = pathfindResult.destination_account;
|
||||
const destinationAmount = pathfindResult.destination_amount;
|
||||
const sourceAddress = pathfindResult.source_account
|
||||
const destinationAddress = pathfindResult.destination_account
|
||||
const destinationAmount = pathfindResult.destination_amount
|
||||
return pathfindResult.alternatives.map(_.partial(parseAlternative,
|
||||
sourceAddress, destinationAddress, destinationAmount));
|
||||
sourceAddress, destinationAddress, destinationAmount))
|
||||
}
|
||||
|
||||
module.exports = parsePathfind;
|
||||
module.exports = parsePathfind
|
||||
|
||||
22
src/ledger/parse/payment-channel-claim.js
Normal file
22
src/ledger/parse/payment-channel-claim.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parseAmount = require('./amount')
|
||||
const claimFlags = utils.txFlags.PaymentChannelClaim
|
||||
|
||||
function parsePaymentChannelClaim(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'PaymentChannelClaim')
|
||||
|
||||
return utils.removeUndefined({
|
||||
channel: tx.Channel,
|
||||
balance: tx.Balance && parseAmount(tx.Balance).value,
|
||||
amount: tx.Amount && parseAmount(tx.Amount).value,
|
||||
signature: tx.Signature,
|
||||
publicKey: tx.PublicKey,
|
||||
renew: Boolean(tx.Flags & claimFlags.Renew) || undefined,
|
||||
close: Boolean(tx.Flags & claimFlags.Close) || undefined
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parsePaymentChannelClaim
|
||||
21
src/ledger/parse/payment-channel-create.js
Normal file
21
src/ledger/parse/payment-channel-create.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parseAmount = require('./amount')
|
||||
|
||||
function parsePaymentChannelCreate(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'PaymentChannelCreate')
|
||||
|
||||
return utils.removeUndefined({
|
||||
amount: parseAmount(tx.Amount).value,
|
||||
destination: tx.Destination,
|
||||
settleDelay: tx.SettleDelay,
|
||||
publicKey: tx.PublicKey,
|
||||
cancelAfter: tx.CancelAfter && utils.parseTimestamp(tx.CancelAfter),
|
||||
sourceTag: tx.SourceTag,
|
||||
destinationTag: tx.DestinationTag
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parsePaymentChannelCreate
|
||||
17
src/ledger/parse/payment-channel-fund.js
Normal file
17
src/ledger/parse/payment-channel-fund.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parseAmount = require('./amount')
|
||||
|
||||
function parsePaymentChannelFund(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'PaymentChannelFund')
|
||||
|
||||
return utils.removeUndefined({
|
||||
channel: tx.Channel,
|
||||
amount: parseAmount(tx.Amount).value,
|
||||
expiration: tx.Expiration && utils.parseTimestamp(tx.Expiration)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parsePaymentChannelFund
|
||||
@@ -1,39 +1,39 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parseAmount = require('./amount');
|
||||
const txFlags = utils.txFlags;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parseAmount = require('./amount')
|
||||
const txFlags = utils.txFlags
|
||||
|
||||
function isNoDirectRipple(tx) {
|
||||
return (tx.Flags & txFlags.Payment.NoRippleDirect) !== 0;
|
||||
return (tx.Flags & txFlags.Payment.NoRippleDirect) !== 0
|
||||
}
|
||||
|
||||
function isQualityLimited(tx) {
|
||||
return (tx.Flags & txFlags.Payment.LimitQuality) !== 0;
|
||||
return (tx.Flags & txFlags.Payment.LimitQuality) !== 0
|
||||
}
|
||||
|
||||
function removeGenericCounterparty(amount, address) {
|
||||
return amount.counterparty === address ?
|
||||
_.omit(amount, 'counterparty') : amount;
|
||||
_.omit(amount, 'counterparty') : amount
|
||||
}
|
||||
|
||||
function parsePayment(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'Payment');
|
||||
assert(tx.TransactionType === 'Payment')
|
||||
|
||||
const source = {
|
||||
address: tx.Account,
|
||||
maxAmount: removeGenericCounterparty(
|
||||
parseAmount(tx.SendMax || tx.Amount), tx.Account),
|
||||
tag: tx.SourceTag
|
||||
};
|
||||
}
|
||||
|
||||
const destination = {
|
||||
address: tx.Destination,
|
||||
amount: removeGenericCounterparty(parseAmount(tx.Amount), tx.Destination),
|
||||
tag: tx.DestinationTag
|
||||
};
|
||||
}
|
||||
|
||||
return utils.removeUndefined({
|
||||
source: utils.removeUndefined(source),
|
||||
@@ -44,7 +44,7 @@ function parsePayment(tx: Object): Object {
|
||||
allowPartialPayment: utils.isPartialPayment(tx) || undefined,
|
||||
noDirectRipple: isNoDirectRipple(tx) || undefined,
|
||||
limitQuality: isQualityLimited(tx) || undefined
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parsePayment;
|
||||
module.exports = parsePayment
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const AccountFlags = require('./utils').constants.AccountFlags;
|
||||
const parseFields = require('./fields');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const assert = require('assert')
|
||||
const AccountFlags = require('./utils').constants.AccountFlags
|
||||
const parseFields = require('./fields')
|
||||
|
||||
function getAccountRootModifiedNode(tx: Object) {
|
||||
const modifiedNodes = tx.meta.AffectedNodes.filter(node =>
|
||||
node.ModifiedNode.LedgerEntryType === 'AccountRoot');
|
||||
assert(modifiedNodes.length === 1);
|
||||
return modifiedNodes[0].ModifiedNode;
|
||||
node.ModifiedNode.LedgerEntryType === 'AccountRoot')
|
||||
assert(modifiedNodes.length === 1)
|
||||
return modifiedNodes[0].ModifiedNode
|
||||
}
|
||||
|
||||
function parseFlags(tx: Object) {
|
||||
const settings = {};
|
||||
const settings = {}
|
||||
if (tx.TransactionType !== 'AccountSet') {
|
||||
return settings;
|
||||
return settings
|
||||
}
|
||||
|
||||
const node = getAccountRootModifiedNode(tx);
|
||||
const oldFlags = _.get(node.PreviousFields, 'Flags');
|
||||
const newFlags = _.get(node.FinalFields, 'Flags');
|
||||
const node = getAccountRootModifiedNode(tx)
|
||||
const oldFlags = _.get(node.PreviousFields, 'Flags')
|
||||
const newFlags = _.get(node.FinalFields, 'Flags')
|
||||
|
||||
if (oldFlags !== undefined && newFlags !== undefined) {
|
||||
const changedFlags = oldFlags ^ newFlags;
|
||||
const setFlags = newFlags & changedFlags;
|
||||
const clearedFlags = oldFlags & changedFlags;
|
||||
const changedFlags = oldFlags ^ newFlags
|
||||
const setFlags = newFlags & changedFlags
|
||||
const clearedFlags = oldFlags & changedFlags
|
||||
_.forEach(AccountFlags, (flagValue, flagName) => {
|
||||
if (setFlags & flagValue) {
|
||||
settings[flagName] = true;
|
||||
settings[flagName] = true
|
||||
} else if (clearedFlags & flagValue) {
|
||||
settings[flagName] = false;
|
||||
settings[flagName] = false
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// enableTransactionIDTracking requires a special case because it
|
||||
// does not affect the Flags field; instead it adds/removes a field called
|
||||
// "AccountTxnID" to/from the account root.
|
||||
|
||||
const oldField = _.get(node.PreviousFields, 'AccountTxnID');
|
||||
const newField = _.get(node.FinalFields, 'AccountTxnID');
|
||||
const oldField = _.get(node.PreviousFields, 'AccountTxnID')
|
||||
const newField = _.get(node.FinalFields, 'AccountTxnID')
|
||||
if (newField && !oldField) {
|
||||
settings.enableTransactionIDTracking = true;
|
||||
settings.enableTransactionIDTracking = true
|
||||
} else if (oldField && !newField) {
|
||||
settings.enableTransactionIDTracking = false;
|
||||
settings.enableTransactionIDTracking = false
|
||||
}
|
||||
|
||||
return settings;
|
||||
return settings
|
||||
}
|
||||
|
||||
function parseSettings(tx: Object) {
|
||||
const txType = tx.TransactionType;
|
||||
const txType = tx.TransactionType
|
||||
assert(txType === 'AccountSet' || txType === 'SetRegularKey' ||
|
||||
txType === 'SignerListSet');
|
||||
txType === 'SignerListSet')
|
||||
|
||||
return _.assign({}, parseFlags(tx), parseFields(tx));
|
||||
return _.assign({}, parseFlags(tx), parseFields(tx))
|
||||
}
|
||||
|
||||
module.exports = parseSettings;
|
||||
module.exports = parseSettings
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
|
||||
function parseSuspendedPaymentCancellation(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'SuspendedPaymentCancel');
|
||||
|
||||
return utils.removeUndefined({
|
||||
memos: utils.parseMemos(tx),
|
||||
owner: tx.Owner,
|
||||
suspensionSequence: tx.OfferSequence
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = parseSuspendedPaymentCancellation;
|
||||
@@ -1,39 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parseAmount = require('./amount');
|
||||
|
||||
function removeGenericCounterparty(amount, address) {
|
||||
return amount.counterparty === address ?
|
||||
_.omit(amount, 'counterparty') : amount;
|
||||
}
|
||||
|
||||
function parseSuspendedPaymentCreation(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'SuspendedPaymentCreate');
|
||||
|
||||
const source = {
|
||||
address: tx.Account,
|
||||
maxAmount: removeGenericCounterparty(
|
||||
parseAmount(tx.SendMax || tx.Amount), tx.Account),
|
||||
tag: tx.SourceTag
|
||||
};
|
||||
|
||||
const destination = {
|
||||
address: tx.Destination,
|
||||
amount: removeGenericCounterparty(parseAmount(tx.Amount), tx.Destination),
|
||||
tag: tx.DestinationTag
|
||||
};
|
||||
|
||||
return utils.removeUndefined({
|
||||
source: utils.removeUndefined(source),
|
||||
destination: utils.removeUndefined(destination),
|
||||
memos: utils.parseMemos(tx),
|
||||
digest: tx.Digest,
|
||||
allowCancelAfter: utils.parseTimestamp(tx.CancelAfter),
|
||||
allowExecuteAfter: utils.parseTimestamp(tx.FinishAfter)
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = parseSuspendedPaymentCreation;
|
||||
@@ -1,19 +0,0 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
|
||||
function parseSuspendedPaymentExecution(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'SuspendedPaymentFinish');
|
||||
|
||||
return utils.removeUndefined({
|
||||
memos: utils.parseMemos(tx),
|
||||
owner: tx.Owner,
|
||||
suspensionSequence: tx.OfferSequence,
|
||||
method: tx.Method,
|
||||
digest: tx.Digest,
|
||||
proof: tx.Proof ? utils.hexToString(tx.Proof) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = parseSuspendedPaymentExecution;
|
||||
@@ -1,18 +1,20 @@
|
||||
/* @flow */
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const parsePayment = require('./payment');
|
||||
const parseTrustline = require('./trustline');
|
||||
const parseOrder = require('./order');
|
||||
const parseOrderCancellation = require('./cancellation');
|
||||
const parseSettings = require('./settings');
|
||||
const parseSuspendedPaymentCreation = require('./suspended-payment-creation');
|
||||
const parseSuspendedPaymentExecution = require('./suspended-payment-execution');
|
||||
const parseSuspendedPaymentCancellation =
|
||||
require('./suspended-payment-cancellation');
|
||||
const parseFeeUpdate = require('./fee-update');
|
||||
const parseAmendment = require('./amendment');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const parsePayment = require('./payment')
|
||||
const parseTrustline = require('./trustline')
|
||||
const parseOrder = require('./order')
|
||||
const parseOrderCancellation = require('./cancellation')
|
||||
const parseSettings = require('./settings')
|
||||
const parseEscrowCreation = require('./escrow-creation')
|
||||
const parseEscrowExecution = require('./escrow-execution')
|
||||
const parseEscrowCancellation = require('./escrow-cancellation')
|
||||
const parsePaymentChannelCreate = require('./payment-channel-create')
|
||||
const parsePaymentChannelFund = require('./payment-channel-fund')
|
||||
const parsePaymentChannelClaim = require('./payment-channel-claim')
|
||||
const parseFeeUpdate = require('./fee-update')
|
||||
const parseAmendment = require('./amendment')
|
||||
|
||||
function parseTransactionType(type) {
|
||||
const mapping = {
|
||||
@@ -22,34 +24,40 @@ function parseTransactionType(type) {
|
||||
OfferCancel: 'orderCancellation',
|
||||
AccountSet: 'settings',
|
||||
SetRegularKey: 'settings',
|
||||
SuspendedPaymentCreate: 'suspendedPaymentCreation',
|
||||
SuspendedPaymentFinish: 'suspendedPaymentExecution',
|
||||
SuspendedPaymentCancel: 'suspendedPaymentCancellation',
|
||||
EscrowCreate: 'escrowCreation',
|
||||
EscrowFinish: 'escrowExecution',
|
||||
EscrowCancel: 'escrowCancellation',
|
||||
PaymentChannelCreate: 'paymentChannelCreate',
|
||||
PaymentChannelFund: 'paymentChannelFund',
|
||||
PaymentChannelClaim: 'paymentChannelClaim',
|
||||
SignerListSet: 'settings',
|
||||
SetFee: 'feeUpdate', // pseudo-transaction
|
||||
EnableAmendment: 'amendment' // pseudo-transaction
|
||||
};
|
||||
return mapping[type] || null;
|
||||
}
|
||||
return mapping[type] || null
|
||||
}
|
||||
|
||||
function parseTransaction(tx: Object): Object {
|
||||
const type = parseTransactionType(tx.TransactionType);
|
||||
const type = parseTransactionType(tx.TransactionType)
|
||||
const mapping = {
|
||||
'payment': parsePayment,
|
||||
'trustline': parseTrustline,
|
||||
'order': parseOrder,
|
||||
'orderCancellation': parseOrderCancellation,
|
||||
'settings': parseSettings,
|
||||
'suspendedPaymentCreation': parseSuspendedPaymentCreation,
|
||||
'suspendedPaymentExecution': parseSuspendedPaymentExecution,
|
||||
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation,
|
||||
'escrowCreation': parseEscrowCreation,
|
||||
'escrowExecution': parseEscrowExecution,
|
||||
'escrowCancellation': parseEscrowCancellation,
|
||||
'paymentChannelCreate': parsePaymentChannelCreate,
|
||||
'paymentChannelFund': parsePaymentChannelFund,
|
||||
'paymentChannelClaim': parsePaymentChannelClaim,
|
||||
'feeUpdate': parseFeeUpdate,
|
||||
'amendment': parseAmendment
|
||||
};
|
||||
const parser = mapping[type];
|
||||
assert(parser !== undefined, 'Unrecognized transaction type');
|
||||
const specification = parser(tx);
|
||||
const outcome = utils.parseOutcome(tx);
|
||||
}
|
||||
const parser = mapping[type]
|
||||
assert(parser !== undefined, 'Unrecognized transaction type')
|
||||
const specification = parser(tx)
|
||||
const outcome = utils.parseOutcome(tx)
|
||||
return utils.removeUndefined({
|
||||
type: type,
|
||||
address: tx.Account,
|
||||
@@ -57,7 +65,7 @@ function parseTransaction(tx: Object): Object {
|
||||
id: tx.hash,
|
||||
specification: utils.removeUndefined(specification),
|
||||
outcome: outcome ? utils.removeUndefined(outcome) : undefined
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parseTransaction;
|
||||
module.exports = parseTransaction
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const utils = require('./utils');
|
||||
const flags = utils.txFlags.TrustSet;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const assert = require('assert')
|
||||
const utils = require('./utils')
|
||||
const flags = utils.txFlags.TrustSet
|
||||
|
||||
function parseFlag(flagsValue, trueValue, falseValue) {
|
||||
if (flagsValue & trueValue) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
if (flagsValue & falseValue) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
function parseTrustline(tx: Object): Object {
|
||||
assert(tx.TransactionType === 'TrustSet');
|
||||
assert(tx.TransactionType === 'TrustSet')
|
||||
|
||||
return utils.removeUndefined({
|
||||
limit: tx.LimitAmount.value,
|
||||
@@ -27,7 +27,7 @@ function parseTrustline(tx: Object): Object {
|
||||
tx.Flags, flags.SetNoRipple, flags.ClearNoRipple),
|
||||
frozen: parseFlag(tx.Flags, flags.SetFreeze, flags.ClearFreeze),
|
||||
authorized: parseFlag(tx.Flags, flags.SetAuth, 0)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = parseTrustline;
|
||||
module.exports = parseTrustline
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
/* @flow */
|
||||
'use strict'; // eslint-disable-line
|
||||
const _ = require('lodash');
|
||||
const transactionParser = require('ripple-lib-transactionparser');
|
||||
const utils = require('../utils');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const parseAmount = require('./amount');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const transactionParser = require('ripple-lib-transactionparser')
|
||||
const utils = require('../utils')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const parseAmount = require('./amount')
|
||||
|
||||
import type {Amount} from '../common/types.js';
|
||||
import type {Amount} from '../common/types.js'
|
||||
|
||||
function adjustQualityForXRP(
|
||||
quality: string, takerGetsCurrency: string, takerPaysCurrency: string
|
||||
) {
|
||||
// quality = takerPays.value/takerGets.value
|
||||
// using drops (1e-6 XRP) for XRP values
|
||||
const numeratorShift = (takerPaysCurrency === 'XRP' ? -6 : 0);
|
||||
const denominatorShift = (takerGetsCurrency === 'XRP' ? -6 : 0);
|
||||
const shift = numeratorShift - denominatorShift;
|
||||
const numeratorShift = (takerPaysCurrency === 'XRP' ? -6 : 0)
|
||||
const denominatorShift = (takerGetsCurrency === 'XRP' ? -6 : 0)
|
||||
const shift = numeratorShift - denominatorShift
|
||||
return shift === 0 ? quality :
|
||||
(new BigNumber(quality)).shift(shift).toString();
|
||||
(new BigNumber(quality)).shift(shift).toString()
|
||||
}
|
||||
|
||||
function parseQuality(quality: ?number) {
|
||||
if (typeof quality === 'number') {
|
||||
return (new BigNumber(quality)).shift(-9).toNumber();
|
||||
return (new BigNumber(quality)).shift(-9).toNumber()
|
||||
}
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
function parseTimestamp(rippleTime: number): string | void {
|
||||
return rippleTime ? utils.common.rippleTimeToISO8601(rippleTime) : undefined;
|
||||
return rippleTime ? utils.common.rippleTimeToISO8601(rippleTime) : undefined
|
||||
}
|
||||
|
||||
function removeEmptyCounterparty(amount) {
|
||||
if (amount.counterparty === '') {
|
||||
delete amount.counterparty;
|
||||
delete amount.counterparty
|
||||
}
|
||||
}
|
||||
|
||||
function removeEmptyCounterpartyInBalanceChanges(balanceChanges) {
|
||||
_.forEach(balanceChanges, changes => {
|
||||
_.forEach(changes, removeEmptyCounterparty);
|
||||
});
|
||||
_.forEach(changes, removeEmptyCounterparty)
|
||||
})
|
||||
}
|
||||
|
||||
function removeEmptyCounterpartyInOrderbookChanges(orderbookChanges) {
|
||||
_.forEach(orderbookChanges, changes => {
|
||||
_.forEach(changes, change => {
|
||||
_.forEach(change, removeEmptyCounterparty);
|
||||
});
|
||||
});
|
||||
_.forEach(change, removeEmptyCounterparty)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function isPartialPayment(tx) {
|
||||
return (tx.Flags & utils.common.txFlags.Payment.PartialPayment) !== 0;
|
||||
return (tx.Flags & utils.common.txFlags.Payment.PartialPayment) !== 0
|
||||
}
|
||||
|
||||
function parseDeliveredAmount(tx: Object): Amount | void {
|
||||
|
||||
if (tx.TransactionType !== 'Payment' ||
|
||||
tx.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (tx.meta.delivered_amount &&
|
||||
tx.meta.delivered_amount === 'unavailable') {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
// parsable delivered_amount
|
||||
if (tx.meta.delivered_amount) {
|
||||
return parseAmount(tx.meta.delivered_amount);
|
||||
return parseAmount(tx.meta.delivered_amount)
|
||||
}
|
||||
|
||||
// DeliveredAmount only present on partial payments
|
||||
if (tx.meta.DeliveredAmount) {
|
||||
return parseAmount(tx.meta.DeliveredAmount);
|
||||
return parseAmount(tx.meta.DeliveredAmount)
|
||||
}
|
||||
|
||||
// no partial payment flag, use tx.Amount
|
||||
if (tx.Amount && !isPartialPayment(tx)) {
|
||||
return parseAmount(tx.Amount);
|
||||
return parseAmount(tx.Amount)
|
||||
}
|
||||
|
||||
// DeliveredAmount field was introduced at
|
||||
@@ -89,21 +89,21 @@ function parseDeliveredAmount(tx: Object): Amount | void {
|
||||
// transferred with a partial payment before
|
||||
// that date must be derived from metadata.
|
||||
if (tx.Amount && tx.ledger_index > 4594094) {
|
||||
return parseAmount(tx.Amount);
|
||||
return parseAmount(tx.Amount)
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
function parseOutcome(tx: Object): ?Object {
|
||||
const metadata = tx.meta || tx.metaData;
|
||||
const metadata = tx.meta || tx.metaData
|
||||
if (!metadata) {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
const balanceChanges = transactionParser.parseBalanceChanges(metadata);
|
||||
const orderbookChanges = transactionParser.parseOrderbookChanges(metadata);
|
||||
removeEmptyCounterpartyInBalanceChanges(balanceChanges);
|
||||
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges);
|
||||
const balanceChanges = transactionParser.parseBalanceChanges(metadata)
|
||||
const orderbookChanges = transactionParser.parseOrderbookChanges(metadata)
|
||||
removeEmptyCounterpartyInBalanceChanges(balanceChanges)
|
||||
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges)
|
||||
|
||||
return utils.common.removeUndefined({
|
||||
result: tx.meta.TransactionResult,
|
||||
@@ -114,24 +114,24 @@ function parseOutcome(tx: Object): ?Object {
|
||||
ledgerVersion: tx.ledger_index,
|
||||
indexInLedger: tx.meta.TransactionIndex,
|
||||
deliveredAmount: parseDeliveredAmount(tx)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function hexToString(hex: string): ?string {
|
||||
return hex ? new Buffer(hex, 'hex').toString('utf-8') : undefined;
|
||||
return hex ? new Buffer(hex, 'hex').toString('utf-8') : undefined
|
||||
}
|
||||
|
||||
function parseMemos(tx: Object): ?Array<Object> {
|
||||
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
return tx.Memos.map(m => {
|
||||
return utils.common.removeUndefined({
|
||||
type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType),
|
||||
format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat),
|
||||
data: m.Memo.parsed_memo_data || hexToString(m.Memo.MemoData)
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -147,4 +147,4 @@ module.exports = {
|
||||
txFlags: utils.common.txFlags,
|
||||
removeUndefined: utils.common.removeUndefined,
|
||||
rippleTimeToISO8601: utils.common.rippleTimeToISO8601
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
import type {Amount, LaxLaxAmount, RippledAmount, Adjustment, MaxAdjustment,
|
||||
MinAdjustment} from '../common/types.js';
|
||||
MinAdjustment} from '../common/types.js'
|
||||
|
||||
|
||||
type Path = {
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const utils = require('./utils');
|
||||
const parsePathfind = require('./parse/pathfind');
|
||||
const {validate, toRippledAmount} = utils.common;
|
||||
const NotFoundError = utils.common.errors.NotFoundError;
|
||||
const ValidationError = utils.common.errors.ValidationError;
|
||||
import type {Connection} from '../common/connection';
|
||||
import type {RippledAmount} from '../common/types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const utils = require('./utils')
|
||||
const parsePathfind = require('./parse/pathfind')
|
||||
const {validate, toRippledAmount} = utils.common
|
||||
const NotFoundError = utils.common.errors.NotFoundError
|
||||
const ValidationError = utils.common.errors.ValidationError
|
||||
import type {Connection} from '../common/connection'
|
||||
import type {RippledAmount} from '../common/types.js'
|
||||
import type {GetPaths, PathFind, RippledPathsResponse, PathFindRequest}
|
||||
from './pathfind-types.js';
|
||||
from './pathfind-types.js'
|
||||
|
||||
|
||||
function addParams(request: PathFindRequest, result: RippledPathsResponse) {
|
||||
return _.defaults(_.assign({}, result, {
|
||||
source_account: request.source_account,
|
||||
source_currencies: request.source_currencies
|
||||
}), {destination_amount: request.destination_amount});
|
||||
}), {destination_amount: request.destination_amount})
|
||||
}
|
||||
|
||||
function requestPathFind(connection: Connection, pathfind: PathFind): Promise {
|
||||
const destinationAmount = _.assign({value: -1}, pathfind.destination.amount);
|
||||
const destinationAmount = _.assign({value: -1}, pathfind.destination.amount)
|
||||
const request: PathFindRequest = {
|
||||
command: 'ripple_path_find',
|
||||
source_account: pathfind.source.address,
|
||||
destination_account: pathfind.destination.address,
|
||||
destination_amount: toRippledAmount(destinationAmount)
|
||||
};
|
||||
}
|
||||
if (typeof request.destination_amount === 'object'
|
||||
&& !request.destination_amount.issuer) {
|
||||
// Convert blank issuer to sender's address
|
||||
@@ -35,43 +35,43 @@ function requestPathFind(connection: Connection, pathfind: PathFind): Promise {
|
||||
// https://ripple.com/build/transactions/
|
||||
// #special-issuer-values-for-sendmax-and-amount
|
||||
// https://ripple.com/build/ripple-rest/#counterparties-in-payments
|
||||
request.destination_amount.issuer = request.destination_account;
|
||||
request.destination_amount.issuer = request.destination_account
|
||||
}
|
||||
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
|
||||
request.source_currencies = pathfind.source.currencies.map(amount =>
|
||||
_.omit(toRippledAmount(amount), 'value'));
|
||||
_.omit(toRippledAmount(amount), 'value'))
|
||||
}
|
||||
if (pathfind.source.amount) {
|
||||
if (pathfind.destination.amount.value !== undefined) {
|
||||
throw new ValidationError('Cannot specify both source.amount'
|
||||
+ ' and destination.amount.value in getPaths');
|
||||
+ ' and destination.amount.value in getPaths')
|
||||
}
|
||||
request.send_max = toRippledAmount(pathfind.source.amount);
|
||||
request.send_max = toRippledAmount(pathfind.source.amount)
|
||||
if (request.send_max.currency && !request.send_max.issuer) {
|
||||
request.send_max.issuer = pathfind.source.address;
|
||||
request.send_max.issuer = pathfind.source.address
|
||||
}
|
||||
}
|
||||
|
||||
return connection.request(request).then(paths => addParams(request, paths));
|
||||
return connection.request(request).then(paths => addParams(request, paths))
|
||||
}
|
||||
|
||||
function addDirectXrpPath(paths: RippledPathsResponse, xrpBalance: string
|
||||
): RippledPathsResponse {
|
||||
// Add XRP "path" only if the source acct has enough XRP to make the payment
|
||||
const destinationAmount = paths.destination_amount;
|
||||
const destinationAmount = paths.destination_amount
|
||||
if ((new BigNumber(xrpBalance)).greaterThanOrEqualTo(destinationAmount)) {
|
||||
paths.alternatives.unshift({
|
||||
paths_computed: [],
|
||||
source_amount: paths.destination_amount
|
||||
});
|
||||
})
|
||||
}
|
||||
return paths;
|
||||
return paths
|
||||
}
|
||||
|
||||
function isRippledIOUAmount(amount: RippledAmount) {
|
||||
// rippled XRP amounts are specified as decimal strings
|
||||
return (typeof amount === 'object') &&
|
||||
amount.currency && (amount.currency !== 'XRP');
|
||||
amount.currency && (amount.currency !== 'XRP')
|
||||
}
|
||||
|
||||
function conditionallyAddDirectXRPPath(connection: Connection, address: string,
|
||||
@@ -79,10 +79,10 @@ function conditionallyAddDirectXRPPath(connection: Connection, address: string,
|
||||
): Promise {
|
||||
if (isRippledIOUAmount(paths.destination_amount)
|
||||
|| !_.includes(paths.destination_currencies, 'XRP')) {
|
||||
return Promise.resolve(paths);
|
||||
return Promise.resolve(paths)
|
||||
}
|
||||
return utils.getXRPBalance(connection, address, undefined).then(
|
||||
xrpBalance => addDirectXrpPath(paths, xrpBalance));
|
||||
xrpBalance => addDirectXrpPath(paths, xrpBalance))
|
||||
}
|
||||
|
||||
function filterSourceFundsLowPaths(pathfind: PathFind,
|
||||
@@ -93,15 +93,15 @@ function filterSourceFundsLowPaths(pathfind: PathFind,
|
||||
paths.alternatives = _.filter(paths.alternatives, alt => {
|
||||
return alt.source_amount &&
|
||||
pathfind.source.amount &&
|
||||
new BigNumber(alt.source_amount.value).eq(pathfind.source.amount.value);
|
||||
});
|
||||
new BigNumber(alt.source_amount.value).eq(pathfind.source.amount.value)
|
||||
})
|
||||
}
|
||||
return paths;
|
||||
return paths
|
||||
}
|
||||
|
||||
function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
||||
if (paths.alternatives && paths.alternatives.length > 0) {
|
||||
return parsePathfind(paths);
|
||||
return parsePathfind(paths)
|
||||
}
|
||||
if (paths.destination_currencies !== undefined &&
|
||||
!_.includes(paths.destination_currencies,
|
||||
@@ -109,30 +109,30 @@ function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
||||
throw new NotFoundError('No paths found. ' +
|
||||
'The destination_account does not accept ' +
|
||||
pathfind.destination.amount.currency + ', they only accept: ' +
|
||||
paths.destination_currencies.join(', '));
|
||||
paths.destination_currencies.join(', '))
|
||||
} else if (paths.source_currencies && paths.source_currencies.length > 0) {
|
||||
throw new NotFoundError('No paths found. Please ensure' +
|
||||
' that the source_account has sufficient funds to execute' +
|
||||
' the payment in one of the specified source_currencies. If it does' +
|
||||
' there may be insufficient liquidity in the network to execute' +
|
||||
' this payment right now');
|
||||
' this payment right now')
|
||||
} else {
|
||||
throw new NotFoundError('No paths found.' +
|
||||
' Please ensure that the source_account has sufficient funds to' +
|
||||
' execute the payment. If it does there may be insufficient liquidity' +
|
||||
' in the network to execute this payment right now');
|
||||
' in the network to execute this payment right now')
|
||||
}
|
||||
}
|
||||
|
||||
function getPaths(pathfind: PathFind): Promise<GetPaths> {
|
||||
validate.getPaths({pathfind});
|
||||
validate.getPaths({pathfind})
|
||||
|
||||
const address = pathfind.source.address;
|
||||
const address = pathfind.source.address
|
||||
return requestPathFind(this.connection, pathfind).then(paths =>
|
||||
conditionallyAddDirectXRPPath(this.connection, address, paths)
|
||||
)
|
||||
.then(paths => filterSourceFundsLowPaths(pathfind, paths))
|
||||
.then(paths => formatResponse(pathfind, paths));
|
||||
.then(paths => formatResponse(pathfind, paths))
|
||||
}
|
||||
|
||||
module.exports = getPaths;
|
||||
module.exports = getPaths
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const parseFields = require('./parse/fields');
|
||||
const {validate} = utils.common;
|
||||
const AccountFlags = utils.common.constants.AccountFlags;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const parseFields = require('./parse/fields')
|
||||
const {validate} = utils.common
|
||||
const AccountFlags = utils.common.constants.AccountFlags
|
||||
|
||||
type SettingsOptions = {
|
||||
ledgerVersion?: number
|
||||
@@ -29,33 +29,33 @@ type GetSettings = {
|
||||
|
||||
|
||||
function parseFlags(value) {
|
||||
const settings = {};
|
||||
const settings = {}
|
||||
for (const flagName in AccountFlags) {
|
||||
if (value & AccountFlags[flagName]) {
|
||||
settings[flagName] = true;
|
||||
settings[flagName] = true
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
return settings
|
||||
}
|
||||
|
||||
function formatSettings(response) {
|
||||
const data = response.account_data;
|
||||
const parsedFlags = parseFlags(data.Flags);
|
||||
const parsedFields = parseFields(data);
|
||||
return _.assign({}, parsedFlags, parsedFields);
|
||||
const data = response.account_data
|
||||
const parsedFlags = parseFlags(data.Flags)
|
||||
const parsedFields = parseFields(data)
|
||||
return _.assign({}, parsedFlags, parsedFields)
|
||||
}
|
||||
|
||||
function getSettings(address: string, options: SettingsOptions = {}
|
||||
): Promise<GetSettings> {
|
||||
validate.getSettings({address, options});
|
||||
validate.getSettings({address, options})
|
||||
|
||||
const request = {
|
||||
command: 'account_info',
|
||||
account: address,
|
||||
ledger_index: options.ledgerVersion || 'validated'
|
||||
};
|
||||
}
|
||||
|
||||
return this.connection.request(request).then(formatSettings);
|
||||
return this.connection.request(request).then(formatSettings)
|
||||
}
|
||||
|
||||
module.exports = getSettings;
|
||||
module.exports = getSettings
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
import type {Amount, Memo} from '../common/types.js';
|
||||
import type {Amount, Memo} from '../common/types.js'
|
||||
|
||||
type Outcome = {
|
||||
result: string,
|
||||
|
||||
@@ -1,57 +1,57 @@
|
||||
/* @flow */
|
||||
'use strict'; // eslint-disable-line strict
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const parseTransaction = require('./parse/transaction');
|
||||
const {validate, errors} = utils.common;
|
||||
import type {Connection} from '../common/connection.js';
|
||||
import type {TransactionType, TransactionOptions} from './transaction-types';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const parseTransaction = require('./parse/transaction')
|
||||
const {validate, errors} = utils.common
|
||||
import type {Connection} from '../common/connection.js'
|
||||
import type {TransactionType, TransactionOptions} from './transaction-types'
|
||||
|
||||
function attachTransactionDate(connection: Connection, tx: Object
|
||||
): Promise<TransactionType> {
|
||||
if (tx.date) {
|
||||
return Promise.resolve(tx);
|
||||
return Promise.resolve(tx)
|
||||
}
|
||||
|
||||
const ledgerVersion = tx.ledger_index || tx.LedgerSequence;
|
||||
const ledgerVersion = tx.ledger_index || tx.LedgerSequence
|
||||
|
||||
if (!ledgerVersion) {
|
||||
return new Promise(() => {
|
||||
throw new errors.NotFoundError(
|
||||
'ledger_index and LedgerSequence not found in tx');
|
||||
});
|
||||
'ledger_index and LedgerSequence not found in tx')
|
||||
})
|
||||
}
|
||||
|
||||
const request = {
|
||||
command: 'ledger',
|
||||
ledger_index: ledgerVersion
|
||||
};
|
||||
}
|
||||
|
||||
return connection.request(request).then(data => {
|
||||
if (typeof data.ledger.close_time === 'number') {
|
||||
return _.assign({date: data.ledger.close_time}, tx);
|
||||
return _.assign({date: data.ledger.close_time}, tx)
|
||||
}
|
||||
throw new errors.UnexpectedError('Ledger missing close_time');
|
||||
throw new errors.UnexpectedError('Ledger missing close_time')
|
||||
}).catch(error => {
|
||||
if (error instanceof errors.UnexpectedError) {
|
||||
throw error;
|
||||
throw error
|
||||
}
|
||||
throw new errors.NotFoundError('Transaction ledger not found');
|
||||
});
|
||||
throw new errors.NotFoundError('Transaction ledger not found')
|
||||
})
|
||||
}
|
||||
|
||||
function isTransactionInRange(tx: Object, options: TransactionOptions) {
|
||||
return (!options.minLedgerVersion
|
||||
|| tx.ledger_index >= options.minLedgerVersion)
|
||||
&& (!options.maxLedgerVersion
|
||||
|| tx.ledger_index <= options.maxLedgerVersion);
|
||||
|| tx.ledger_index <= options.maxLedgerVersion)
|
||||
}
|
||||
|
||||
function convertError(connection: Connection, options: TransactionOptions,
|
||||
error: Error
|
||||
): Promise<Error> {
|
||||
const _error = (error.message === 'txnNotFound') ?
|
||||
new errors.NotFoundError('Transaction not found') : error;
|
||||
new errors.NotFoundError('Transaction not found') : error
|
||||
if (_error instanceof errors.NotFoundError) {
|
||||
return utils.hasCompleteLedgerRange(connection, options.minLedgerVersion,
|
||||
options.maxLedgerVersion).then(hasCompleteLedgerRange => {
|
||||
@@ -61,32 +61,32 @@ function convertError(connection: Connection, options: TransactionOptions,
|
||||
.then(isPendingLedgerVersion => {
|
||||
return isPendingLedgerVersion ?
|
||||
new errors.PendingLedgerVersionError() :
|
||||
new errors.MissingLedgerHistoryError();
|
||||
});
|
||||
new errors.MissingLedgerHistoryError()
|
||||
})
|
||||
}
|
||||
return _error;
|
||||
});
|
||||
return _error
|
||||
})
|
||||
}
|
||||
return Promise.resolve(_error);
|
||||
return Promise.resolve(_error)
|
||||
}
|
||||
|
||||
function formatResponse(options: TransactionOptions, tx: TransactionType
|
||||
): TransactionType {
|
||||
if (tx.validated !== true || !isTransactionInRange(tx, options)) {
|
||||
throw new errors.NotFoundError('Transaction not found');
|
||||
throw new errors.NotFoundError('Transaction not found')
|
||||
}
|
||||
return parseTransaction(tx);
|
||||
return parseTransaction(tx)
|
||||
}
|
||||
|
||||
function getTransaction(id: string, options: TransactionOptions = {}
|
||||
): Promise<TransactionType> {
|
||||
validate.getTransaction({id, options});
|
||||
validate.getTransaction({id, options})
|
||||
|
||||
const request = {
|
||||
command: 'tx',
|
||||
transaction: id,
|
||||
binary: false
|
||||
};
|
||||
}
|
||||
|
||||
return utils.ensureLedgerVersion.call(this, options).then(_options => {
|
||||
return this.connection.request(request).then(tx =>
|
||||
@@ -94,10 +94,10 @@ function getTransaction(id: string, options: TransactionOptions = {}
|
||||
).then(_.partial(formatResponse, _options))
|
||||
.catch(error => {
|
||||
return convertError(this.connection, _options, error).then(_error => {
|
||||
throw _error;
|
||||
});
|
||||
});
|
||||
});
|
||||
throw _error
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = getTransaction;
|
||||
module.exports = getTransaction
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/* @flow */
|
||||
/* eslint-disable max-params */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const binary = require('ripple-binary-codec');
|
||||
const {computeTransactionHash} = require('ripple-hashes');
|
||||
const utils = require('./utils');
|
||||
const parseTransaction = require('./parse/transaction');
|
||||
const getTransaction = require('./transaction');
|
||||
const {validate} = utils.common;
|
||||
import type {Connection} from '../common/connection.js';
|
||||
import type {TransactionType} from './transaction-types';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const binary = require('ripple-binary-codec')
|
||||
const {computeTransactionHash} = require('ripple-hashes')
|
||||
const utils = require('./utils')
|
||||
const parseTransaction = require('./parse/transaction')
|
||||
const getTransaction = require('./transaction')
|
||||
const {validate} = utils.common
|
||||
import type {Connection} from '../common/connection.js'
|
||||
import type {TransactionType} from './transaction-types'
|
||||
|
||||
|
||||
type TransactionsOptions = {
|
||||
@@ -29,21 +29,21 @@ type TransactionsOptions = {
|
||||
type GetTransactionsResponse = Array<TransactionType>
|
||||
|
||||
function parseBinaryTransaction(transaction) {
|
||||
const tx = binary.decode(transaction.tx_blob);
|
||||
tx.hash = computeTransactionHash(tx);
|
||||
tx.ledger_index = transaction.ledger_index;
|
||||
const tx = binary.decode(transaction.tx_blob)
|
||||
tx.hash = computeTransactionHash(tx)
|
||||
tx.ledger_index = transaction.ledger_index
|
||||
return {
|
||||
tx: tx,
|
||||
meta: binary.decode(transaction.meta),
|
||||
validated: transaction.validated
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function parseAccountTxTransaction(tx) {
|
||||
const _tx = tx.tx_blob ? parseBinaryTransaction(tx) : tx;
|
||||
const _tx = tx.tx_blob ? parseBinaryTransaction(tx) : tx
|
||||
// rippled uses a different response format for 'account_tx' than 'tx'
|
||||
return parseTransaction(_.assign({}, _tx.tx,
|
||||
{meta: _tx.meta, validated: _tx.validated}));
|
||||
{meta: _tx.meta, validated: _tx.validated}))
|
||||
}
|
||||
|
||||
function counterpartyFilter(filters, tx: TransactionType) {
|
||||
@@ -53,36 +53,36 @@ function counterpartyFilter(filters, tx: TransactionType) {
|
||||
tx.specification.destination.address === filters.counterparty) ||
|
||||
(tx.specification.counterparty === filters.counterparty)
|
||||
))) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
function transactionFilter(address: string, filters: TransactionsOptions,
|
||||
tx: TransactionType
|
||||
) {
|
||||
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
if (filters.types && !_.includes(filters.types, tx.type)) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
if (filters.initiated === true && tx.address !== address) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
if (filters.initiated === false && tx.address === address) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
if (filters.counterparty && !counterpartyFilter(filters, tx)) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
function orderFilter(options: TransactionsOptions, tx: TransactionType) {
|
||||
return !options.startTx || (options.earliestFirst ?
|
||||
utils.compareTransactions(tx, options.startTx) > 0 :
|
||||
utils.compareTransactions(tx, options.startTx) < 0);
|
||||
utils.compareTransactions(tx, options.startTx) < 0)
|
||||
}
|
||||
|
||||
function formatPartialResponse(address: string,
|
||||
@@ -91,11 +91,11 @@ function formatPartialResponse(address: string,
|
||||
return {
|
||||
marker: data.marker,
|
||||
results: data.transactions
|
||||
.filter((tx) => tx.validated)
|
||||
.filter(tx => tx.validated)
|
||||
.map(parseAccountTxTransaction)
|
||||
.filter(_.partial(transactionFilter, address, options))
|
||||
.filter(_.partial(orderFilter, options))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getAccountTx(connection: Connection, address: string,
|
||||
@@ -112,70 +112,70 @@ function getAccountTx(connection: Connection, address: string,
|
||||
binary: options.binary,
|
||||
limit: utils.clamp(limit, 10, 400),
|
||||
marker: marker
|
||||
};
|
||||
}
|
||||
|
||||
return connection.request(request).then(response =>
|
||||
formatPartialResponse(address, options, response));
|
||||
formatPartialResponse(address, options, response))
|
||||
}
|
||||
|
||||
function checkForLedgerGaps(connection: Connection,
|
||||
options: TransactionsOptions, transactions: GetTransactionsResponse
|
||||
) {
|
||||
let {minLedgerVersion, maxLedgerVersion} = options;
|
||||
let {minLedgerVersion, maxLedgerVersion} = options
|
||||
|
||||
// if we reached the limit on number of transactions, then we can shrink
|
||||
// the required ledger range to only guarantee that there are no gaps in
|
||||
// the range of ledgers spanned by those transactions
|
||||
if (options.limit && transactions.length === options.limit) {
|
||||
if (options.earliestFirst) {
|
||||
maxLedgerVersion = _.last(transactions).outcome.ledgerVersion;
|
||||
maxLedgerVersion = _.last(transactions).outcome.ledgerVersion
|
||||
} else {
|
||||
minLedgerVersion = _.last(transactions).outcome.ledgerVersion;
|
||||
minLedgerVersion = _.last(transactions).outcome.ledgerVersion
|
||||
}
|
||||
}
|
||||
|
||||
return utils.hasCompleteLedgerRange(connection, minLedgerVersion,
|
||||
maxLedgerVersion).then(hasCompleteLedgerRange => {
|
||||
if (!hasCompleteLedgerRange) {
|
||||
throw new utils.common.errors.MissingLedgerHistoryError();
|
||||
throw new utils.common.errors.MissingLedgerHistoryError()
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function formatResponse(connection: Connection, options: TransactionsOptions,
|
||||
transactions: GetTransactionsResponse
|
||||
) {
|
||||
const compare = options.earliestFirst ? utils.compareTransactions :
|
||||
_.rearg(utils.compareTransactions, 1, 0);
|
||||
const sortedTransactions = transactions.sort(compare);
|
||||
_.rearg(utils.compareTransactions, 1, 0)
|
||||
const sortedTransactions = transactions.sort(compare)
|
||||
return checkForLedgerGaps(connection, options, sortedTransactions).then(
|
||||
() => sortedTransactions);
|
||||
() => sortedTransactions)
|
||||
}
|
||||
|
||||
function getTransactionsInternal(connection: Connection, address: string,
|
||||
options: TransactionsOptions
|
||||
): Promise<GetTransactionsResponse> {
|
||||
const getter = _.partial(getAccountTx, connection, address, options);
|
||||
const format = _.partial(formatResponse, connection, options);
|
||||
return utils.getRecursive(getter, options.limit).then(format);
|
||||
const getter = _.partial(getAccountTx, connection, address, options)
|
||||
const format = _.partial(formatResponse, connection, options)
|
||||
return utils.getRecursive(getter, options.limit).then(format)
|
||||
}
|
||||
|
||||
function getTransactions(address: string, options: TransactionsOptions = {}
|
||||
): Promise<GetTransactionsResponse> {
|
||||
validate.getTransactions({address, options});
|
||||
validate.getTransactions({address, options})
|
||||
|
||||
const defaults = {maxLedgerVersion: -1};
|
||||
const defaults = {maxLedgerVersion: -1}
|
||||
if (options.start) {
|
||||
return getTransaction.call(this, options.start).then(tx => {
|
||||
const ledgerVersion = tx.outcome.ledgerVersion;
|
||||
const ledgerVersion = tx.outcome.ledgerVersion
|
||||
const bound = options.earliestFirst ?
|
||||
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion};
|
||||
const newOptions = _.assign({}, defaults, options, {startTx: tx}, bound);
|
||||
return getTransactionsInternal(this.connection, address, newOptions);
|
||||
});
|
||||
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion}
|
||||
const newOptions = _.assign({}, defaults, options, {startTx: tx}, bound)
|
||||
return getTransactionsInternal(this.connection, address, newOptions)
|
||||
})
|
||||
}
|
||||
const newOptions = _.assign({}, defaults, options);
|
||||
return getTransactionsInternal(this.connection, address, newOptions);
|
||||
const newOptions = _.assign({}, defaults, options)
|
||||
return getTransactionsInternal(this.connection, address, newOptions)
|
||||
}
|
||||
|
||||
module.exports = getTransactions;
|
||||
module.exports = getTransactions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
export type TrustLineSpecification = {
|
||||
currency: string,
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const utils = require('./utils');
|
||||
const {validate} = utils.common;
|
||||
const parseAccountTrustline = require('./parse/account-trustline');
|
||||
import type {Connection} from '../common/connection.js';
|
||||
import type {TrustlinesOptions, Trustline} from './trustlines-types.js';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const {validate} = utils.common
|
||||
const parseAccountTrustline = require('./parse/account-trustline')
|
||||
import type {Connection} from '../common/connection.js'
|
||||
import type {TrustlinesOptions, Trustline} from './trustlines-types.js'
|
||||
|
||||
|
||||
type GetTrustlinesResponse = Array<Trustline>
|
||||
|
||||
function currencyFilter(currency: string, trustline: Trustline) {
|
||||
return currency === null || trustline.specification.currency === currency;
|
||||
return currency === null || trustline.specification.currency === currency
|
||||
}
|
||||
|
||||
function formatResponse(options: TrustlinesOptions, data) {
|
||||
@@ -19,7 +19,7 @@ function formatResponse(options: TrustlinesOptions, data) {
|
||||
marker: data.marker,
|
||||
results: data.lines.map(parseAccountTrustline)
|
||||
.filter(_.partial(currencyFilter, options.currency || null))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getAccountLines(connection: Connection, address: string,
|
||||
@@ -33,20 +33,20 @@ function getAccountLines(connection: Connection, address: string,
|
||||
marker: marker,
|
||||
limit: utils.clamp(limit, 10, 400),
|
||||
peer: options.counterparty
|
||||
};
|
||||
}
|
||||
|
||||
return connection.request(request).then(_.partial(formatResponse, options));
|
||||
return connection.request(request).then(_.partial(formatResponse, options))
|
||||
}
|
||||
|
||||
function getTrustlines(address: string, options: TrustlinesOptions = {}
|
||||
): Promise<GetTrustlinesResponse> {
|
||||
validate.getTrustlines({address, options});
|
||||
validate.getTrustlines({address, options})
|
||||
|
||||
return this.getLedgerVersion().then(ledgerVersion => {
|
||||
const getter = _.partial(getAccountLines, this.connection, address,
|
||||
options.ledgerVersion || ledgerVersion, options);
|
||||
return utils.getRecursive(getter, options.limit);
|
||||
});
|
||||
options.ledgerVersion || ledgerVersion, options)
|
||||
return utils.getRecursive(getter, options.limit)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = getTrustlines;
|
||||
module.exports = getTrustlines
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
'use strict' // eslint-disable-line strict
|
||||
|
||||
import type {Amount} from '../common/types.js';
|
||||
import type {Amount} from '../common/types.js'
|
||||
|
||||
export type OrdersOptions = {
|
||||
limit?: number,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const assert = require('assert');
|
||||
const common = require('../common');
|
||||
const dropsToXrp = common.dropsToXrp;
|
||||
import type {TransactionType} from './transaction-types';
|
||||
import type {Issue} from '../common/types.js';
|
||||
import type {Connection} from '../common/connection';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const assert = require('assert')
|
||||
const common = require('../common')
|
||||
const dropsToXrp = common.dropsToXrp
|
||||
import type {TransactionType} from './transaction-types'
|
||||
import type {Issue} from '../common/types.js'
|
||||
import type {Connection} from '../common/connection'
|
||||
|
||||
type RecursiveData = {
|
||||
marker: string,
|
||||
@@ -16,8 +16,8 @@ type RecursiveData = {
|
||||
type Getter = (marker: ?string, limit: number) => Promise<RecursiveData>
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
assert(min <= max, 'Illegal clamp bounds');
|
||||
return Math.min(Math.max(value, min), max);
|
||||
assert(min <= max, 'Illegal clamp bounds')
|
||||
return Math.min(Math.max(value, min), max)
|
||||
}
|
||||
|
||||
function getXRPBalance(connection: Connection, address: string,
|
||||
@@ -27,51 +27,51 @@ function getXRPBalance(connection: Connection, address: string,
|
||||
command: 'account_info',
|
||||
account: address,
|
||||
ledger_index: ledgerVersion
|
||||
};
|
||||
}
|
||||
return connection.request(request).then(data =>
|
||||
dropsToXrp(data.account_data.Balance));
|
||||
dropsToXrp(data.account_data.Balance))
|
||||
}
|
||||
|
||||
// If the marker is omitted from a response, you have reached the end
|
||||
function getRecursiveRecur(getter: Getter, marker?: string, limit: number
|
||||
): Promise {
|
||||
return getter(marker, limit).then(data => {
|
||||
const remaining = limit - data.results.length;
|
||||
const remaining = limit - data.results.length
|
||||
if (remaining > 0 && data.marker !== undefined) {
|
||||
return getRecursiveRecur(getter, data.marker, remaining).then(results =>
|
||||
data.results.concat(results)
|
||||
);
|
||||
)
|
||||
}
|
||||
return data.results.slice(0, limit);
|
||||
});
|
||||
return data.results.slice(0, limit)
|
||||
})
|
||||
}
|
||||
|
||||
function getRecursive(getter: Getter, limit?: number): Promise {
|
||||
return getRecursiveRecur(getter, undefined, limit || Infinity);
|
||||
return getRecursiveRecur(getter, undefined, limit || Infinity)
|
||||
}
|
||||
|
||||
function renameCounterpartyToIssuer(amount?: Issue): ?{issuer?: string} {
|
||||
if (amount === undefined) {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
const issuer = amount.counterparty === undefined ?
|
||||
(amount.issuer !== undefined ? amount.issuer : undefined) :
|
||||
amount.counterparty;
|
||||
const withIssuer = _.assign({}, amount, {issuer: issuer});
|
||||
return _.omit(withIssuer, 'counterparty');
|
||||
amount.counterparty
|
||||
const withIssuer = _.assign({}, amount, {issuer: issuer})
|
||||
return _.omit(withIssuer, 'counterparty')
|
||||
}
|
||||
|
||||
type RequestBookOffersArgs = {taker_gets: Issue, taker_pays: Issue}
|
||||
|
||||
function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
|
||||
const taker_gets = renameCounterpartyToIssuer(order.taker_gets);
|
||||
const taker_pays = renameCounterpartyToIssuer(order.taker_pays);
|
||||
const changes = {taker_gets: taker_gets, taker_pays: taker_pays};
|
||||
return _.assign({}, order, _.omit(changes, _.isUndefined));
|
||||
const taker_gets = renameCounterpartyToIssuer(order.taker_gets)
|
||||
const taker_pays = renameCounterpartyToIssuer(order.taker_pays)
|
||||
const changes = {taker_gets: taker_gets, taker_pays: taker_pays}
|
||||
return _.assign({}, order, _.omit(changes, _.isUndefined))
|
||||
}
|
||||
|
||||
function signum(num) {
|
||||
return (num === 0) ? 0 : (num > 0 ? 1 : -1);
|
||||
return (num === 0) ? 0 : (num > 0 ? 1 : -1)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,27 +88,27 @@ function signum(num) {
|
||||
function compareTransactions(first: TransactionType, second: TransactionType
|
||||
): number {
|
||||
if (!first.outcome || !second.outcome) {
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
|
||||
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger);
|
||||
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger)
|
||||
}
|
||||
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1;
|
||||
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1
|
||||
}
|
||||
|
||||
function hasCompleteLedgerRange(connection: Connection,
|
||||
minLedgerVersion?: number, maxLedgerVersion?: number
|
||||
): Promise<boolean> {
|
||||
const firstLedgerVersion = 32570; // earlier versions have been lost
|
||||
const firstLedgerVersion = 32570 // earlier versions have been lost
|
||||
return connection.hasLedgerVersions(
|
||||
minLedgerVersion || firstLedgerVersion, maxLedgerVersion);
|
||||
minLedgerVersion || firstLedgerVersion, maxLedgerVersion)
|
||||
}
|
||||
|
||||
function isPendingLedgerVersion(connection: Connection,
|
||||
maxLedgerVersion: ?number
|
||||
): Promise<boolean> {
|
||||
return connection.getLedgerVersion().then(ledgerVersion =>
|
||||
ledgerVersion < (maxLedgerVersion || 0));
|
||||
ledgerVersion < (maxLedgerVersion || 0))
|
||||
}
|
||||
|
||||
function ensureLedgerVersion(options: Object
|
||||
@@ -116,10 +116,10 @@ function ensureLedgerVersion(options: Object
|
||||
if (Boolean(options) && options.ledgerVersion !== undefined &&
|
||||
options.ledgerVersion !== null
|
||||
) {
|
||||
return Promise.resolve(options);
|
||||
return Promise.resolve(options)
|
||||
}
|
||||
return this.getLedgerVersion().then(ledgerVersion =>
|
||||
_.assign({}, options, {ledgerVersion}));
|
||||
_.assign({}, options, {ledgerVersion}))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -132,4 +132,4 @@ module.exports = {
|
||||
isPendingLedgerVersion,
|
||||
clamp: clamp,
|
||||
common: common
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
'use strict';
|
||||
const keypairs = require('ripple-keypairs');
|
||||
const common = require('../common');
|
||||
const {errors, validate} = common;
|
||||
'use strict' // eslint-disable-line strict
|
||||
const keypairs = require('ripple-keypairs')
|
||||
const common = require('../common')
|
||||
const {errors, validate} = common
|
||||
|
||||
function generateAddress(options?: Object): Object {
|
||||
const secret = keypairs.generateSeed(options);
|
||||
const keypair = keypairs.deriveKeypair(secret);
|
||||
const address = keypairs.deriveAddress(keypair.publicKey);
|
||||
return {secret, address};
|
||||
const secret = keypairs.generateSeed(options)
|
||||
const keypair = keypairs.deriveKeypair(secret)
|
||||
const address = keypairs.deriveAddress(keypair.publicKey)
|
||||
return {secret, address}
|
||||
}
|
||||
|
||||
function generateAddressAPI(options?: Object): Object {
|
||||
validate.generateAddress({options});
|
||||
validate.generateAddress({options})
|
||||
try {
|
||||
return generateAddress(options);
|
||||
return generateAddress(options)
|
||||
} catch (error) {
|
||||
throw new errors.UnexpectedError(error.message);
|
||||
throw new errors.UnexpectedError(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateAddressAPI
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const common = require('../common');
|
||||
const hashes = require('ripple-hashes');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const common = require('../common')
|
||||
const hashes = require('ripple-hashes')
|
||||
|
||||
function convertLedgerHeader(header) {
|
||||
return {
|
||||
@@ -19,53 +19,56 @@ function convertLedgerHeader(header) {
|
||||
total_coins: header.totalDrops,
|
||||
totalCoins: header.totalDrops,
|
||||
transaction_hash: header.transactionHash
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function hashLedgerHeader(ledgerHeader) {
|
||||
const header = convertLedgerHeader(ledgerHeader);
|
||||
return hashes.computeLedgerHash(header);
|
||||
const header = convertLedgerHeader(ledgerHeader)
|
||||
return hashes.computeLedgerHash(header)
|
||||
}
|
||||
|
||||
function computeTransactionHash(ledger) {
|
||||
function computeTransactionHash(ledger, version) {
|
||||
if (ledger.rawTransactions === undefined) {
|
||||
return ledger.transactionHash;
|
||||
return ledger.transactionHash
|
||||
}
|
||||
const transactions = JSON.parse(ledger.rawTransactions);
|
||||
const transactions = JSON.parse(ledger.rawTransactions)
|
||||
const txs = _.map(transactions, tx => {
|
||||
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {});
|
||||
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {})
|
||||
const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'),
|
||||
tx.meta ? {metaData: tx.meta} : {});
|
||||
return renameMeta;
|
||||
});
|
||||
const transactionHash = hashes.computeTransactionTreeHash(txs);
|
||||
tx.meta ? {metaData: tx.meta} : {})
|
||||
return renameMeta
|
||||
})
|
||||
const transactionHash = hashes.computeTransactionTreeHash(txs, version)
|
||||
if (ledger.transactionHash !== undefined
|
||||
&& ledger.transactionHash !== transactionHash) {
|
||||
throw new common.errors.ValidationError('transactionHash in header'
|
||||
+ ' does not match computed hash of transactions');
|
||||
+ ' does not match computed hash of transactions')
|
||||
}
|
||||
return transactionHash;
|
||||
return transactionHash
|
||||
}
|
||||
|
||||
function computeStateHash(ledger) {
|
||||
function computeStateHash(ledger, version) {
|
||||
if (ledger.rawState === undefined) {
|
||||
return ledger.stateHash;
|
||||
return ledger.stateHash
|
||||
}
|
||||
const state = JSON.parse(ledger.rawState);
|
||||
const stateHash = hashes.computeStateTreeHash(state);
|
||||
const state = JSON.parse(ledger.rawState)
|
||||
const stateHash = hashes.computeStateTreeHash(state, version)
|
||||
if (ledger.stateHash !== undefined && ledger.stateHash !== stateHash) {
|
||||
throw new common.errors.ValidationError('stateHash in header'
|
||||
+ ' does not match computed hash of state');
|
||||
+ ' does not match computed hash of state')
|
||||
}
|
||||
return stateHash;
|
||||
return stateHash
|
||||
}
|
||||
|
||||
const sLCF_SHAMapV2 = 0x02
|
||||
|
||||
function computeLedgerHash(ledger: Object): string {
|
||||
const version = ((ledger.closeFlags & sLCF_SHAMapV2) === 0) ? 1 : 2
|
||||
const subhashes = {
|
||||
transactionHash: computeTransactionHash(ledger),
|
||||
stateHash: computeStateHash(ledger)
|
||||
};
|
||||
return hashLedgerHeader(_.assign({}, ledger, subhashes));
|
||||
transactionHash: computeTransactionHash(ledger, version),
|
||||
stateHash: computeStateHash(ledger, version)
|
||||
}
|
||||
return hashLedgerHeader(_.assign({}, ledger, subhashes))
|
||||
}
|
||||
|
||||
module.exports = computeLedgerHash;
|
||||
module.exports = computeLedgerHash
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
import type {GetServerInfoResponse} from '../common/serverinfo';
|
||||
'use strict' // eslint-disable-line strict
|
||||
const common = require('../common')
|
||||
import type {GetServerInfoResponse} from '../common/serverinfo'
|
||||
|
||||
function isConnected(): boolean {
|
||||
return this.connection.isConnected();
|
||||
return this.connection.isConnected()
|
||||
}
|
||||
|
||||
function getLedgerVersion(): Promise<number> {
|
||||
return this.connection.getLedgerVersion();
|
||||
return this.connection.getLedgerVersion()
|
||||
}
|
||||
|
||||
function connect(): Promise<void> {
|
||||
return this.connection.connect();
|
||||
return this.connection.connect()
|
||||
}
|
||||
|
||||
function disconnect(): Promise<void> {
|
||||
return this.connection.disconnect();
|
||||
return this.connection.disconnect()
|
||||
}
|
||||
|
||||
function getServerInfo(): Promise<GetServerInfoResponse> {
|
||||
return common.serverInfo.getServerInfo(this.connection);
|
||||
return common.serverInfo.getServerInfo(this.connection)
|
||||
}
|
||||
|
||||
function getFee(): Promise<number> {
|
||||
const cushion = this._feeCushion || 1.2;
|
||||
return common.serverInfo.getFee(this.connection, cushion);
|
||||
const cushion = this._feeCushion || 1.2
|
||||
return common.serverInfo.getFee(this.connection, cushion)
|
||||
}
|
||||
|
||||
function formatLedgerClose(ledgerClose: Object): Object {
|
||||
@@ -38,7 +38,7 @@ function formatLedgerClose(ledgerClose: Object): Object {
|
||||
reserveIncrementXRP: common.dropsToXrp(ledgerClose.reserve_inc),
|
||||
transactionCount: ledgerClose.txn_count,
|
||||
validatedLedgerVersions: ledgerClose.validated_ledgers
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -49,4 +49,4 @@ module.exports = {
|
||||
getFee,
|
||||
getLedgerVersion,
|
||||
formatLedgerClose
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
/* @flow */
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const binary = require('ripple-binary-codec');
|
||||
const utils = require('./utils');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const {decodeAddress} = require('ripple-address-codec');
|
||||
const {validate} = utils.common;
|
||||
const {computeBinaryTransactionHash} = require('ripple-hashes');
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const binary = require('ripple-binary-codec')
|
||||
const utils = require('./utils')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const {decodeAddress} = require('ripple-address-codec')
|
||||
const {validate} = utils.common
|
||||
const {computeBinaryTransactionHash} = require('ripple-hashes')
|
||||
|
||||
function addressToBigNumber(address) {
|
||||
const hex = (new Buffer(decodeAddress(address))).toString('hex');
|
||||
return new BigNumber(hex, 16);
|
||||
const hex = (new Buffer(decodeAddress(address))).toString('hex')
|
||||
return new BigNumber(hex, 16)
|
||||
}
|
||||
|
||||
function compareSigners(a, b) {
|
||||
return addressToBigNumber(a.Signer.Account)
|
||||
.comparedTo(addressToBigNumber(b.Signer.Account));
|
||||
.comparedTo(addressToBigNumber(b.Signer.Account))
|
||||
}
|
||||
|
||||
function combine(signedTransactions: Array<string>): Object {
|
||||
validate.combine({signedTransactions});
|
||||
validate.combine({signedTransactions})
|
||||
|
||||
const txs = _.map(signedTransactions, binary.decode);
|
||||
const tx = _.omit(txs[0], 'Signers');
|
||||
const txs = _.map(signedTransactions, binary.decode)
|
||||
const tx = _.omit(txs[0], 'Signers')
|
||||
if (!_.every(txs, _tx => _.isEqual(tx, _.omit(_tx, 'Signers')))) {
|
||||
throw new utils.common.errors.ValidationError(
|
||||
'txJSON is not the same for all signedTransactions');
|
||||
'txJSON is not the same for all signedTransactions')
|
||||
}
|
||||
const unsortedSigners = _.reduce(txs, (accumulator, _tx) =>
|
||||
accumulator.concat(_tx.Signers || []), []);
|
||||
const signers = unsortedSigners.sort(compareSigners);
|
||||
const signedTx = _.assign({}, tx, {Signers: signers});
|
||||
const signedTransaction = binary.encode(signedTx);
|
||||
const id = computeBinaryTransactionHash(signedTransaction);
|
||||
return {signedTransaction, id};
|
||||
accumulator.concat(_tx.Signers || []), [])
|
||||
const signers = unsortedSigners.sort(compareSigners)
|
||||
const signedTx = _.assign({}, tx, {Signers: signers})
|
||||
const signedTransaction = binary.encode(signedTx)
|
||||
const id = computeBinaryTransactionHash(signedTransaction)
|
||||
return {signedTransaction, id}
|
||||
}
|
||||
|
||||
module.exports = combine;
|
||||
module.exports = combine
|
||||
|
||||
41
src/transaction/escrow-cancellation.js
Normal file
41
src/transaction/escrow-cancellation.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/* @flow */
|
||||
'use strict' // eslint-disable-line strict
|
||||
const _ = require('lodash')
|
||||
const utils = require('./utils')
|
||||
const validate = utils.common.validate
|
||||
import type {Instructions, Prepare} from './types.js'
|
||||
import type {Memo} from '../common/types.js'
|
||||
|
||||
type EscrowCancellation = {
|
||||
owner: string,
|
||||
escrowSequence: number,
|
||||
memos?: Array<Memo>
|
||||
}
|
||||
|
||||
function createEscrowCancellationTransaction(account: string,
|
||||
payment: EscrowCancellation
|
||||
): Object {
|
||||
const txJSON: Object = {
|
||||
TransactionType: 'EscrowCancel',
|
||||
Account: account,
|
||||
Owner: payment.owner,
|
||||
OfferSequence: payment.escrowSequence
|
||||
}
|
||||
if (payment.memos !== undefined) {
|
||||
txJSON.Memos = _.map(payment.memos, utils.convertMemo)
|
||||
}
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function prepareEscrowCancellation(address: string,
|
||||
escrowCancellation: EscrowCancellation,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
validate.prepareEscrowCancellation(
|
||||
{address, escrowCancellation, instructions})
|
||||
const txJSON = createEscrowCancellationTransaction(
|
||||
address, escrowCancellation)
|
||||
return utils.prepareTransaction(txJSON, this, instructions)
|
||||
}
|
||||
|
||||
module.exports = prepareEscrowCancellation
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user