mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-12 08:35:48 +00:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c534d87c0 | ||
|
|
138e7942da | ||
|
|
23504821cf | ||
|
|
b09da3e8f1 | ||
|
|
f3dd2fec99 | ||
|
|
462e375800 | ||
|
|
ca8c881375 | ||
|
|
96605a57d4 | ||
|
|
491ce40081 | ||
|
|
f33eb07bdd | ||
|
|
8bb1dc9b47 | ||
|
|
78b50472da | ||
|
|
e0259b37ed | ||
|
|
bf863a2594 | ||
|
|
edd174881e | ||
|
|
0bf747f6fc | ||
|
|
ab4d2b5d58 | ||
|
|
1b81280358 | ||
|
|
32f4eea3b8 | ||
|
|
1a3a49decb | ||
|
|
416717aff6 | ||
|
|
769d955a40 | ||
|
|
6de85b841d | ||
|
|
b4c6af29e4 | ||
|
|
7192606e21 | ||
|
|
f5196389e8 | ||
|
|
27be06c5c9 | ||
|
|
1d3ddb5e85 | ||
|
|
2145c104fd | ||
|
|
64e0d098e7 | ||
|
|
50d8cbb0ee | ||
|
|
9580397558 | ||
|
|
cf544b74f5 | ||
|
|
312f831efb | ||
|
|
f5bad5d28e | ||
|
|
9b7d255200 | ||
|
|
7a027bdd93 | ||
|
|
439a611a9e | ||
|
|
5f92b230aa | ||
|
|
29bc5303ae | ||
|
|
5314e5e7e9 | ||
|
|
c88462c99b | ||
|
|
0b552f1a7e | ||
|
|
552635a3c7 | ||
|
|
ca769bee39 | ||
|
|
b7ca0a0a14 | ||
|
|
84097a3179 | ||
|
|
8ba36b2588 | ||
|
|
e1d4ebc5f6 | ||
|
|
9e712d6089 | ||
|
|
90bea3dc6b | ||
|
|
bf480bb971 | ||
|
|
a94b48be50 | ||
|
|
abed42d848 | ||
|
|
3d6e795ca5 | ||
|
|
a3cbe8e9d4 | ||
|
|
0a2000098a | ||
|
|
a2348b5133 | ||
|
|
20d2f9d894 | ||
|
|
321f908e76 | ||
|
|
49875cb0e5 | ||
|
|
fa6a2c5bbb | ||
|
|
1074c00b60 | ||
|
|
8a8b10541e | ||
|
|
46cf4d677c | ||
|
|
94587d7515 | ||
|
|
b77a12fd0d | ||
|
|
a98526b398 | ||
|
|
5639bf9d48 | ||
|
|
c626685103 |
@@ -20,6 +20,7 @@
|
||||
"no-useless-constructor": 0,
|
||||
"no-unused-vars": 0,
|
||||
"no-prototype-builtins": 0,
|
||||
"require-atomic-updates": 0
|
||||
"require-atomic-updates": 0,
|
||||
"no-dupe-class-members": 0
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,6 @@
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"quoteProps": "consistent"
|
||||
"quoteProps": "consistent",
|
||||
"bracketSpacing": false
|
||||
}
|
||||
35
HISTORY.md
35
HISTORY.md
@@ -1,5 +1,40 @@
|
||||
# ripple-lib Release History
|
||||
|
||||
## 1.6.0 (2020-01-06)
|
||||
|
||||
* Add support for AccountDelete (#1120)
|
||||
* Improve error type given on rejected message _send to be DisconnectedError (#1098)
|
||||
* Internal
|
||||
* Add unit test for unhandled promise rejection warning on message _send (#1098)
|
||||
* Dependencies
|
||||
* Update @types/node, @typescript-eslint/parser
|
||||
|
||||
## 1.5.1 (2019-12-28)
|
||||
|
||||
* Fix support for CDNs (#1142)
|
||||
* Internal
|
||||
* Clean up connection trace logic (#1114)
|
||||
* Clean up the connection config (#1115)
|
||||
* Run prettier format (#1116)
|
||||
* Update eslint command (#1118)
|
||||
* Dependencies
|
||||
* Update webpack-cli, webpack, ts-node, @types/lodash, @types/ws, @types/node, @typescript-eslint/parser, @typescript-eslint/eslint-plugin, https-proxy-agent, mocha, eventemitter2
|
||||
|
||||
## 1.5.0 (2019-12-14)
|
||||
|
||||
* Add support for `WalletLocator` (#1083)
|
||||
* Types: Move and de-dupe `TransactionJSON` type (#1096)
|
||||
* This resolves an error surfaced by [TypeScript 3.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#local-and-imported-type-declarations-now-conflict)
|
||||
* Add a heartbeat to detect hung connections (#1101)
|
||||
* Dependencies
|
||||
* Update TypeScript version (#1096)
|
||||
* Update ripple-lib-transactionparser to 0.8.1 (#1097)
|
||||
* Update ripple-binary-codec to 0.2.5
|
||||
* Update webpack (#1112)
|
||||
* Require node 8 and yarn (#1107)
|
||||
* Testing: Refactor and add unit tests
|
||||
* Fix some errors caught by the improved tests
|
||||
|
||||
## 1.4.2 (2019-11-14)
|
||||
|
||||
* Add support for tick size (#1090) (thanks @RareData)
|
||||
|
||||
51
README.md
51
README.md
@@ -1,10 +1,13 @@
|
||||
[](https://travis-ci.org/ripple/ripple-lib)
|
||||
# ripple-lib
|
||||
# ripple-lib (RippleAPI)
|
||||
|
||||
A JavaScript API for interacting with the XRP Ledger
|
||||
A JavaScript/TypeScript API for interacting with the XRP Ledger
|
||||
|
||||
[](https://www.npmjs.org/package/ripple-lib)
|
||||
|
||||
This is the recommended library for integrating a JavaScript/TypeScript app with the XRP Ledger, especially if you intend to use advanced functionality such as IOUs, payment paths, the decentralized exchange, account settings, payment channels, escrows, multi-signing, and more.
|
||||
|
||||
**What is ripple-lib used for?** Here's a [list of applications](APPLICATIONS.md) that use `ripple-lib`. Open a PR to add your app or project to the list!
|
||||
|
||||
### Features
|
||||
|
||||
+ Connect to a `rippled` server from Node.js or a web browser
|
||||
@@ -13,10 +16,6 @@ A JavaScript API for interacting with the XRP Ledger
|
||||
+ Sign and submit transactions to the XRP Ledger
|
||||
+ Type definitions for TypeScript
|
||||
|
||||
## Getting Started
|
||||
|
||||
See also: [RippleAPI Beginners Guide](https://xrpl.org/get-started-with-rippleapi-for-javascript.html)
|
||||
|
||||
### Requirements
|
||||
|
||||
+ **[Node v10](https://nodejs.org/)** is recommended. Other versions may work but are not frequently tested.
|
||||
@@ -29,9 +28,11 @@ In an existing project (with `package.json`), install `ripple-lib`:
|
||||
$ yarn add ripple-lib
|
||||
```
|
||||
|
||||
Then see the [documentation](https://github.com/ripple/ripple-lib/blob/develop/docs/index.md) and [code samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples).
|
||||
## Documentation
|
||||
|
||||
**What is ripple-lib used for?** Here's a [list of applications](APPLICATIONS.md) that use `ripple-lib`. Open a PR to add your app or project to the list!
|
||||
+ [RippleAPI Beginners Guide](https://xrpl.org/get-started-with-rippleapi-for-javascript.html)
|
||||
+ [RippleAPI Full Reference Documentation](https://xrpl.org/rippleapi-reference.html) ([in this repo](https://github.com/ripple/ripple-lib/blob/develop/docs/index.md))
|
||||
+ [Code Samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples)
|
||||
|
||||
### Mailing Lists
|
||||
|
||||
@@ -45,35 +46,41 @@ If you're using the XRP Ledger in production, you should run a [rippled server](
|
||||
|
||||
## Development
|
||||
|
||||
To build the library for Node.js:
|
||||
```
|
||||
$ yarn compile
|
||||
```
|
||||
|
||||
The TypeScript compiler will [output](./tsconfig.json#L7) the resulting JS files in `./dist/npm/`.
|
||||
|
||||
To build the library for the browser:
|
||||
To build the library for Node.js and the browser:
|
||||
```
|
||||
$ yarn build
|
||||
```
|
||||
|
||||
Gulp will [output](./Gulpfile.js) the resulting JS files in `./build/`.
|
||||
The TypeScript compiler will [output](./tsconfig.json#L7) the resulting JS files in `./dist/npm/`.
|
||||
|
||||
webpack will output the resulting JS files in `./build/`.
|
||||
|
||||
For details, see the `scripts` in `package.json`.
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Unit Tests
|
||||
|
||||
1. Clone the repository
|
||||
2. `cd` into the repository and install dependencies with `yarn install`
|
||||
3. `yarn test`
|
||||
|
||||
Also, run `yarn lint` to lint the code with `tslint`.
|
||||
### Linting
|
||||
|
||||
Run `yarn lint` to lint the code with `tslint`.
|
||||
|
||||
## Generating Documentation
|
||||
|
||||
The continuous integration tests require that the documentation stays up-to-date. If you make changes to the JSON schemas, fixtures, or documentation sources, you must update the documentation by running `yarn run docgen`.
|
||||
Do not edit `./docs/index.md` directly because it is a generated file.
|
||||
|
||||
Instead, edit the appropriate `.md.ejs` files in `./docs/src/`.
|
||||
|
||||
If you make changes to the JSON schemas, fixtures, or documentation sources, update the documentation by running `yarn run docgen`.
|
||||
|
||||
## More Information
|
||||
|
||||
+ [RippleAPI Reference](https://developers.ripple.com/rippleapi-reference.html) - XRP Ledger Dev Portal
|
||||
+ [XRP Ledger Dev Portal](https://developers.ripple.com/)
|
||||
+ [ripple-lib-announce mailing list](https://groups.google.com/forum/#!forum/ripple-lib-announce) - subscribe for release announcements
|
||||
+ [RippleAPI Reference](https://xrpl.org/rippleapi-reference.html) - XRP Ledger Dev Portal
|
||||
+ [XRP Ledger Dev Portal](https://xrpl.org/)
|
||||
|
||||
[](https://travis-ci.org/ripple/ripple-lib)
|
||||
|
||||
@@ -541,7 +541,7 @@ defaultRipple | boolean | *Optional* Enable [rippling](https://ripple.com/build/
|
||||
depositAuth | boolean | *Optional* Enable [Deposit Authorization](https://ripple.com/build/deposit-authorization/) on this account. If set, transactions cannot send value of any kind to this account unless the sender of those transactions is the account itself. (Requires the [DepositAuth amendment](https://ripple.com/build/known-amendments/#depositauth))
|
||||
disableMasterKey | boolean | *Optional* Disallows use of the master key to sign transactions for this account. To disable the master key, you must authorize the transaction by signing it with the master key pair. You cannot use a regular key pair or a multi-signature. You can re-enable the master key pair using a regular key pair or multi-signature. See [AccountSet](https://developers.ripple.com/accountset.html).
|
||||
disallowIncomingXRP | boolean | *Optional* Indicates that client applications should not send XRP to this account. Not enforced by rippled.
|
||||
domain | string | *Optional* The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase.
|
||||
domain | string | *Optional* The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase.
|
||||
emailHash | string,null | *Optional* Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.
|
||||
enableTransactionIDTracking | boolean | *Optional* Track the ID of this account’s most recent transaction.
|
||||
globalFreeze | boolean | *Optional* Freeze all assets issued by this account.
|
||||
@@ -560,6 +560,7 @@ signers | object | *Optional* Settings that determine what sets of accounts can
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
tickSize | string | *Optional* Tick size to use for offers involving a currency issued by this address. The exchange rates of those offers is rounded to this many significant digits. Valid values are 3 to 15 inclusive, or 0 to disable.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
|
||||
walletLocator | string,null | *Optional* Transaction hash or any other 64 character hexadecimal string, that may or may not represent the result of a hash operation. Use `null` to clear.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -1707,6 +1708,7 @@ return api.getTransactions(address).then(transaction => {
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2019-04-01T07:39:01.000Z",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
@@ -1800,6 +1802,7 @@ return api.getTransactions(address).then(transaction => {
|
||||
},
|
||||
"outcome": {
|
||||
"result": "tesSUCCESS",
|
||||
"timestamp": "2019-04-01T07:39:01.000Z",
|
||||
"fee": "0.00001",
|
||||
"deliveredAmount": {
|
||||
"currency": "USD",
|
||||
@@ -3912,7 +3915,7 @@ defaultRipple | boolean | *Optional* Enable [rippling](https://ripple.com/build/
|
||||
depositAuth | boolean | *Optional* Enable [Deposit Authorization](https://ripple.com/build/deposit-authorization/) on this account. If set, transactions cannot send value of any kind to this account unless the sender of those transactions is the account itself. (Requires the [DepositAuth amendment](https://ripple.com/build/known-amendments/#depositauth))
|
||||
disableMasterKey | boolean | *Optional* Disallows use of the master key to sign transactions for this account. To disable the master key, you must authorize the transaction by signing it with the master key pair. You cannot use a regular key pair or a multi-signature. You can re-enable the master key pair using a regular key pair or multi-signature. See [AccountSet](https://developers.ripple.com/accountset.html).
|
||||
disallowIncomingXRP | boolean | *Optional* Indicates that client applications should not send XRP to this account. Not enforced by rippled.
|
||||
domain | string | *Optional* The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase.
|
||||
domain | string | *Optional* The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase.
|
||||
emailHash | string,null | *Optional* Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.
|
||||
enableTransactionIDTracking | boolean | *Optional* Track the ID of this account’s most recent transaction.
|
||||
globalFreeze | boolean | *Optional* Freeze all assets issued by this account.
|
||||
@@ -3931,6 +3934,7 @@ signers | object | *Optional* Settings that determine what sets of accounts can
|
||||
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
|
||||
tickSize | string | *Optional* Tick size to use for offers involving a currency issued by this address. The exchange rates of those offers is rounded to this many significant digits. Valid values are 3 to 15 inclusive, or 0 to disable.
|
||||
transferRate | number,null | *Optional* The fee to charge when users transfer this account’s issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
|
||||
walletLocator | string,null | *Optional* Transaction hash or any other 64 character hexadecimal string, that may or may not represent the result of a hash operation. Use `null` to clear.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -3946,6 +3950,7 @@ return api.getSettings(address).then(settings =>
|
||||
"requireDestinationTag": true,
|
||||
"disallowIncomingXRP": true,
|
||||
"emailHash": "23463B99B62A72F26ED677CC556C44E8",
|
||||
"walletLocator": "00000000000000000000000000000000000000000000000000000000DEADBEEF",
|
||||
"domain": "example.com",
|
||||
"transferRate": 1.002,
|
||||
"tickSize": 5,
|
||||
@@ -4506,7 +4511,7 @@ Prepare a transaction. The prepared transaction must subsequently be [signed](#s
|
||||
|
||||
This method works with any of [the transaction types supported by rippled](https://developers.ripple.com/transaction-types.html).
|
||||
|
||||
Notably, this is the preferred method for preparing a `DepositPreauth` transaction (added in rippled 1.1.0).
|
||||
Notably, this is the preferred method for preparing `DepositPreauth` or `AccountDelete` transactions.
|
||||
|
||||
### Parameters
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Prepare a transaction. The prepared transaction must subsequently be [signed](#s
|
||||
|
||||
This method works with any of [the transaction types supported by rippled](https://developers.ripple.com/transaction-types.html).
|
||||
|
||||
Notably, this is the preferred method for preparing a `DepositPreauth` transaction (added in rippled 1.1.0).
|
||||
Notably, this is the preferred method for preparing `DepositPreauth` or `AccountDelete` transactions.
|
||||
|
||||
### Parameters
|
||||
|
||||
|
||||
32
package.json
32
package.json
@@ -1,13 +1,16 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "1.4.2",
|
||||
"version": "1.6.0",
|
||||
"license": "ISC",
|
||||
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
|
||||
"files": [
|
||||
"dist/npm/*",
|
||||
"build/ripple-latest-min.js"
|
||||
"build/ripple-latest-min.js",
|
||||
"build/ripple-latest.js"
|
||||
],
|
||||
"main": "dist/npm/",
|
||||
"unpkg": "build/ripple-latest-min.js",
|
||||
"jsdelivr": "build/ripple-latest-min.js",
|
||||
"types": "dist/npm/index.d.ts",
|
||||
"browser": {
|
||||
"ws": "./dist/npm/common/wswrapper.js",
|
||||
@@ -20,34 +23,34 @@
|
||||
"@types/lodash": "^4.14.136",
|
||||
"@types/ws": "^6.0.3",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"https-proxy-agent": "^3.0.0",
|
||||
"https-proxy-agent": "^4.0.0",
|
||||
"jsonschema": "1.2.2",
|
||||
"lodash": "^4.17.4",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"ripple-address-codec": "^4.0.0",
|
||||
"ripple-binary-codec": "^0.2.4",
|
||||
"ripple-binary-codec": "^0.2.5",
|
||||
"ripple-keypairs": "^0.11.0",
|
||||
"ripple-lib-transactionparser": "0.8.0",
|
||||
"ripple-lib-transactionparser": "0.8.1",
|
||||
"ws": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^12.12.5",
|
||||
"@types/node": "^13.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "^2.3.3",
|
||||
"@typescript-eslint/parser": "^2.3.3",
|
||||
"assert-diff": "^1.0.1",
|
||||
"assert-diff": "^2.0.3",
|
||||
"doctoc": "^0.15.0",
|
||||
"ejs": "^2.3.4",
|
||||
"eslint": "^6.5.1",
|
||||
"eventemitter2": "^5.0.1",
|
||||
"eventemitter2": "^6.0.0",
|
||||
"json-schema-to-markdown-table": "^0.4.0",
|
||||
"mocha": "6.2.0",
|
||||
"mocha": "6.2.2",
|
||||
"mocha-junit-reporter": "^1.9.1",
|
||||
"nyc": "^14.1.1",
|
||||
"source-map-support": "0.5.12",
|
||||
"prettier": "^1.19.1",
|
||||
"ts-node": "^8.4.1",
|
||||
"typescript": "^3.6.4",
|
||||
"webpack": "^4.30.0",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-bundle-analyzer": "^3.6.0",
|
||||
"webpack-cli": "^3.3.9"
|
||||
},
|
||||
@@ -63,7 +66,9 @@
|
||||
"docgen": "node --harmony scripts/build_docs.js",
|
||||
"prepublish": "yarn clean && yarn build",
|
||||
"test": "TS_NODE_PROJECT=src/tsconfig.json nyc mocha --exit",
|
||||
"lint": "eslint src/**/*.ts 'test/*-test.{ts,js}'",
|
||||
"test:watch": "TS_NODE_PROJECT=src/tsconfig.json mocha --watch --reporter dot",
|
||||
"format": "prettier --write '{src,test}/**/*.ts'",
|
||||
"lint": "eslint 'src/**/*.ts' 'test/*-test.{ts,js}'",
|
||||
"perf": "./scripts/perf_test.sh",
|
||||
"start": "node scripts/http.js"
|
||||
},
|
||||
@@ -73,6 +78,7 @@
|
||||
},
|
||||
"readmeFilename": "README.md",
|
||||
"engines": {
|
||||
"node": ">=6.12.3"
|
||||
"node": ">=8",
|
||||
"yarn": "^1.15.2"
|
||||
}
|
||||
}
|
||||
|
||||
160
src/api.ts
160
src/api.ts
@@ -24,8 +24,7 @@ import getBalances from './ledger/balances'
|
||||
import getBalanceSheet from './ledger/balance-sheet'
|
||||
import getPaths from './ledger/pathfind'
|
||||
import getOrders from './ledger/orders'
|
||||
import {getOrderbook,
|
||||
formatBidsAndAsks} from './ledger/orderbook'
|
||||
import {getOrderbook, formatBidsAndAsks} from './ledger/orderbook'
|
||||
import {getSettings, parseAccountFlags} from './ledger/settings'
|
||||
import getAccountInfo from './ledger/accountinfo'
|
||||
import getAccountObjects from './ledger/accountobjects'
|
||||
@@ -47,7 +46,11 @@ import prepareSettings from './transaction/settings'
|
||||
import sign from './transaction/sign'
|
||||
import combine from './transaction/combine'
|
||||
import submit from './transaction/submit'
|
||||
import {generateAddressAPI, GenerateAddressOptions, GeneratedAddress} from './offline/generate-address'
|
||||
import {
|
||||
generateAddressAPI,
|
||||
GenerateAddressOptions,
|
||||
GeneratedAddress
|
||||
} from './offline/generate-address'
|
||||
import {deriveKeypair, deriveAddress, deriveXAddress} from './offline/derive'
|
||||
import computeLedgerHash from './offline/ledgerhash'
|
||||
import signPaymentChannelClaim from './offline/sign-payment-channel-claim'
|
||||
@@ -55,18 +58,28 @@ import verifyPaymentChannelClaim from './offline/verify-payment-channel-claim'
|
||||
import getLedger from './ledger/ledger'
|
||||
|
||||
import {
|
||||
AccountObjectsRequest, AccountObjectsResponse,
|
||||
AccountOffersRequest, AccountOffersResponse,
|
||||
AccountInfoRequest, AccountInfoResponse,
|
||||
AccountLinesRequest, AccountLinesResponse,
|
||||
BookOffersRequest, BookOffersResponse,
|
||||
GatewayBalancesRequest, GatewayBalancesResponse,
|
||||
LedgerRequest, LedgerResponse,
|
||||
LedgerEntryRequest, LedgerEntryResponse,
|
||||
ServerInfoRequest, ServerInfoResponse
|
||||
AccountObjectsRequest,
|
||||
AccountObjectsResponse,
|
||||
AccountOffersRequest,
|
||||
AccountOffersResponse,
|
||||
AccountInfoRequest,
|
||||
AccountInfoResponse,
|
||||
AccountLinesRequest,
|
||||
AccountLinesResponse,
|
||||
BookOffersRequest,
|
||||
BookOffersResponse,
|
||||
GatewayBalancesRequest,
|
||||
GatewayBalancesResponse,
|
||||
LedgerRequest,
|
||||
LedgerResponse,
|
||||
LedgerDataRequest,
|
||||
LedgerDataResponse,
|
||||
LedgerEntryRequest,
|
||||
LedgerEntryResponse,
|
||||
ServerInfoRequest,
|
||||
ServerInfoResponse
|
||||
} from './common/types/commands'
|
||||
|
||||
|
||||
import RangeSet from './common/rangeset'
|
||||
import * as ledgerUtils from './ledger/utils'
|
||||
import * as transactionUtils from './transaction/utils'
|
||||
@@ -74,15 +87,14 @@ import * as schemaValidator from './common/schema-validator'
|
||||
import {getServerInfo, getFee} from './common/serverinfo'
|
||||
import {clamp, renameCounterpartyToIssuer} from './ledger/utils'
|
||||
import {TransactionJSON, Instructions, Prepare} from './transaction/types'
|
||||
import {ConnectionOptions} from './common/connection'
|
||||
import {ConnectionUserOptions} from './common/connection'
|
||||
import {isValidXAddress, isValidClassicAddress} from 'ripple-address-codec'
|
||||
|
||||
export interface APIOptions extends ConnectionOptions {
|
||||
server?: string,
|
||||
feeCushion?: number,
|
||||
maxFeeXRP?: string,
|
||||
trace?: boolean,
|
||||
proxy?: string,
|
||||
export interface APIOptions extends ConnectionUserOptions {
|
||||
server?: string
|
||||
feeCushion?: number
|
||||
maxFeeXRP?: string
|
||||
proxy?: string
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
@@ -91,7 +103,7 @@ export interface APIOptions extends ConnectionOptions {
|
||||
* command. This varies from command to command, but we need to know it to
|
||||
* properly count across many requests.
|
||||
*/
|
||||
function getCollectKeyFromCommand(command: string): string|undefined {
|
||||
function getCollectKeyFromCommand(command: string): string | undefined {
|
||||
switch (command) {
|
||||
case 'account_offers':
|
||||
case 'book_offers':
|
||||
@@ -140,12 +152,12 @@ class RippleAPI extends EventEmitter {
|
||||
this.emit('connected')
|
||||
})
|
||||
this.connection.on('disconnected', code => {
|
||||
let finalCode = code;
|
||||
// This is a backwards-compatible fix for this change in the ws library:
|
||||
let finalCode = code
|
||||
// This is a backwards-compatible fix for this change in the ws library:
|
||||
// https://github.com/websockets/ws/issues/1257
|
||||
// TODO: Remove in next major, breaking version
|
||||
if (finalCode === 1005) {
|
||||
finalCode = 1000;
|
||||
finalCode = 1000
|
||||
}
|
||||
this.emit('disconnected', finalCode)
|
||||
})
|
||||
@@ -156,31 +168,51 @@ class RippleAPI extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes a request to the API with the given command and
|
||||
* additional request body parameters.
|
||||
*/
|
||||
async request(command: 'account_info', params: AccountInfoRequest):
|
||||
Promise<AccountInfoResponse>
|
||||
async request(command: 'account_lines', params: AccountLinesRequest):
|
||||
Promise<AccountLinesResponse>
|
||||
async request(command: 'account_objects', params: AccountObjectsRequest):
|
||||
Promise<AccountObjectsResponse>
|
||||
async request(command: 'account_offers', params: AccountOffersRequest):
|
||||
Promise<AccountOffersResponse>
|
||||
async request(command: 'book_offers', params: BookOffersRequest):
|
||||
Promise<BookOffersResponse>
|
||||
async request(command: 'gateway_balances', params: GatewayBalancesRequest):
|
||||
Promise<GatewayBalancesResponse>
|
||||
async request(command: 'ledger', params: LedgerRequest):
|
||||
Promise<LedgerResponse>
|
||||
async request(command: 'ledger_entry', params: LedgerEntryRequest):
|
||||
Promise<LedgerEntryResponse>
|
||||
async request(command: 'server_info', params?: ServerInfoRequest):
|
||||
Promise<ServerInfoResponse>
|
||||
async request(command: string, params: any):
|
||||
Promise<any>
|
||||
async request(
|
||||
command: 'account_info',
|
||||
params: AccountInfoRequest
|
||||
): Promise<AccountInfoResponse>
|
||||
async request(
|
||||
command: 'account_lines',
|
||||
params: AccountLinesRequest
|
||||
): Promise<AccountLinesResponse>
|
||||
async request(
|
||||
command: 'account_objects',
|
||||
params: AccountObjectsRequest
|
||||
): Promise<AccountObjectsResponse>
|
||||
async request(
|
||||
command: 'account_offers',
|
||||
params: AccountOffersRequest
|
||||
): Promise<AccountOffersResponse>
|
||||
async request(
|
||||
command: 'book_offers',
|
||||
params: BookOffersRequest
|
||||
): Promise<BookOffersResponse>
|
||||
async request(
|
||||
command: 'gateway_balances',
|
||||
params: GatewayBalancesRequest
|
||||
): Promise<GatewayBalancesResponse>
|
||||
async request(
|
||||
command: 'ledger',
|
||||
params: LedgerRequest
|
||||
): Promise<LedgerResponse>
|
||||
async request(
|
||||
command: 'ledger_data',
|
||||
params?: LedgerDataRequest
|
||||
): Promise<LedgerDataResponse>
|
||||
async request(
|
||||
command: 'ledger_entry',
|
||||
params: LedgerEntryRequest
|
||||
): Promise<LedgerEntryResponse>
|
||||
async request(
|
||||
command: 'server_info',
|
||||
params?: ServerInfoRequest
|
||||
): Promise<ServerInfoResponse>
|
||||
async request(command: string, params: any): Promise<any>
|
||||
async request(command: string, params: any = {}): Promise<any> {
|
||||
return this.connection.request({
|
||||
...params,
|
||||
@@ -205,7 +237,7 @@ class RippleAPI extends EventEmitter {
|
||||
command: string,
|
||||
params: object = {},
|
||||
currentResponse: T
|
||||
): Promise<object> {
|
||||
): Promise<T> {
|
||||
if (!currentResponse.marker) {
|
||||
return Promise.reject(
|
||||
new errors.NotFoundError('response does not have a next page')
|
||||
@@ -222,8 +254,10 @@ class RippleAPI extends EventEmitter {
|
||||
*
|
||||
* You can later submit the transaction with `submit()`.
|
||||
*/
|
||||
async prepareTransaction(txJSON: TransactionJSON, instructions: Instructions = {}):
|
||||
Promise<Prepare> {
|
||||
async prepareTransaction(
|
||||
txJSON: TransactionJSON,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
return transactionUtils.prepareTransaction(txJSON, this, instructions)
|
||||
}
|
||||
|
||||
@@ -251,16 +285,23 @@ class RippleAPI extends EventEmitter {
|
||||
* general use. Instead, use rippled's built-in pagination and make multiple
|
||||
* requests as needed.
|
||||
*/
|
||||
async _requestAll(command: 'account_offers', params: AccountOffersRequest):
|
||||
Promise<AccountOffersResponse[]>
|
||||
async _requestAll(command: 'book_offers', params: BookOffersRequest):
|
||||
Promise<BookOffersResponse[]>
|
||||
async _requestAll(command: 'account_lines', params: AccountLinesRequest):
|
||||
Promise<AccountLinesResponse[]>
|
||||
async _requestAll(
|
||||
command: 'account_offers',
|
||||
params: AccountOffersRequest
|
||||
): Promise<AccountOffersResponse[]>
|
||||
async _requestAll(
|
||||
command: 'book_offers',
|
||||
params: BookOffersRequest
|
||||
): Promise<BookOffersResponse[]>
|
||||
async _requestAll(
|
||||
command: 'account_lines',
|
||||
params: AccountLinesRequest
|
||||
): Promise<AccountLinesResponse[]>
|
||||
async _requestAll(
|
||||
command: string,
|
||||
params: any = {},
|
||||
options: {collect?: string} = {}): Promise<any[]> {
|
||||
options: {collect?: string} = {}
|
||||
): Promise<any[]> {
|
||||
// The data under collection is keyed based on the command. Fail if command
|
||||
// not recognized and collection key not provided.
|
||||
const collectKey = options.collect || getCollectKeyFromCommand(command)
|
||||
@@ -269,8 +310,7 @@ class RippleAPI extends EventEmitter {
|
||||
}
|
||||
// If limit is not provided, fetches all data over multiple requests.
|
||||
// NOTE: This may return much more than needed. Set limit when possible.
|
||||
const countTo: number =
|
||||
(params.limit !== undefined) ? params.limit : Infinity
|
||||
const countTo: number = params.limit !== undefined ? params.limit : Infinity
|
||||
let count: number = 0
|
||||
let marker: string = params.marker
|
||||
let lastBatchLength: number
|
||||
@@ -294,7 +334,7 @@ class RippleAPI extends EventEmitter {
|
||||
} else {
|
||||
lastBatchLength = 0
|
||||
}
|
||||
} while(!!marker && count < countTo && lastBatchLength !== 0)
|
||||
} while (!!marker && count < countTo && lastBatchLength !== 0)
|
||||
return results
|
||||
}
|
||||
|
||||
@@ -372,6 +412,4 @@ class RippleAPI extends EventEmitter {
|
||||
isValidSecret = schemaValidator.isValidSecret
|
||||
}
|
||||
|
||||
export {
|
||||
RippleAPI
|
||||
}
|
||||
export {RippleAPI}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
|
||||
import * as _ from 'lodash'
|
||||
import {RippleAPI} from './api'
|
||||
import {RippleAPI, APIOptions} from './api'
|
||||
|
||||
class RippleAPIBroadcast extends RippleAPI {
|
||||
|
||||
ledgerVersion: number | undefined = undefined
|
||||
private _apis: RippleAPI[]
|
||||
|
||||
constructor(servers, options) {
|
||||
constructor(servers, options: APIOptions = {}) {
|
||||
super(options)
|
||||
|
||||
const apis: RippleAPI[] = servers.map(server => new RippleAPI(
|
||||
_.assign({}, options, {server})
|
||||
))
|
||||
const apis: RippleAPI[] = servers.map(
|
||||
server => new RippleAPI(_.assign({}, options, {server}))
|
||||
)
|
||||
|
||||
// exposed for testing
|
||||
this._apis = apis
|
||||
|
||||
this.getMethodNames().forEach(name => {
|
||||
this[name] = function() { // eslint-disable-line no-loop-func
|
||||
this[name] = function() {
|
||||
// eslint-disable-line no-loop-func
|
||||
return Promise.race(apis.map(api => api[name](...arguments)))
|
||||
}
|
||||
})
|
||||
@@ -44,13 +43,16 @@ class RippleAPIBroadcast extends RippleAPI {
|
||||
apis.forEach(api => {
|
||||
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 === undefined) {
|
||||
if (
|
||||
ledger.ledgerVersion > this.ledgerVersion ||
|
||||
this.ledgerVersion === undefined
|
||||
) {
|
||||
this.ledgerVersion = ledger.ledgerVersion
|
||||
this.emit('ledger', ledger)
|
||||
}
|
||||
@@ -68,6 +70,4 @@ class RippleAPIBroadcast extends RippleAPI {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
RippleAPIBroadcast
|
||||
}
|
||||
export {RippleAPIBroadcast}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
function setPrototypeOf(object, prototype) {
|
||||
// Object.setPrototypeOf not supported on Internet Explorer 9
|
||||
Object.setPrototypeOf ? Object.setPrototypeOf(object, prototype) :
|
||||
// @ts-ignore: Specifically a fallback for IE9
|
||||
object.__proto__ = prototype
|
||||
Object.setPrototypeOf
|
||||
? Object.setPrototypeOf(object, prototype)
|
||||
: // @ts-ignore: Specifically a fallback for IE9
|
||||
(object.__proto__ = prototype)
|
||||
}
|
||||
|
||||
function getConstructorName(object: object): string {
|
||||
@@ -17,7 +17,4 @@ function getConstructorName(object: object): string {
|
||||
return functionConstructor ? functionConstructor[1] : classConstructor[1]
|
||||
}
|
||||
|
||||
export {
|
||||
getConstructorName,
|
||||
setPrototypeOf
|
||||
}
|
||||
export {getConstructorName, setPrototypeOf}
|
||||
|
||||
@@ -3,12 +3,21 @@ import {EventEmitter} from 'events'
|
||||
import {parse as parseUrl} from 'url'
|
||||
import WebSocket from 'ws'
|
||||
import RangeSet from './rangeset'
|
||||
import {RippledError, DisconnectedError, NotConnectedError,
|
||||
TimeoutError, ResponseFormatError, ConnectionError,
|
||||
RippledNotInitializedError} from './errors'
|
||||
import {
|
||||
RippledError,
|
||||
DisconnectedError,
|
||||
NotConnectedError,
|
||||
TimeoutError,
|
||||
ResponseFormatError,
|
||||
ConnectionError,
|
||||
RippledNotInitializedError
|
||||
} from './errors'
|
||||
|
||||
/**
|
||||
* ConnectionOptions is the configuration for the configuration object.
|
||||
*/
|
||||
export interface ConnectionOptions {
|
||||
trace?: boolean
|
||||
trace?: boolean | ((id: string, message: string) => void)
|
||||
proxy?: string
|
||||
proxyAuthorization?: string
|
||||
authorization?: string
|
||||
@@ -16,63 +25,57 @@ export interface ConnectionOptions {
|
||||
key?: string
|
||||
passphrase?: string
|
||||
certificate?: string
|
||||
timeout?: number,
|
||||
connectionTimeout?: number
|
||||
timeout: number
|
||||
connectionTimeout: number
|
||||
}
|
||||
|
||||
class Connection extends EventEmitter {
|
||||
/**
|
||||
* ConnectionUserOptions is the user-provided configuration object. All configuration
|
||||
* is optional, so any ConnectionOptions configuration that has a default value is
|
||||
* still optional for the user to provide.
|
||||
*/
|
||||
export type ConnectionUserOptions = Partial<ConnectionOptions>
|
||||
|
||||
class Connection extends EventEmitter {
|
||||
private _url: string
|
||||
private _trace: boolean
|
||||
private _console?: Console
|
||||
private _proxyURL?: string
|
||||
private _proxyAuthorization?: string
|
||||
private _authorization?: string
|
||||
private _trustedCertificates?: string[]
|
||||
private _key?: string
|
||||
private _passphrase?: string
|
||||
private _certificate?: string
|
||||
private _timeout: number
|
||||
private _isReady: boolean = false
|
||||
private _ws: null|WebSocket = null
|
||||
protected _ledgerVersion: null|number = null
|
||||
private _ws: null | WebSocket = null
|
||||
protected _ledgerVersion: null | number = null
|
||||
private _availableLedgerVersions = new RangeSet()
|
||||
private _nextRequestID: number = 1
|
||||
private _retry: number = 0
|
||||
private _connectTimer: null|NodeJS.Timer = null
|
||||
private _retryTimer: null|NodeJS.Timer = null
|
||||
private _onOpenErrorBound: null| null|((...args: any[]) => void) = null
|
||||
private _onUnexpectedCloseBound: null|((...args: any[]) => void) = null
|
||||
private _fee_base: null|number = null
|
||||
private _fee_ref: null|number = null
|
||||
private _connectionTimeout: number
|
||||
private _connectTimer: null | NodeJS.Timeout = null
|
||||
private _retryTimer: null | NodeJS.Timeout = null
|
||||
private _heartbeatInterval: null | NodeJS.Timeout = null
|
||||
private _onOpenErrorBound: null | null | ((...args: any[]) => void) = null
|
||||
private _onUnexpectedCloseBound: null | ((...args: any[]) => void) = null
|
||||
private _fee_base: null | number = null
|
||||
private _fee_ref: null | number = null
|
||||
|
||||
constructor(url, options: ConnectionOptions = {}) {
|
||||
private _trace: (id: string, message: string) => void = () => {}
|
||||
private _config: ConnectionOptions
|
||||
|
||||
constructor(url?: string, options: ConnectionUserOptions = {}) {
|
||||
super()
|
||||
this.setMaxListeners(Infinity)
|
||||
this._url = url
|
||||
this._trace = options.trace || false
|
||||
if (this._trace) {
|
||||
// for easier unit testing
|
||||
this._console = console
|
||||
this._config = {
|
||||
timeout: 20 * 1000,
|
||||
connectionTimeout: 2 * 1000,
|
||||
...options
|
||||
}
|
||||
if (typeof options.trace === 'function') {
|
||||
this._trace = options.trace
|
||||
} else if (options.trace === true) {
|
||||
this._trace = console.log
|
||||
}
|
||||
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._connectionTimeout = options.connectionTimeout || 2000
|
||||
}
|
||||
|
||||
_updateLedgerVersions(data) {
|
||||
this._ledgerVersion = Number(data.ledger_index)
|
||||
if (data.validated_ledgers) {
|
||||
this._availableLedgerVersions.reset()
|
||||
this._availableLedgerVersions.parseAndAddRanges(
|
||||
data.validated_ledgers)
|
||||
this._availableLedgerVersions.parseAndAddRanges(data.validated_ledgers)
|
||||
} else {
|
||||
this._availableLedgerVersions.addValue(this._ledgerVersion)
|
||||
}
|
||||
@@ -105,9 +108,7 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
_onMessage(message) {
|
||||
if (this._trace) {
|
||||
this._console!.log(message)
|
||||
}
|
||||
this._trace('receive', message)
|
||||
let parameters
|
||||
try {
|
||||
parameters = this._parseMessage(message)
|
||||
@@ -154,17 +155,17 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
_calculateTimeout(retriesCount) {
|
||||
return (retriesCount < 40)
|
||||
// First, for 2 seconds: 20 times per second
|
||||
? (1000 / 20)
|
||||
: (retriesCount < 40 + 60)
|
||||
// Then, for 1 minute: once per second
|
||||
? (1000)
|
||||
: (retriesCount < 40 + 60 + 60)
|
||||
// Then, for 10 minutes: once every 10 seconds
|
||||
? (10 * 1000)
|
||||
// Then: once every 30 seconds
|
||||
: (30 * 1000)
|
||||
return retriesCount < 40
|
||||
? // First, for 2 seconds: 20 times per second
|
||||
1000 / 20
|
||||
: retriesCount < 40 + 60
|
||||
? // Then, for 1 minute: once per second
|
||||
1000
|
||||
: retriesCount < 40 + 60 + 60
|
||||
? // Then, for 10 minutes: once every 10 seconds
|
||||
10 * 1000
|
||||
: // Then: once every 30 seconds
|
||||
30 * 1000
|
||||
}
|
||||
|
||||
_retryConnect() {
|
||||
@@ -231,8 +232,12 @@ class Connection extends EventEmitter {
|
||||
if (this._onUnexpectedCloseBound) {
|
||||
this._ws.removeListener('close', this._onUnexpectedCloseBound)
|
||||
}
|
||||
this._onUnexpectedCloseBound =
|
||||
this._onUnexpectedClose.bind(this, false, null, null)
|
||||
this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(
|
||||
this,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
)
|
||||
this._ws.once('close', this._onUnexpectedCloseBound)
|
||||
}
|
||||
|
||||
@@ -251,18 +256,21 @@ class Connection extends EventEmitter {
|
||||
|
||||
_createWebSocket(): WebSocket {
|
||||
const options: WebSocket.ClientOptions = {}
|
||||
if (this._proxyURL !== undefined) {
|
||||
if (this._config.proxy !== undefined) {
|
||||
const parsedURL = parseUrl(this._url)
|
||||
const parsedProxyURL = parseUrl(this._proxyURL)
|
||||
const proxyOverrides = _.omitBy({
|
||||
secureEndpoint: (parsedURL.protocol === 'wss:'),
|
||||
secureProxy: (parsedProxyURL.protocol === 'https:'),
|
||||
auth: this._proxyAuthorization,
|
||||
ca: this._trustedCertificates,
|
||||
key: this._key,
|
||||
passphrase: this._passphrase,
|
||||
cert: this._certificate
|
||||
}, _.isUndefined)
|
||||
const parsedProxyURL = parseUrl(this._config.proxy)
|
||||
const proxyOverrides = _.omitBy(
|
||||
{
|
||||
secureEndpoint: parsedURL.protocol === 'wss:',
|
||||
secureProxy: parsedProxyURL.protocol === 'https:',
|
||||
auth: this._config.proxyAuthorization,
|
||||
ca: this._config.trustedCertificates,
|
||||
key: this._config.key,
|
||||
passphrase: this._config.passphrase,
|
||||
cert: this._config.certificate
|
||||
},
|
||||
_.isUndefined
|
||||
)
|
||||
const proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides)
|
||||
let HttpsProxyAgent
|
||||
try {
|
||||
@@ -272,16 +280,19 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
options.agent = new HttpsProxyAgent(proxyOptions)
|
||||
}
|
||||
if (this._authorization !== undefined) {
|
||||
const base64 = Buffer.from(this._authorization).toString('base64')
|
||||
if (this._config.authorization !== undefined) {
|
||||
const base64 = Buffer.from(this._config.authorization).toString('base64')
|
||||
options.headers = {Authorization: `Basic ${base64}`}
|
||||
}
|
||||
const optionsOverrides = _.omitBy({
|
||||
ca: this._trustedCertificates,
|
||||
key: this._key,
|
||||
passphrase: this._passphrase,
|
||||
cert: this._certificate
|
||||
}, _.isUndefined)
|
||||
const optionsOverrides = _.omitBy(
|
||||
{
|
||||
ca: this._config.trustedCertificates,
|
||||
key: this._config.key,
|
||||
passphrase: this._config.passphrase,
|
||||
cert: this._config.certificate
|
||||
},
|
||||
_.isUndefined
|
||||
)
|
||||
const websocketOptions = _.assign({}, options, optionsOverrides)
|
||||
const websocket = new WebSocket(this._url, null, websocketOptions)
|
||||
// we will have a listener for each outstanding request,
|
||||
@@ -295,52 +306,70 @@ class Connection extends EventEmitter {
|
||||
connect(): Promise<void> {
|
||||
this._clearConnectTimer()
|
||||
this._clearReconnectTimer()
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this._connectTimer = setTimeout(() => {
|
||||
reject(new ConnectionError(`Error: connect() timed out after ${this._connectionTimeout} ms. ` +
|
||||
`If your internet connection is working, the rippled server may be blocked or inaccessible.`))
|
||||
}, this._connectionTimeout)
|
||||
if (!this._url) {
|
||||
reject(new ConnectionError(
|
||||
'Cannot connect because no server was specified'))
|
||||
}
|
||||
if (this._state === WebSocket.OPEN) {
|
||||
resolve()
|
||||
} else if (this._state === WebSocket.CONNECTING) {
|
||||
this._ws.once('open', () => resolve)
|
||||
} else {
|
||||
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
|
||||
// connection (end or close)."
|
||||
// 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))
|
||||
// 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', () => {
|
||||
return this._onOpen().then(resolve, reject)
|
||||
this._clearHeartbeatInterval()
|
||||
return (
|
||||
new Promise<void>((_resolve, reject) => {
|
||||
this._connectTimer = setTimeout(() => {
|
||||
reject(
|
||||
new ConnectionError(
|
||||
`Error: connect() timed out after ${this._config.connectionTimeout} ms. ` +
|
||||
`If your internet connection is working, the rippled server may be blocked or inaccessible.`
|
||||
)
|
||||
)
|
||||
}, this._config.connectionTimeout)
|
||||
if (!this._url) {
|
||||
reject(
|
||||
new ConnectionError(
|
||||
'Cannot connect because no server was specified'
|
||||
)
|
||||
)
|
||||
}
|
||||
const resolve = () => {
|
||||
this._startHeartbeatInterval()
|
||||
_resolve()
|
||||
}
|
||||
if (this._state === WebSocket.OPEN) {
|
||||
resolve()
|
||||
} else if (this._state === WebSocket.CONNECTING) {
|
||||
this._ws.once('open', () => resolve)
|
||||
} else {
|
||||
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
|
||||
// connection (end or close)."
|
||||
// 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))
|
||||
// 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', () => {
|
||||
return this._onOpen().then(resolve, reject)
|
||||
})
|
||||
}
|
||||
})
|
||||
// Once we have a resolution or rejection, clear the timeout timer as no
|
||||
// longer needed.
|
||||
.then(() => {
|
||||
this._clearConnectTimer()
|
||||
})
|
||||
}
|
||||
})
|
||||
// Once we have a resolution or rejection, clear the timeout timer as no
|
||||
// longer needed.
|
||||
.then(() => {
|
||||
this._clearConnectTimer()
|
||||
})
|
||||
.catch((err) => {
|
||||
this._clearConnectTimer()
|
||||
throw err;
|
||||
})
|
||||
.catch(err => {
|
||||
this._clearConnectTimer()
|
||||
throw err
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
disconnect(): Promise<void> {
|
||||
@@ -348,6 +377,7 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
_disconnect(calledByUser): Promise<void> {
|
||||
this._clearHeartbeatInterval()
|
||||
if (calledByUser) {
|
||||
this._clearConnectTimer()
|
||||
this._clearReconnectTimer()
|
||||
@@ -377,12 +407,34 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
reconnect() {
|
||||
// NOTE: We currently have a "reconnecting" event, but that only triggers through
|
||||
// _retryConnect, which was written in a way that is required to run as an internal
|
||||
// part of the post-disconnect connect() flow.
|
||||
// See: https://github.com/ripple/ripple-lib/pull/1101#issuecomment-565360423
|
||||
this.emit('reconnect')
|
||||
return this.disconnect().then(() => this.connect())
|
||||
}
|
||||
|
||||
private _clearHeartbeatInterval = () => {
|
||||
clearInterval(this._heartbeatInterval)
|
||||
}
|
||||
|
||||
private _startHeartbeatInterval = () => {
|
||||
this._clearHeartbeatInterval()
|
||||
this._heartbeatInterval = setInterval(() => this._heartbeat(), 1000 * 60)
|
||||
}
|
||||
|
||||
/**
|
||||
* A heartbeat is just a "ping" command, sent on an interval.
|
||||
* If this succeeds, we're good. If it fails, disconnect so that the consumer can reconnect, if desired.
|
||||
*/
|
||||
private _heartbeat = () => {
|
||||
return this.request({command: 'ping'}).catch(() => this.reconnect())
|
||||
}
|
||||
|
||||
_whenReady<T>(promise: Promise<T>): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
promise.catch(reject);
|
||||
promise.catch(reject)
|
||||
if (!this._shouldBeConnected) {
|
||||
reject(new NotConnectedError())
|
||||
} else if (this._state === WebSocket.OPEN && this._isReady) {
|
||||
@@ -398,9 +450,14 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
hasLedgerVersions(lowLedgerVersion, highLedgerVersion): Promise<boolean> {
|
||||
return this._whenReady(Promise.resolve(
|
||||
this._availableLedgerVersions.containsRange(
|
||||
lowLedgerVersion, highLedgerVersion || this._ledgerVersion)))
|
||||
return this._whenReady(
|
||||
Promise.resolve(
|
||||
this._availableLedgerVersions.containsRange(
|
||||
lowLedgerVersion,
|
||||
highLedgerVersion || this._ledgerVersion
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
hasLedgerVersion(ledgerVersion): Promise<boolean> {
|
||||
@@ -416,17 +473,19 @@ class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
_send(message: string): Promise<void> {
|
||||
if (this._trace) {
|
||||
this._console.log(message)
|
||||
}
|
||||
this._trace('send', message)
|
||||
return new Promise((resolve, reject) => {
|
||||
this._ws.send(message, undefined, error => {
|
||||
if (error) {
|
||||
reject(new DisconnectedError(error.message, error))
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
try {
|
||||
this._ws.send(message, undefined, error => {
|
||||
if (error) {
|
||||
reject(new DisconnectedError(error.message, error))
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
reject(new DisconnectedError(error.message, error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -468,12 +527,18 @@ class Connection extends EventEmitter {
|
||||
|
||||
this.once(eventName, response => {
|
||||
if (response.status === 'error') {
|
||||
_reject(new RippledError(response.error_message || response.error, response))
|
||||
_reject(
|
||||
new RippledError(response.error_message || response.error, response)
|
||||
)
|
||||
} else if (response.status === 'success') {
|
||||
_resolve(response.result)
|
||||
} else {
|
||||
_reject(new ResponseFormatError(
|
||||
'unrecognized status: ' + response.status, response))
|
||||
_reject(
|
||||
new ResponseFormatError(
|
||||
'unrecognized status: ' + response.status,
|
||||
response
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -482,14 +547,16 @@ class Connection extends EventEmitter {
|
||||
// JSON.stringify automatically removes keys with value of 'undefined'
|
||||
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)
|
||||
// Node.js won't exit if a timer is still running, so we tell Node to ignore (Node will still wait for the request to complete)
|
||||
if (timer.unref) {
|
||||
timer.unref()
|
||||
}
|
||||
}).catch(_reject)
|
||||
this._whenReady(this._send(message))
|
||||
.then(() => {
|
||||
const delay = timeout || this._config.timeout
|
||||
timer = setTimeout(() => _reject(new TimeoutError()), delay)
|
||||
// Node.js won't exit if a timer is still running, so we tell Node to ignore (Node will still wait for the request to complete)
|
||||
if (timer.unref) {
|
||||
timer.unref()
|
||||
}
|
||||
})
|
||||
.catch(_reject)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
|
||||
import {txFlagIndices} from './txflags'
|
||||
|
||||
// Ordering from https://developers.ripple.com/accountroot.html
|
||||
const accountRootFlags = {
|
||||
|
||||
// lsfDefaultRipple:
|
||||
// Enable rippling on trust lines by default.
|
||||
// Required for issuing addresses; discouraged for others.
|
||||
@@ -73,16 +71,17 @@ const AccountFlagIndices = {
|
||||
}
|
||||
|
||||
const AccountFields = {
|
||||
EmailHash: {name: 'emailHash', encoding: 'hex',
|
||||
length: 32, defaults: '00000000000000000000000000000000'},
|
||||
EmailHash: {
|
||||
name: 'emailHash',
|
||||
encoding: 'hex',
|
||||
length: 32,
|
||||
defaults: '00000000000000000000000000000000'
|
||||
},
|
||||
WalletLocator: {name: 'walletLocator'},
|
||||
MessageKey: {name: 'messageKey'},
|
||||
Domain: {name: 'domain', encoding: 'hex'},
|
||||
TransferRate: {name: 'transferRate', defaults: 0, shift: 9},
|
||||
TickSize: {name: 'tickSize', defaults: 0}
|
||||
}
|
||||
|
||||
export {
|
||||
AccountFields,
|
||||
AccountFlagIndices,
|
||||
AccountFlags
|
||||
}
|
||||
export {AccountFields, AccountFlagIndices, AccountFlags}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
|
||||
import {inspect} from 'util'
|
||||
import * as browserHacks from './browser-hacks'
|
||||
|
||||
class RippleError extends Error {
|
||||
|
||||
name: string
|
||||
message: string
|
||||
data?: any
|
||||
@@ -70,8 +68,11 @@ class MissingLedgerHistoryError extends RippleError {
|
||||
|
||||
class PendingLedgerVersionError extends RippleError {
|
||||
constructor(message?: string) {
|
||||
super(message || 'maxLedgerVersion is greater than server\'s most recent' +
|
||||
' validated ledger')
|
||||
super(
|
||||
message ||
|
||||
"maxLedgerVersion is greater than server's most recent" +
|
||||
' validated ledger'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
* some arbitrary string. For example "TXN".
|
||||
*/
|
||||
|
||||
enum HashPrefix {
|
||||
enum HashPrefix {
|
||||
// transaction plus signature to give transaction ID
|
||||
TRANSACTION_ID = 0x54584E00, // 'TXN'
|
||||
TRANSACTION_ID = 0x54584e00, // 'TXN'
|
||||
|
||||
// transaction plus metadata
|
||||
TRANSACTION_NODE = 0x534E4400, // 'TND'
|
||||
TRANSACTION_NODE = 0x534e4400, // 'TND'
|
||||
|
||||
// inner node in tree
|
||||
INNER_NODE = 0x4D494E00, // 'MIN'
|
||||
INNER_NODE = 0x4d494e00, // 'MIN'
|
||||
|
||||
// leaf node in tree
|
||||
LEAF_NODE = 0x4D4C4E00, // 'MLN'
|
||||
LEAF_NODE = 0x4d4c4e00, // 'MLN'
|
||||
|
||||
// inner transaction to sign
|
||||
TRANSACTION_SIGN = 0x53545800, // 'STX'
|
||||
@@ -31,10 +31,10 @@
|
||||
TRANSACTION_SIGN_TESTNET = 0x73747800, // 'stx'
|
||||
|
||||
// inner transaction to multisign
|
||||
TRANSACTION_MULTISIGN = 0x534D5400, // 'SMT'
|
||||
TRANSACTION_MULTISIGN = 0x534d5400, // 'SMT'
|
||||
|
||||
// ledger
|
||||
LEDGER = 0x4C575200 // 'LWR'
|
||||
LEDGER = 0x4c575200 // 'LWR'
|
||||
}
|
||||
|
||||
export default HashPrefix
|
||||
|
||||
@@ -18,8 +18,11 @@ const bytesToHex = (bytes: number[]): string => {
|
||||
return Buffer.from(bytes).toString('hex')
|
||||
}
|
||||
|
||||
const bigintToHex = (integerString: string | number | BigNumber, byteLength: number): string => {
|
||||
const hex = (new BigNumber(integerString)).toString(16)
|
||||
const bigintToHex = (
|
||||
integerString: string | number | BigNumber,
|
||||
byteLength: number
|
||||
): string => {
|
||||
const hex = new BigNumber(integerString).toString(16)
|
||||
return padLeftZero(hex, byteLength * 2)
|
||||
}
|
||||
|
||||
@@ -28,12 +31,15 @@ const ledgerSpaceHex = (name: string): string => {
|
||||
}
|
||||
|
||||
const addressToHex = (address: string): string => {
|
||||
return (Buffer.from(decodeAccountID(address))).toString('hex')
|
||||
return Buffer.from(decodeAccountID(address)).toString('hex')
|
||||
}
|
||||
|
||||
const currencyToHex = (currency: string): string => {
|
||||
if (currency.length === 3) {
|
||||
const bytes = new Array(20 + 1).join('0').split('').map(parseFloat)
|
||||
const bytes = new Array(20 + 1)
|
||||
.join('0')
|
||||
.split('')
|
||||
.map(parseFloat)
|
||||
bytes[12] = currency.charCodeAt(0) & 0xff
|
||||
bytes[13] = currency.charCodeAt(1) & 0xff
|
||||
bytes[14] = currency.charCodeAt(2) & 0xff
|
||||
@@ -51,7 +57,7 @@ const addLengthPrefix = (hex: string): string => {
|
||||
return bytesToHex([193 + (x >>> 8), x & 0xff]) + hex
|
||||
} else if (length <= 918744) {
|
||||
const x = length - 12481
|
||||
return bytesToHex([241 + (x >>> 16), x >>> 8 & 0xff, x & 0xff]) + hex
|
||||
return bytesToHex([241 + (x >>> 16), (x >>> 8) & 0xff, x & 0xff]) + hex
|
||||
}
|
||||
throw new Error('Variable integer overflow.')
|
||||
}
|
||||
@@ -65,7 +71,9 @@ export const computeTransactionHash = (txJSON: any): string => {
|
||||
return computeBinaryTransactionHash(encode(txJSON))
|
||||
}
|
||||
|
||||
export const computeBinaryTransactionSigningHash = (txBlobHex: string): string => {
|
||||
export const computeBinaryTransactionSigningHash = (
|
||||
txBlobHex: string
|
||||
): string => {
|
||||
const prefix = HashPrefix.TRANSACTION_SIGN.toString(16).toUpperCase()
|
||||
return sha512Half(prefix + txBlobHex)
|
||||
}
|
||||
@@ -79,9 +87,9 @@ export const computeAccountHash = (address: string): string => {
|
||||
}
|
||||
|
||||
export const computeSignerListHash = (address: string): string => {
|
||||
return sha512Half(ledgerSpaceHex('signerList') +
|
||||
addressToHex(address) +
|
||||
'00000000') // uint32(0) signer list index
|
||||
return sha512Half(
|
||||
ledgerSpaceHex('signerList') + addressToHex(address) + '00000000'
|
||||
) // uint32(0) signer list index
|
||||
}
|
||||
|
||||
export const computeOrderHash = (address: string, sequence: number): string => {
|
||||
@@ -89,18 +97,24 @@ export const computeOrderHash = (address: string, sequence: number): string => {
|
||||
return sha512Half(prefix + addressToHex(address) + intToHex(sequence, 4))
|
||||
}
|
||||
|
||||
export const computeTrustlineHash = (address1: string, address2: string, currency: string): string => {
|
||||
export const computeTrustlineHash = (
|
||||
address1: string,
|
||||
address2: string,
|
||||
currency: string
|
||||
): string => {
|
||||
const address1Hex = addressToHex(address1)
|
||||
const address2Hex = addressToHex(address2)
|
||||
|
||||
const swap = (new BigNumber(address1Hex, 16)).isGreaterThan(
|
||||
new BigNumber(address2Hex, 16))
|
||||
const swap = new BigNumber(address1Hex, 16).isGreaterThan(
|
||||
new BigNumber(address2Hex, 16)
|
||||
)
|
||||
const lowAddressHex = swap ? address2Hex : address1Hex
|
||||
const highAddressHex = swap ? address1Hex : address2Hex
|
||||
|
||||
const prefix = ledgerSpaceHex('rippleState')
|
||||
return sha512Half(prefix + lowAddressHex + highAddressHex +
|
||||
currencyToHex(currency))
|
||||
return sha512Half(
|
||||
prefix + lowAddressHex + highAddressHex + currencyToHex(currency)
|
||||
)
|
||||
}
|
||||
|
||||
export const computeTransactionTreeHash = (transactions: any[]): string => {
|
||||
@@ -131,25 +145,35 @@ export const computeStateTreeHash = (entries: any[]): string => {
|
||||
// see rippled Ledger::updateHash()
|
||||
export const computeLedgerHash = (ledgerHeader): string => {
|
||||
const prefix = HashPrefix.LEDGER.toString(16).toUpperCase()
|
||||
return sha512Half(prefix +
|
||||
intToHex(ledgerHeader.ledger_index, 4) +
|
||||
bigintToHex(ledgerHeader.total_coins, 8) +
|
||||
ledgerHeader.parent_hash +
|
||||
ledgerHeader.transaction_hash +
|
||||
ledgerHeader.account_hash +
|
||||
intToHex(ledgerHeader.parent_close_time, 4) +
|
||||
intToHex(ledgerHeader.close_time, 4) +
|
||||
intToHex(ledgerHeader.close_time_resolution, 1) +
|
||||
intToHex(ledgerHeader.close_flags, 1)
|
||||
return sha512Half(
|
||||
prefix +
|
||||
intToHex(ledgerHeader.ledger_index, 4) +
|
||||
bigintToHex(ledgerHeader.total_coins, 8) +
|
||||
ledgerHeader.parent_hash +
|
||||
ledgerHeader.transaction_hash +
|
||||
ledgerHeader.account_hash +
|
||||
intToHex(ledgerHeader.parent_close_time, 4) +
|
||||
intToHex(ledgerHeader.close_time, 4) +
|
||||
intToHex(ledgerHeader.close_time_resolution, 1) +
|
||||
intToHex(ledgerHeader.close_flags, 1)
|
||||
)
|
||||
}
|
||||
|
||||
export const computeEscrowHash = (address, sequence): string => {
|
||||
return sha512Half(ledgerSpaceHex('escrow') + addressToHex(address) +
|
||||
intToHex(sequence, 4))
|
||||
return sha512Half(
|
||||
ledgerSpaceHex('escrow') + addressToHex(address) + intToHex(sequence, 4)
|
||||
)
|
||||
}
|
||||
|
||||
export const computePaymentChannelHash = (address, dstAddress, sequence): string => {
|
||||
return sha512Half(ledgerSpaceHex('paychan') + addressToHex(address) +
|
||||
addressToHex(dstAddress) + intToHex(sequence, 4))
|
||||
export const computePaymentChannelHash = (
|
||||
address,
|
||||
dstAddress,
|
||||
sequence
|
||||
): string => {
|
||||
return sha512Half(
|
||||
ledgerSpaceHex('paychan') +
|
||||
addressToHex(address) +
|
||||
addressToHex(dstAddress) +
|
||||
intToHex(sequence, 4)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/**
|
||||
* Ripple ledger namespace prefixes.
|
||||
*
|
||||
@@ -8,18 +7,18 @@
|
||||
* Each namespace is just a single character prefix.
|
||||
*/
|
||||
export default {
|
||||
account : 'a',
|
||||
dirNode : 'd',
|
||||
generatorMap : 'g',
|
||||
rippleState : 'r',
|
||||
offer : 'o', // Entry for an offer.
|
||||
ownerDir : 'O', // Directory of things owned by an account.
|
||||
bookDir : 'B', // Directory of order books.
|
||||
contract : 'c',
|
||||
skipList : 's',
|
||||
amendment : 'f',
|
||||
feeSettings : 'e',
|
||||
signerList : 'S',
|
||||
escrow : 'u',
|
||||
paychan : 'x'
|
||||
account: 'a',
|
||||
dirNode: 'd',
|
||||
generatorMap: 'g',
|
||||
rippleState: 'r',
|
||||
offer: 'o', // Entry for an offer.
|
||||
ownerDir: 'O', // Directory of things owned by an account.
|
||||
bookDir: 'B', // Directory of order books.
|
||||
contract: 'c',
|
||||
skipList: 's',
|
||||
amendment: 'f',
|
||||
feeSettings: 'e',
|
||||
signerList: 'S',
|
||||
escrow: 'u',
|
||||
paychan: 'x'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import {createHash} from 'crypto'
|
||||
|
||||
const sha512Half = (hex: string): string => {
|
||||
return createHash('sha512').update(Buffer.from(hex, 'hex')).digest('hex').toUpperCase().slice(0, 64)
|
||||
return createHash('sha512')
|
||||
.update(Buffer.from(hex, 'hex'))
|
||||
.digest('hex')
|
||||
.toUpperCase()
|
||||
.slice(0, 64)
|
||||
}
|
||||
|
||||
export default sha512Half
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import hashPrefix from './hash-prefix'
|
||||
import sha512Half from './sha512Half'
|
||||
const HEX_ZERO = '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
const HEX_ZERO =
|
||||
'0000000000000000000000000000000000000000000000000000000000000000'
|
||||
|
||||
export enum NodeType {
|
||||
INNER = 1,
|
||||
@@ -18,15 +19,17 @@ export abstract class Node {
|
||||
public constructor() {}
|
||||
|
||||
public addItem(_tag: string, _node: Node): void {
|
||||
throw new Error('Called unimplemented virtual method SHAMapTreeNode#addItem.')
|
||||
throw new Error(
|
||||
'Called unimplemented virtual method SHAMapTreeNode#addItem.'
|
||||
)
|
||||
}
|
||||
public get hash(): string|void {
|
||||
throw new Error('Called unimplemented virtual method SHAMapTreeNode#hash.');
|
||||
public get hash(): string | void {
|
||||
throw new Error('Called unimplemented virtual method SHAMapTreeNode#hash.')
|
||||
}
|
||||
}
|
||||
|
||||
export class InnerNode extends Node {
|
||||
public leaves: { [slot: number]: Node }
|
||||
public leaves: {[slot: number]: Node}
|
||||
public type: NodeType
|
||||
public depth: number
|
||||
public empty: boolean
|
||||
@@ -48,9 +51,10 @@ export class InnerNode extends Node {
|
||||
* @param {string} tag equates to a ledger entry `index`
|
||||
* @param {Node} node to add
|
||||
* @return {void}
|
||||
*/
|
||||
*/
|
||||
|
||||
public addItem(tag: string, node: Node): void {
|
||||
const existingNode = this.getNode(parseInt(tag[this.depth],16))
|
||||
const existingNode = this.getNode(parseInt(tag[this.depth], 16))
|
||||
if (existingNode) {
|
||||
// A node already exists in this slot
|
||||
if (existingNode instanceof InnerNode) {
|
||||
@@ -60,15 +64,16 @@ export class InnerNode extends Node {
|
||||
if (existingNode.tag === tag) {
|
||||
// Collision
|
||||
throw new Error(
|
||||
'Tried to add a node to a SHAMap that was already in there.')
|
||||
'Tried to add a node to a SHAMap that was already in there.'
|
||||
)
|
||||
} else {
|
||||
// Turn it into an inner node
|
||||
const newInnerNode = new InnerNode(this.depth + 1)
|
||||
|
||||
|
||||
// Parent new and existing node
|
||||
newInnerNode.addItem(existingNode.tag, existingNode)
|
||||
newInnerNode.addItem(tag, node)
|
||||
|
||||
|
||||
// And place the newly created inner node in the slot
|
||||
this.setNode(parseInt(tag[this.depth], 16), newInnerNode)
|
||||
}
|
||||
@@ -87,7 +92,7 @@ export class InnerNode extends Node {
|
||||
*/
|
||||
public setNode(slot: number, node: Node): void {
|
||||
if (slot < 0 || slot > 15) {
|
||||
throw new Error ('Invalid slot: slot must be between 0-15.')
|
||||
throw new Error('Invalid slot: slot must be between 0-15.')
|
||||
}
|
||||
this.leaves[slot] = node
|
||||
this.empty = false
|
||||
@@ -100,8 +105,8 @@ export class InnerNode extends Node {
|
||||
*/
|
||||
public getNode(slot: number): Node {
|
||||
if (slot < 0 || slot > 15) {
|
||||
throw new Error ('Invalid slot: slot must be between 0-15.')
|
||||
}
|
||||
throw new Error('Invalid slot: slot must be between 0-15.')
|
||||
}
|
||||
return this.leaves[slot]
|
||||
}
|
||||
|
||||
@@ -113,7 +118,7 @@ export class InnerNode extends Node {
|
||||
}
|
||||
const prefix = hashPrefix.INNER_NODE.toString(16)
|
||||
return sha512Half(prefix + hex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Leaf extends Node {
|
||||
@@ -135,21 +140,24 @@ export class Leaf extends Node {
|
||||
this.data = data
|
||||
}
|
||||
|
||||
public get hash(): string|void {
|
||||
public get hash(): string | void {
|
||||
switch (this.type) {
|
||||
case NodeType.ACCOUNT_STATE:
|
||||
case NodeType.ACCOUNT_STATE: {
|
||||
const leafPrefix = hashPrefix.LEAF_NODE.toString(16)
|
||||
return sha512Half(leafPrefix + this.data + this.tag)
|
||||
case NodeType.TRANSACTION_NO_METADATA:
|
||||
}
|
||||
case NodeType.TRANSACTION_NO_METADATA: {
|
||||
const txIDPrefix = hashPrefix.TRANSACTION_ID.toString(16)
|
||||
return sha512Half(txIDPrefix + this.data)
|
||||
case NodeType.TRANSACTION_METADATA:
|
||||
}
|
||||
case NodeType.TRANSACTION_METADATA: {
|
||||
const txNodePrefix = hashPrefix.TRANSACTION_NODE.toString(16)
|
||||
return sha512Half(txNodePrefix + this.data + this.tag)
|
||||
}
|
||||
default:
|
||||
throw new Error('Tried to hash a SHAMap node of unknown type.')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SHAMap {
|
||||
|
||||
@@ -6,16 +6,15 @@ import {xAddressToClassicAddress, isValidXAddress} from 'ripple-address-codec'
|
||||
|
||||
export function ensureClassicAddress(account: string): string {
|
||||
if (isValidXAddress(account)) {
|
||||
const {
|
||||
classicAddress,
|
||||
tag
|
||||
} = xAddressToClassicAddress(account)
|
||||
const {classicAddress, tag} = xAddressToClassicAddress(account)
|
||||
|
||||
// Except for special cases, X-addresses used for requests
|
||||
// must not have an embedded tag. In other words,
|
||||
// `tag` should be `false`.
|
||||
if (tag !== false) {
|
||||
throw new Error('This command does not support the use of a tag. Use an address without a tag.')
|
||||
throw new Error(
|
||||
'This command does not support the use of a tag. Use an address without a tag.'
|
||||
)
|
||||
}
|
||||
|
||||
// For rippled requests that use an account, always use a classic address.
|
||||
@@ -25,12 +24,7 @@ export function ensureClassicAddress(account: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
constants,
|
||||
errors,
|
||||
validate,
|
||||
serverInfo
|
||||
}
|
||||
export {constants, errors, validate, serverInfo}
|
||||
export {
|
||||
dropsToXrp,
|
||||
xrpToDrops,
|
||||
|
||||
@@ -18,7 +18,6 @@ function mergeIntervals(intervals: Interval[]): Interval[] {
|
||||
}
|
||||
|
||||
class RangeSet {
|
||||
|
||||
ranges: Array<[number, number]>
|
||||
|
||||
constructor() {
|
||||
@@ -30,8 +29,9 @@ class RangeSet {
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return this.ranges.map(range =>
|
||||
range[0].toString() + '-' + range[1].toString()).join(',')
|
||||
return this.ranges
|
||||
.map(range => range[0].toString() + '-' + range[1].toString())
|
||||
.join(',')
|
||||
}
|
||||
|
||||
addRange(start: number, end: number) {
|
||||
|
||||
@@ -62,6 +62,8 @@ function loadSchemas() {
|
||||
require('./schemas/specifications/check-cash.json'),
|
||||
require('./schemas/specifications/check-cancel.json'),
|
||||
require('./schemas/specifications/trustline.json'),
|
||||
require('./schemas/specifications/deposit-preauth.json'),
|
||||
require('./schemas/specifications/account-delete.json'),
|
||||
require('./schemas/output/sign.json'),
|
||||
require('./schemas/output/submit.json'),
|
||||
require('./schemas/output/get-account-info.json'),
|
||||
@@ -175,8 +177,4 @@ function isValidAddress(address: string): boolean {
|
||||
return isValidXAddress(address) || isValidClassicAddress(address)
|
||||
}
|
||||
|
||||
export {
|
||||
schemaValidate,
|
||||
isValidSecret,
|
||||
isValidAddress
|
||||
}
|
||||
export {schemaValidate, isValidSecret, isValidAddress}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"domain": {
|
||||
"type": "string",
|
||||
"description": " The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
|
||||
"description": "The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
|
||||
},
|
||||
"emailHash": {
|
||||
"description": "Hash of an email address to be used for generating an avatar image. Conventionally, clients use Gravatar to display this image. Use `null` to clear.",
|
||||
@@ -30,6 +30,13 @@
|
||||
{"$ref": "hash128"}
|
||||
]
|
||||
},
|
||||
"walletLocator": {
|
||||
"description": "Transaction hash or any other 64 character hexadecimal string, that may or may not represent the result of a hash operation. Use `null` to clear.",
|
||||
"oneOf": [
|
||||
{"type": "null"},
|
||||
{"$ref": "hash256"}
|
||||
]
|
||||
},
|
||||
"enableTransactionIDTracking": {
|
||||
"type": "boolean",
|
||||
"description": "Track the ID of this account’s most recent transaction."
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
"paymentChannelClaim",
|
||||
"checkCreate",
|
||||
"checkCancel",
|
||||
"checkCash"
|
||||
"checkCash",
|
||||
"depositPreauth",
|
||||
"accountDelete"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -208,6 +208,30 @@
|
||||
"$ref": "paymentChannelClaim"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [
|
||||
"depositPreauth"
|
||||
]
|
||||
},
|
||||
"specification": {
|
||||
"$ref": "depositPreauth"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [
|
||||
"accountDelete"
|
||||
]
|
||||
},
|
||||
"specification": {
|
||||
"$ref": "accountDelete"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
29
src/common/schemas/specifications/account-delete.json
Normal file
29
src/common/schemas/specifications/account-delete.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "accountDelete",
|
||||
"link": "account-delete",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"destination": {
|
||||
"$ref": "address",
|
||||
"description": "Address of an account to receive any leftover XRP after deleting the sending account. Must be a funded account in the ledger, and must not be the sending account."
|
||||
},
|
||||
"destinationTag": {
|
||||
"$ref": "tag",
|
||||
"description": "(Optional) Arbitrary destination tag that identifies a hosted recipient or other information for the recipient of the deleted account's leftover XRP."
|
||||
},
|
||||
"destinationXAddress": {
|
||||
"$ref": "address",
|
||||
"description": "X-address of an account to receive any leftover XRP after deleting the sending account. Must be a funded account in the ledger, and must not be the sending account."
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": ["destination"]
|
||||
},
|
||||
{
|
||||
"required": ["destinationXAddress"]
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
21
src/common/schemas/specifications/deposit-preauth.json
Normal file
21
src/common/schemas/specifications/deposit-preauth.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "depositPreauth",
|
||||
"link": "deposit-preauth",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorize": {
|
||||
"$ref": "address",
|
||||
"description": "Address of the account that can cash the check."
|
||||
},
|
||||
"unauthorize": {
|
||||
"$ref": "address",
|
||||
"description": "Address of the account that can cash the check."
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{"required": ["authorize"]},
|
||||
{"required": ["unauthorize"]}
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -4,32 +4,33 @@ import BigNumber from 'bignumber.js'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type GetServerInfoResponse = {
|
||||
buildVersion: string,
|
||||
completeLedgers: string,
|
||||
hostID: string,
|
||||
ioLatencyMs: number,
|
||||
buildVersion: string
|
||||
completeLedgers: string
|
||||
hostID: string
|
||||
ioLatencyMs: number
|
||||
load?: {
|
||||
jobTypes: Array<object>,
|
||||
jobTypes: Array<object>
|
||||
threads: number
|
||||
},
|
||||
}
|
||||
lastClose: {
|
||||
convergeTimeS: number,
|
||||
convergeTimeS: number
|
||||
proposers: number
|
||||
},
|
||||
loadFactor: number,
|
||||
peers: number,
|
||||
pubkeyNode: string,
|
||||
pubkeyValidator?: string,
|
||||
serverState: string,
|
||||
}
|
||||
loadFactor: number
|
||||
peers: number
|
||||
pubkeyNode: string
|
||||
pubkeyValidator?: string
|
||||
serverState: string
|
||||
validatedLedger: {
|
||||
age: number,
|
||||
baseFeeXRP: string,
|
||||
hash: string,
|
||||
reserveBaseXRP: string,
|
||||
reserveIncrementXRP: string,
|
||||
age: number
|
||||
baseFeeXRP: string
|
||||
hash: string
|
||||
reserveBaseXRP: string
|
||||
reserveIncrementXRP: string
|
||||
ledgerVersion: number
|
||||
},
|
||||
}
|
||||
validationQuorum: number
|
||||
networkLedger?: string
|
||||
}
|
||||
|
||||
function renameKeys(object, mapping) {
|
||||
@@ -50,12 +51,9 @@ function getServerInfo(this: RippleAPI): Promise<GetServerInfoResponse> {
|
||||
reserveIncXrp: 'reserveIncrementXRP',
|
||||
seq: 'ledgerVersion'
|
||||
})
|
||||
info.validatedLedger.baseFeeXRP =
|
||||
info.validatedLedger.baseFeeXRP.toString()
|
||||
info.validatedLedger.reserveBaseXRP =
|
||||
info.validatedLedger.reserveBaseXRP.toString()
|
||||
info.validatedLedger.reserveIncrementXRP =
|
||||
info.validatedLedger.reserveIncrementXRP.toString()
|
||||
info.validatedLedger.baseFeeXRP = info.validatedLedger.baseFeeXRP.toString()
|
||||
info.validatedLedger.reserveBaseXRP = info.validatedLedger.reserveBaseXRP.toString()
|
||||
info.validatedLedger.reserveIncrementXRP = info.validatedLedger.reserveIncrementXRP.toString()
|
||||
}
|
||||
return info
|
||||
})
|
||||
@@ -63,10 +61,7 @@ function getServerInfo(this: RippleAPI): Promise<GetServerInfoResponse> {
|
||||
|
||||
// This is a public API that can be called directly.
|
||||
// This is not used by the `prepare*` methods. See `src/transaction/utils.ts`
|
||||
async function getFee(
|
||||
this: RippleAPI,
|
||||
cushion?: number
|
||||
): Promise<string> {
|
||||
async function getFee(this: RippleAPI, cushion?: number): Promise<string> {
|
||||
if (cushion === undefined) {
|
||||
cushion = this._feeCushion
|
||||
}
|
||||
@@ -81,10 +76,7 @@ async function getFee(
|
||||
// Cap fee to `this._maxFeeXRP`
|
||||
fee = BigNumber.min(fee, this._maxFeeXRP)
|
||||
// Round fee to 6 decimal places
|
||||
return (new BigNumber(fee.toFixed(6))).toString(10)
|
||||
return new BigNumber(fee.toFixed(6)).toString(10)
|
||||
}
|
||||
|
||||
export {
|
||||
getServerInfo,
|
||||
getFee
|
||||
}
|
||||
export {getServerInfo, getFee}
|
||||
|
||||
@@ -58,7 +58,4 @@ const txFlagIndices = {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
txFlags,
|
||||
txFlagIndices
|
||||
}
|
||||
export {txFlags, txFlagIndices}
|
||||
|
||||
@@ -5,19 +5,19 @@ import {
|
||||
} from '../objects'
|
||||
|
||||
export interface AccountInfoRequest {
|
||||
account: string,
|
||||
strict?: boolean,
|
||||
queue?: boolean,
|
||||
ledger_hash?: string,
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current'),
|
||||
account: string
|
||||
strict?: boolean
|
||||
queue?: boolean
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
signer_lists?: boolean
|
||||
}
|
||||
|
||||
export interface AccountInfoResponse {
|
||||
account_data: AccountRootLedgerEntry,
|
||||
signer_lists?: SignerListLedgerEntry[],
|
||||
ledger_current_index?: number,
|
||||
ledger_index?: number,
|
||||
queue_data?: QueueData,
|
||||
account_data: AccountRootLedgerEntry
|
||||
signer_lists?: SignerListLedgerEntry[]
|
||||
ledger_current_index?: number
|
||||
ledger_index?: number
|
||||
queue_data?: QueueData
|
||||
validated?: boolean
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import {Trustline} from '../objects'
|
||||
|
||||
export interface AccountLinesRequest {
|
||||
account: string,
|
||||
ledger_hash?: string,
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current'),
|
||||
peer?: string,
|
||||
limit?: number,
|
||||
marker?: any,
|
||||
account: string
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
peer?: string
|
||||
limit?: number
|
||||
marker?: any
|
||||
}
|
||||
|
||||
export interface AccountLinesResponse {
|
||||
account: string,
|
||||
lines: Trustline[],
|
||||
ledger_current_index?: number,
|
||||
ledger_index?: number,
|
||||
ledger_hash?: string,
|
||||
marker?: any,
|
||||
account: string
|
||||
lines: Trustline[]
|
||||
ledger_current_index?: number
|
||||
ledger_index?: number
|
||||
ledger_hash?: string
|
||||
marker?: any
|
||||
}
|
||||
|
||||
@@ -1,84 +1,91 @@
|
||||
import {
|
||||
CheckLedgerEntry, RippleStateLedgerEntry,
|
||||
OfferLedgerEntry, SignerListLedgerEntry,
|
||||
EscrowLedgerEntry, PayChannelLedgerEntry,
|
||||
CheckLedgerEntry,
|
||||
RippleStateLedgerEntry,
|
||||
OfferLedgerEntry,
|
||||
SignerListLedgerEntry,
|
||||
EscrowLedgerEntry,
|
||||
PayChannelLedgerEntry,
|
||||
DepositPreauthLedgerEntry
|
||||
} from '../objects'
|
||||
|
||||
export interface GetAccountObjectsOptions {
|
||||
type?: string | (
|
||||
'check' |
|
||||
'escrow' |
|
||||
'offer' |
|
||||
'payment_channel' |
|
||||
'signer_list' |
|
||||
'state'
|
||||
),
|
||||
ledgerHash?: string,
|
||||
ledgerIndex?: number | ('validated' | 'closed' | 'current'),
|
||||
limit?: number,
|
||||
type?:
|
||||
| string
|
||||
| (
|
||||
| 'check'
|
||||
| 'escrow'
|
||||
| 'offer'
|
||||
| 'payment_channel'
|
||||
| 'signer_list'
|
||||
| 'state'
|
||||
)
|
||||
ledgerHash?: string
|
||||
ledgerIndex?: number | ('validated' | 'closed' | 'current')
|
||||
limit?: number
|
||||
marker?: string
|
||||
}
|
||||
|
||||
export interface AccountObjectsRequest {
|
||||
account: string,
|
||||
account: string
|
||||
|
||||
// (Optional) Filter results to include only this type of ledger object.
|
||||
type?: string | (
|
||||
'check' |
|
||||
'escrow' |
|
||||
'offer' |
|
||||
'payment_channel' |
|
||||
'signer_list' |
|
||||
'state'
|
||||
),
|
||||
type?:
|
||||
| string
|
||||
| (
|
||||
| 'check'
|
||||
| 'escrow'
|
||||
| 'offer'
|
||||
| 'payment_channel'
|
||||
| 'signer_list'
|
||||
| 'state'
|
||||
)
|
||||
|
||||
// (Optional) A 20-byte hex string for the ledger version to use.
|
||||
ledger_hash?: string,
|
||||
ledger_hash?: string
|
||||
|
||||
// (Optional) The sequence number of the ledger to use,
|
||||
// or a shortcut string to choose a ledger automatically.
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current'),
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
|
||||
limit?: number,
|
||||
limit?: number
|
||||
|
||||
marker?: string
|
||||
}
|
||||
|
||||
export interface AccountObjectsResponse {
|
||||
account: string,
|
||||
account: string
|
||||
|
||||
// Array of objects owned by this account.
|
||||
// from the getAccountObjects section of the dev center
|
||||
account_objects: Array<
|
||||
CheckLedgerEntry |
|
||||
RippleStateLedgerEntry |
|
||||
OfferLedgerEntry |
|
||||
SignerListLedgerEntry |
|
||||
EscrowLedgerEntry |
|
||||
PayChannelLedgerEntry |
|
||||
DepositPreauthLedgerEntry
|
||||
>,
|
||||
| CheckLedgerEntry
|
||||
| RippleStateLedgerEntry
|
||||
| OfferLedgerEntry
|
||||
| SignerListLedgerEntry
|
||||
| EscrowLedgerEntry
|
||||
| PayChannelLedgerEntry
|
||||
| DepositPreauthLedgerEntry
|
||||
>
|
||||
|
||||
// (May be omitted) The identifying hash of the ledger
|
||||
// that was used to generate this response.
|
||||
ledger_hash?: string,
|
||||
ledger_hash?: string
|
||||
|
||||
// (May be omitted) The sequence number of the ledger version
|
||||
// that was used to generate this response.
|
||||
ledger_index?: number,
|
||||
ledger_index?: number
|
||||
|
||||
// (May be omitted) The sequence number of the current in-progress ledger
|
||||
// version that was used to generate this response.
|
||||
ledger_current_index?: number,
|
||||
ledger_current_index?: number
|
||||
|
||||
// The limit that was used in this request, if any.
|
||||
limit?: number,
|
||||
limit?: number
|
||||
|
||||
// Server-defined value indicating the response is paginated. Pass this
|
||||
// to the next call to resume where this call left off. Omitted when there
|
||||
// are no additional pages after this one.
|
||||
marker?: string,
|
||||
marker?: string
|
||||
|
||||
// If true, this information comes from a ledger version
|
||||
// that has been validated by consensus.
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import {RippledAmount} from '../objects'
|
||||
|
||||
export interface AccountOffersRequest {
|
||||
account: string,
|
||||
ledger_hash?: string,
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current'),
|
||||
limit?: number,
|
||||
marker?: any,
|
||||
account: string
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
limit?: number
|
||||
marker?: any
|
||||
}
|
||||
|
||||
export interface AccountOffersResponse {
|
||||
account: string,
|
||||
ledger_hash?: string,
|
||||
ledger_current_index?: number,
|
||||
ledger_index?: number,
|
||||
marker?: any,
|
||||
offers?: AccountOffer[],
|
||||
account: string
|
||||
ledger_hash?: string
|
||||
ledger_current_index?: number
|
||||
ledger_index?: number
|
||||
marker?: any
|
||||
offers?: AccountOffer[]
|
||||
}
|
||||
|
||||
export interface AccountOffer {
|
||||
seq: number,
|
||||
flags: number,
|
||||
taker_gets: RippledAmount,
|
||||
taker_pays: RippledAmount,
|
||||
quality: string,
|
||||
seq: number
|
||||
flags: number
|
||||
taker_gets: RippledAmount
|
||||
taker_pays: RippledAmount
|
||||
quality: string
|
||||
expiration?: number
|
||||
}
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
import {
|
||||
TakerRequestAmount,
|
||||
RippledAmount,
|
||||
OfferLedgerEntry
|
||||
} from '../objects'
|
||||
import {TakerRequestAmount, RippledAmount, OfferLedgerEntry} from '../objects'
|
||||
|
||||
export interface BookOffersRequest {
|
||||
taker?: string,
|
||||
taker_gets: TakerRequestAmount,
|
||||
taker_pays: TakerRequestAmount,
|
||||
ledger_hash?: string,
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current'),
|
||||
limit?: number,
|
||||
taker?: string
|
||||
taker_gets: TakerRequestAmount
|
||||
taker_pays: TakerRequestAmount
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
limit?: number
|
||||
marker?: any
|
||||
}
|
||||
|
||||
export interface BookOffersResponse {
|
||||
offers: BookOffer[],
|
||||
ledger_hash?: string,
|
||||
ledger_current_index?: number,
|
||||
ledger_index?: number,
|
||||
offers: BookOffer[]
|
||||
ledger_hash?: string
|
||||
ledger_current_index?: number
|
||||
ledger_index?: number
|
||||
marker?: any
|
||||
}
|
||||
|
||||
export interface BookOffer extends OfferLedgerEntry {
|
||||
quality?: string
|
||||
owner_funds?: string,
|
||||
taker_gets_funded?: RippledAmount,
|
||||
owner_funds?: string
|
||||
taker_gets_funded?: RippledAmount
|
||||
taker_pays_funded?: RippledAmount
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import {Amount} from '../objects'
|
||||
|
||||
export interface GatewayBalancesRequest {
|
||||
account: string,
|
||||
strict?: boolean,
|
||||
hotwallet: string|Array<string>,
|
||||
ledger_hash?: string,
|
||||
account: string
|
||||
strict?: boolean
|
||||
hotwallet: string | Array<string>
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
}
|
||||
|
||||
export interface GatewayBalancesResponse {
|
||||
account: string,
|
||||
obligations?: {[currency: string]: string},
|
||||
balances?: {[address: string]: Amount[]},
|
||||
assets?: {[address: string]: Amount[]},
|
||||
ledger_hash?: string,
|
||||
ledger_current_index?: number,
|
||||
account: string
|
||||
obligations?: {[currency: string]: string}
|
||||
balances?: {[address: string]: Amount[]}
|
||||
assets?: {[address: string]: Amount[]}
|
||||
ledger_hash?: string
|
||||
ledger_current_index?: number
|
||||
ledger_index?: number
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@ export * from './account_offers'
|
||||
export * from './book_offers'
|
||||
export * from './gateway_balances'
|
||||
export * from './ledger'
|
||||
export * from './ledger_data'
|
||||
export * from './ledger_entry'
|
||||
export * from './server_info'
|
||||
|
||||
12
src/common/types/commands/ledger_data.ts
Normal file
12
src/common/types/commands/ledger_data.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {LedgerData} from '../objects'
|
||||
|
||||
export interface LedgerDataRequest {
|
||||
id?: any
|
||||
ledger_hash?: string
|
||||
ledger_index?: string
|
||||
binary?: boolean
|
||||
limit?: number
|
||||
marker?: string
|
||||
}
|
||||
|
||||
export type LedgerDataResponse = LedgerData
|
||||
@@ -3,29 +3,34 @@ import {LedgerEntry} from '../objects'
|
||||
export interface LedgerEntryRequest {
|
||||
ledger_hash?: string
|
||||
ledger_index?: number | ('validated' | 'closed' | 'current')
|
||||
index?: string,
|
||||
account_root?: string,
|
||||
directory?: string | {
|
||||
sub_index?: number,
|
||||
dir_root: string
|
||||
} | {
|
||||
sub_index?: number,
|
||||
owner: string
|
||||
},
|
||||
offer?: string | {
|
||||
account: string,
|
||||
seq: number
|
||||
},
|
||||
index?: string
|
||||
account_root?: string
|
||||
directory?:
|
||||
| string
|
||||
| {
|
||||
sub_index?: number
|
||||
dir_root: string
|
||||
}
|
||||
| {
|
||||
sub_index?: number
|
||||
owner: string
|
||||
}
|
||||
offer?:
|
||||
| string
|
||||
| {
|
||||
account: string
|
||||
seq: number
|
||||
}
|
||||
ripple_state?: {
|
||||
accounts: [string, string],
|
||||
accounts: [string, string]
|
||||
currency: string
|
||||
},
|
||||
}
|
||||
binary?: boolean
|
||||
}
|
||||
|
||||
export interface LedgerEntryResponse {
|
||||
index: string,
|
||||
ledger_index: number,
|
||||
node_binary?: string,
|
||||
node?: LedgerEntry,
|
||||
index: string
|
||||
ledger_index: number
|
||||
node_binary?: string
|
||||
node?: LedgerEntry
|
||||
}
|
||||
|
||||
@@ -4,48 +4,48 @@ export interface ServerInfoRequest {
|
||||
|
||||
export interface ServerInfoResponse {
|
||||
info: {
|
||||
amendment_blocked?: boolean,
|
||||
build_version: string,
|
||||
closed_ledger?: LedgerInfo,
|
||||
complete_ledgers: string,
|
||||
hostid: string,
|
||||
io_latency_ms: number,
|
||||
amendment_blocked?: boolean
|
||||
build_version: string
|
||||
closed_ledger?: LedgerInfo
|
||||
complete_ledgers: string
|
||||
hostid: string
|
||||
io_latency_ms: number
|
||||
last_close: {
|
||||
converge_time_s: number,
|
||||
converge_time_s: number
|
||||
proposers: number
|
||||
},
|
||||
}
|
||||
load?: {
|
||||
job_types: {
|
||||
job_type: string,
|
||||
per_second: number,
|
||||
job_type: string
|
||||
per_second: number
|
||||
in_progress: number
|
||||
}[],
|
||||
}[]
|
||||
threads: number
|
||||
},
|
||||
load_factor: number,
|
||||
load_factor_local?: number,
|
||||
load_factor_net?: number,
|
||||
load_factor_cluster?: number,
|
||||
load_factor_fee_escalation?: number,
|
||||
load_factor_fee_queue?: number,
|
||||
load_factor_server?: number,
|
||||
peers: number,
|
||||
pubkey_node: string,
|
||||
pubkey_validator: string,
|
||||
server_state: string,
|
||||
state_accounting: any,
|
||||
uptime: number,
|
||||
validated_ledger?: LedgerInfo,
|
||||
validation_quorum: number,
|
||||
}
|
||||
load_factor: number
|
||||
load_factor_local?: number
|
||||
load_factor_net?: number
|
||||
load_factor_cluster?: number
|
||||
load_factor_fee_escalation?: number
|
||||
load_factor_fee_queue?: number
|
||||
load_factor_server?: number
|
||||
peers: number
|
||||
pubkey_node: string
|
||||
pubkey_validator: string
|
||||
server_state: string
|
||||
state_accounting: any
|
||||
uptime: number
|
||||
validated_ledger?: LedgerInfo
|
||||
validation_quorum: number
|
||||
validator_list_expires: string
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export interface LedgerInfo {
|
||||
age: number,
|
||||
base_fee_xrp: number,
|
||||
hash: string,
|
||||
reserve_base_xrp: number,
|
||||
reserve_inc_xrp: number,
|
||||
seq: number,
|
||||
age: number
|
||||
base_fee_xrp: number
|
||||
hash: string
|
||||
reserve_base_xrp: number
|
||||
reserve_inc_xrp: number
|
||||
seq: number
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import {Amount} from './amounts'
|
||||
|
||||
export type Adjustment = {
|
||||
address: string,
|
||||
amount: Amount,
|
||||
address: string
|
||||
amount: Amount
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type MaxAdjustment = {
|
||||
address: string,
|
||||
maxAmount: Amount,
|
||||
address: string
|
||||
maxAmount: Amount
|
||||
tag?: number
|
||||
}
|
||||
|
||||
export type MinAdjustment = {
|
||||
address: string,
|
||||
minAmount: Amount,
|
||||
address: string
|
||||
minAmount: Amount
|
||||
tag?: number
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ export interface Amount extends Issue {
|
||||
value: string
|
||||
}
|
||||
|
||||
|
||||
export type RippledAmount = string | Amount
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './adjustments'
|
||||
export * from './amounts'
|
||||
export * from './ledger'
|
||||
export * from './ledger_data'
|
||||
export * from './ledger_entries'
|
||||
export * from './memos'
|
||||
export * from './orders'
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
export interface Ledger {
|
||||
account_hash: string,
|
||||
close_time: number,
|
||||
close_time_human: string,
|
||||
close_time_resolution: number,
|
||||
closed: boolean,
|
||||
ledger_hash: string,
|
||||
ledger_index: string,
|
||||
parent_hash: string,
|
||||
total_coins: string,
|
||||
transaction_hash: string,
|
||||
transactions: string[] | object[],
|
||||
account_hash: string
|
||||
close_time: number
|
||||
close_time_human: string
|
||||
close_time_resolution: number
|
||||
closed: boolean
|
||||
ledger_hash: string
|
||||
ledger_index: string
|
||||
parent_hash: string
|
||||
total_coins: string
|
||||
transaction_hash: string
|
||||
transactions: string[] | object[]
|
||||
// @deprecated
|
||||
seqNum?: string,
|
||||
seqNum?: string
|
||||
// @deprecated
|
||||
totalCoins?: string,
|
||||
totalCoins?: string
|
||||
// @deprecated
|
||||
hash?: string,
|
||||
close_flags?: number,
|
||||
parent_close_time?: number,
|
||||
accountState?: any[],
|
||||
hash?: string
|
||||
close_flags?: number
|
||||
parent_close_time?: number
|
||||
accountState?: any[]
|
||||
validated?: boolean
|
||||
}
|
||||
|
||||
6
src/common/types/objects/ledger_data.ts
Normal file
6
src/common/types/objects/ledger_data.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface LedgerData {
|
||||
ledger_index: string
|
||||
ledger_hash: string
|
||||
marker: string
|
||||
state: ({data?: string; LedgerEntryType?: string; index: string} & any)[]
|
||||
}
|
||||
@@ -2,188 +2,189 @@ import {SignerEntry} from './index'
|
||||
import {Amount, RippledAmount} from './amounts'
|
||||
|
||||
export interface AccountRootLedgerEntry {
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
Account: string,
|
||||
Balance: string,
|
||||
Flags: number,
|
||||
OwnerCount: number,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
Sequence: number,
|
||||
AccountTxnID?: string,
|
||||
Domain?: string,
|
||||
EmailHash?: string,
|
||||
LedgerEntryType: 'AccountRoot'
|
||||
Account: string
|
||||
Balance: string
|
||||
Flags: number
|
||||
OwnerCount: number
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
Sequence: number
|
||||
AccountTxnID?: string
|
||||
Domain?: string
|
||||
EmailHash?: string
|
||||
MessageKey?: string
|
||||
RegularKey?: string,
|
||||
TickSize?: number,
|
||||
TransferRate?: number,
|
||||
WalletLocator?: string, // DEPRECATED
|
||||
RegularKey?: string
|
||||
TickSize?: number
|
||||
TransferRate?: number
|
||||
WalletLocator?: string
|
||||
WalletSize?: number // DEPRECATED
|
||||
}
|
||||
|
||||
export interface AmendmentsLedgerEntry {
|
||||
LedgerEntryType: 'Amendments',
|
||||
Amendments?: string[],
|
||||
Majorities?: any[],
|
||||
LedgerEntryType: 'Amendments'
|
||||
Amendments?: string[]
|
||||
Majorities?: any[]
|
||||
Flags: 0
|
||||
}
|
||||
|
||||
export interface CheckLedgerEntry {
|
||||
LedgerEntryType: 'Check',
|
||||
Account: string,
|
||||
Destination, string,
|
||||
Flags: 0,
|
||||
OwnerNode: string,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
SendMax: string | object,
|
||||
Sequence: number,
|
||||
DestinationNode: string,
|
||||
DestinationTag: number,
|
||||
Expiration: number,
|
||||
InvoiceID: string,
|
||||
LedgerEntryType: 'Check'
|
||||
Account: string
|
||||
Destination
|
||||
string
|
||||
Flags: 0
|
||||
OwnerNode: string
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
SendMax: string | object
|
||||
Sequence: number
|
||||
DestinationNode: string
|
||||
DestinationTag: number
|
||||
Expiration: number
|
||||
InvoiceID: string
|
||||
SourceTag: number
|
||||
}
|
||||
|
||||
export interface DepositPreauthLedgerEntry {
|
||||
LedgerEntryType: 'DepositPreauth',
|
||||
Account: string,
|
||||
Authorize: string,
|
||||
OwnerNode: string,
|
||||
PreviousTxnID: string,
|
||||
LedgerEntryType: 'DepositPreauth'
|
||||
Account: string
|
||||
Authorize: string
|
||||
OwnerNode: string
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
|
||||
export interface DirectoryNodeLedgerEntry {
|
||||
LedgerEntryType: 'DirectoryNode',
|
||||
Flags: number,
|
||||
RootIndex: string,
|
||||
Indexes: string[],
|
||||
IndexNext?: number,
|
||||
LedgerEntryType: 'DirectoryNode'
|
||||
Flags: number
|
||||
RootIndex: string
|
||||
Indexes: string[]
|
||||
IndexNext?: number
|
||||
IndexPrevious?: number
|
||||
}
|
||||
|
||||
export interface OfferDirectoryNodeLedgerEntry
|
||||
extends DirectoryNodeLedgerEntry {
|
||||
TakerPaysCurrency: string,
|
||||
TakerPaysIssuer: string,
|
||||
TakerGetsCurrency: string,
|
||||
TakerGetsIssuer: string,
|
||||
extends DirectoryNodeLedgerEntry {
|
||||
TakerPaysCurrency: string
|
||||
TakerPaysIssuer: string
|
||||
TakerGetsCurrency: string
|
||||
TakerGetsIssuer: string
|
||||
ExchangeRate?: number // DEPRECATED
|
||||
}
|
||||
|
||||
export interface OwnerDirectoryNodeLedgerEntry
|
||||
extends DirectoryNodeLedgerEntry {
|
||||
Owner: string,
|
||||
Owner: string
|
||||
}
|
||||
|
||||
export interface EscrowLedgerEntry {
|
||||
LedgerEntryType: 'Escrow',
|
||||
Account: string,
|
||||
Destination: string,
|
||||
Amount: string,
|
||||
Condition?: string,
|
||||
CancelAfter?: number,
|
||||
FinishAfter?: number,
|
||||
Flags: number,
|
||||
SourceTag?: number,
|
||||
DestinationTag?: number,
|
||||
OwnerNode: string,
|
||||
DestinationNode?: string,
|
||||
PreviousTxnID: string,
|
||||
LedgerEntryType: 'Escrow'
|
||||
Account: string
|
||||
Destination: string
|
||||
Amount: string
|
||||
Condition?: string
|
||||
CancelAfter?: number
|
||||
FinishAfter?: number
|
||||
Flags: number
|
||||
SourceTag?: number
|
||||
DestinationTag?: number
|
||||
OwnerNode: string
|
||||
DestinationNode?: string
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
|
||||
export interface FeeSettingsLedgerEntry {
|
||||
LedgerEntryType: 'FeeSettings',
|
||||
BaseFee: string,
|
||||
ReferenceFeeUnits: number,
|
||||
ReserveBase: number,
|
||||
ReserveIncrement: number,
|
||||
LedgerEntryType: 'FeeSettings'
|
||||
BaseFee: string
|
||||
ReferenceFeeUnits: number
|
||||
ReserveBase: number
|
||||
ReserveIncrement: number
|
||||
Flags: number
|
||||
}
|
||||
|
||||
export interface LedgerHashesLedgerEntry {
|
||||
LedgerEntryType: 'LedgerHashes',
|
||||
Hashes: string[],
|
||||
Flags: number,
|
||||
FirstLedgerSequence?: number, // DEPRECATED
|
||||
LedgerEntryType: 'LedgerHashes'
|
||||
Hashes: string[]
|
||||
Flags: number
|
||||
FirstLedgerSequence?: number // DEPRECATED
|
||||
LastLedgerSequence?: number
|
||||
}
|
||||
|
||||
export interface OfferLedgerEntry {
|
||||
LedgerEntryType: 'Offer',
|
||||
Flags: number,
|
||||
Account: string,
|
||||
Sequence: number,
|
||||
TakerPays: RippledAmount,
|
||||
TakerGets: RippledAmount,
|
||||
BookDirectory: string,
|
||||
BookNode: string,
|
||||
OwnerNode: string,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
LedgerEntryType: 'Offer'
|
||||
Flags: number
|
||||
Account: string
|
||||
Sequence: number
|
||||
TakerPays: RippledAmount
|
||||
TakerGets: RippledAmount
|
||||
BookDirectory: string
|
||||
BookNode: string
|
||||
OwnerNode: string
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
Expiration?: number
|
||||
}
|
||||
|
||||
export interface PayChannelLedgerEntry {
|
||||
LedgerEntryType: 'PayChannel',
|
||||
Sequence: number,
|
||||
Account: string,
|
||||
Amount: string,
|
||||
Balance: string,
|
||||
PublicKey: string,
|
||||
Destination: string,
|
||||
SettleDelay: number,
|
||||
Expiration?: number,
|
||||
CancelAfter?: number,
|
||||
SourceTag?: number,
|
||||
DestinationTag?: number,
|
||||
OwnerNode: string,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
LedgerEntryType: 'PayChannel'
|
||||
Sequence: number
|
||||
Account: string
|
||||
Amount: string
|
||||
Balance: string
|
||||
PublicKey: string
|
||||
Destination: string
|
||||
SettleDelay: number
|
||||
Expiration?: number
|
||||
CancelAfter?: number
|
||||
SourceTag?: number
|
||||
DestinationTag?: number
|
||||
OwnerNode: string
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
index: string
|
||||
}
|
||||
|
||||
export interface RippleStateLedgerEntry {
|
||||
LedgerEntryType: 'RippleState',
|
||||
Flags: number,
|
||||
Balance: Amount,
|
||||
LowLimit: Amount,
|
||||
HighLimit: Amount,
|
||||
PreviousTxnID: string,
|
||||
PreviousTxnLgrSeq: number,
|
||||
LowNode?: string,
|
||||
HighNode?: string,
|
||||
LowQualityIn?: number,
|
||||
LowQualityOut?: number,
|
||||
HighQualityIn?: number,
|
||||
LedgerEntryType: 'RippleState'
|
||||
Flags: number
|
||||
Balance: Amount
|
||||
LowLimit: Amount
|
||||
HighLimit: Amount
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
LowNode?: string
|
||||
HighNode?: string
|
||||
LowQualityIn?: number
|
||||
LowQualityOut?: number
|
||||
HighQualityIn?: number
|
||||
HighQualityOut?: number
|
||||
}
|
||||
|
||||
export interface SignerListLedgerEntry {
|
||||
LedgerEntryType: 'SignerList',
|
||||
OwnerNode: string,
|
||||
SignerQuorum: number,
|
||||
SignerEntries: SignerEntry[],
|
||||
SignerListID: number,
|
||||
PreviousTxnID: string,
|
||||
LedgerEntryType: 'SignerList'
|
||||
OwnerNode: string
|
||||
SignerQuorum: number
|
||||
SignerEntries: SignerEntry[]
|
||||
SignerListID: number
|
||||
PreviousTxnID: string
|
||||
PreviousTxnLgrSeq: number
|
||||
}
|
||||
|
||||
// see https://ripple.com/build/ledger-format/#ledger-object-types
|
||||
export type LedgerEntry =
|
||||
AccountRootLedgerEntry |
|
||||
AmendmentsLedgerEntry |
|
||||
CheckLedgerEntry |
|
||||
DepositPreauthLedgerEntry |
|
||||
DirectoryNodeLedgerEntry |
|
||||
OfferDirectoryNodeLedgerEntry |
|
||||
OwnerDirectoryNodeLedgerEntry |
|
||||
EscrowLedgerEntry |
|
||||
FeeSettingsLedgerEntry |
|
||||
LedgerHashesLedgerEntry |
|
||||
OfferLedgerEntry |
|
||||
PayChannelLedgerEntry |
|
||||
RippleStateLedgerEntry |
|
||||
SignerListLedgerEntry
|
||||
| AccountRootLedgerEntry
|
||||
| AmendmentsLedgerEntry
|
||||
| CheckLedgerEntry
|
||||
| DepositPreauthLedgerEntry
|
||||
| DirectoryNodeLedgerEntry
|
||||
| OfferDirectoryNodeLedgerEntry
|
||||
| OwnerDirectoryNodeLedgerEntry
|
||||
| EscrowLedgerEntry
|
||||
| FeeSettingsLedgerEntry
|
||||
| LedgerHashesLedgerEntry
|
||||
| OfferLedgerEntry
|
||||
| PayChannelLedgerEntry
|
||||
| RippleStateLedgerEntry
|
||||
| SignerListLedgerEntry
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
export type Memo = {
|
||||
type?: string,
|
||||
format?: string,
|
||||
type?: string
|
||||
format?: string
|
||||
data?: string
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ import {Amount} from './amounts'
|
||||
import {Memo} from './memos'
|
||||
|
||||
export type FormattedOrderSpecification = {
|
||||
direction: string,
|
||||
quantity: Amount,
|
||||
totalPrice: Amount,
|
||||
immediateOrCancel?: boolean,
|
||||
fillOrKill?: boolean,
|
||||
expirationTime?: string,
|
||||
orderToReplace?: number,
|
||||
memos?: Memo[],
|
||||
direction: string
|
||||
quantity: Amount
|
||||
totalPrice: Amount
|
||||
immediateOrCancel?: boolean
|
||||
fillOrKill?: boolean
|
||||
expirationTime?: string
|
||||
orderToReplace?: number
|
||||
memos?: Memo[]
|
||||
// If enabled, the offer will not consume offers that exactly match it, and
|
||||
// instead becomes an Offer node in the ledger. It will still consume offers
|
||||
// that cross it.
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
export interface QueueTransaction {
|
||||
auth_change: boolean,
|
||||
fee: string,
|
||||
fee_level: string,
|
||||
max_spend_drops: string,
|
||||
auth_change: boolean
|
||||
fee: string
|
||||
fee_level: string
|
||||
max_spend_drops: string
|
||||
seq: number
|
||||
}
|
||||
|
||||
export interface QueueData {
|
||||
txn_count: number,
|
||||
auth_change_queued?: boolean,
|
||||
lowest_sequence?: number,
|
||||
highest_sequence?: number,
|
||||
max_spend_drops_total?: string,
|
||||
txn_count: number
|
||||
auth_change_queued?: boolean
|
||||
lowest_sequence?: number
|
||||
highest_sequence?: number
|
||||
max_spend_drops_total?: string
|
||||
transactions?: QueueTransaction[]
|
||||
}
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
import {Memo} from './memos'
|
||||
|
||||
export type WeightedSigner = {
|
||||
address: string,
|
||||
address: string
|
||||
weight: number
|
||||
}
|
||||
|
||||
export type Signers = {
|
||||
threshold?: number,
|
||||
threshold?: number
|
||||
weights: WeightedSigner[]
|
||||
}
|
||||
|
||||
export type FormattedSettings = {
|
||||
defaultRipple?: boolean,
|
||||
depositAuth?: boolean,
|
||||
disableMasterKey?: boolean,
|
||||
disallowIncomingXRP?: boolean,
|
||||
domain?: string,
|
||||
emailHash?: string|null,
|
||||
enableTransactionIDTracking?: boolean,
|
||||
globalFreeze?: boolean,
|
||||
memos?: Memo[],
|
||||
messageKey?: string,
|
||||
noFreeze?: boolean,
|
||||
passwordSpent?: boolean,
|
||||
regularKey?: string,
|
||||
requireAuthorization?: boolean,
|
||||
requireDestinationTag?: boolean,
|
||||
signers?: Signers,
|
||||
transferRate?: number|null,
|
||||
defaultRipple?: boolean
|
||||
depositAuth?: boolean
|
||||
disableMasterKey?: boolean
|
||||
disallowIncomingXRP?: boolean
|
||||
domain?: string
|
||||
emailHash?: string | null
|
||||
walletLocator?: string | null
|
||||
enableTransactionIDTracking?: boolean
|
||||
globalFreeze?: boolean
|
||||
memos?: Memo[]
|
||||
messageKey?: string
|
||||
noFreeze?: boolean
|
||||
passwordSpent?: boolean
|
||||
regularKey?: string
|
||||
requireAuthorization?: boolean
|
||||
requireDestinationTag?: boolean
|
||||
signers?: Signers
|
||||
transferRate?: number | null
|
||||
tickSize?: number
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface SignerEntry {
|
||||
Account: string,
|
||||
Account: string
|
||||
SignerWeight: number
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@ import {RippledAmount} from './amounts'
|
||||
import {Memo} from './memos'
|
||||
|
||||
export interface OfferCreateTransaction {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: string,
|
||||
AccountTxnID?: string,
|
||||
Fee: string,
|
||||
Field: any,
|
||||
Flags: number,
|
||||
LastLedgerSequence?: number,
|
||||
Sequence: number,
|
||||
Signers: any[],
|
||||
SigningPubKey: string,
|
||||
SourceTag?: number,
|
||||
TakerGets: RippledAmount,
|
||||
TakerPays: RippledAmount,
|
||||
TxnSignature: string,
|
||||
Expiration?: number,
|
||||
Memos?: Memo[],
|
||||
OfferSequence?: number,
|
||||
TransactionType: 'OfferCreate'
|
||||
Account: string
|
||||
AccountTxnID?: string
|
||||
Fee: string
|
||||
Field: any
|
||||
Flags: number
|
||||
LastLedgerSequence?: number
|
||||
Sequence: number
|
||||
Signers: any[]
|
||||
SigningPubKey: string
|
||||
SourceTag?: number
|
||||
TakerGets: RippledAmount
|
||||
TakerPays: RippledAmount
|
||||
TxnSignature: string
|
||||
Expiration?: number
|
||||
Memos?: Memo[]
|
||||
OfferSequence?: number
|
||||
}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
import {Memo} from './memos'
|
||||
|
||||
export interface Trustline {
|
||||
account: string,
|
||||
balance: string,
|
||||
currency: string,
|
||||
limit: string,
|
||||
limit_peer: string,
|
||||
quality_in: number,
|
||||
quality_out: number,
|
||||
no_ripple?: boolean,
|
||||
no_ripple_peer?: boolean,
|
||||
freeze?: boolean,
|
||||
freeze_peer?: boolean,
|
||||
authorized?: boolean,
|
||||
peer_authorized?: boolean,
|
||||
account: string
|
||||
balance: string
|
||||
currency: string
|
||||
limit: string
|
||||
limit_peer: string
|
||||
quality_in: number
|
||||
quality_out: number
|
||||
no_ripple?: boolean
|
||||
no_ripple_peer?: boolean
|
||||
freeze?: boolean
|
||||
freeze_peer?: boolean
|
||||
authorized?: boolean
|
||||
peer_authorized?: boolean
|
||||
}
|
||||
|
||||
export type FormattedTrustlineSpecification = {
|
||||
currency: string,
|
||||
counterparty: string,
|
||||
limit: string,
|
||||
qualityIn?: number,
|
||||
qualityOut?: number,
|
||||
ripplingDisabled?: boolean,
|
||||
authorized?: boolean,
|
||||
frozen?: boolean,
|
||||
currency: string
|
||||
counterparty: string
|
||||
limit: string
|
||||
qualityIn?: number
|
||||
qualityOut?: number
|
||||
ripplingDisabled?: boolean
|
||||
authorized?: boolean
|
||||
frozen?: boolean
|
||||
memos?: Memo[]
|
||||
}
|
||||
|
||||
export type FormattedTrustline = {
|
||||
specification: FormattedTrustlineSpecification,
|
||||
specification: FormattedTrustlineSpecification
|
||||
counterparty: {
|
||||
limit: string,
|
||||
ripplingDisabled?: boolean,
|
||||
frozen?: boolean,
|
||||
limit: string
|
||||
ripplingDisabled?: boolean
|
||||
frozen?: boolean
|
||||
authorized?: boolean
|
||||
},
|
||||
}
|
||||
state: {
|
||||
balance: string
|
||||
}
|
||||
|
||||
@@ -13,77 +13,96 @@ function isValidSecret(secret: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function dropsToXrp(drops: string | BigNumber): string {
|
||||
function dropsToXrp(drops: BigNumber.Value): string {
|
||||
if (typeof drops === 'string') {
|
||||
if (!drops.match(/^-?[0-9]*\.?[0-9]*$/)) {
|
||||
throw new ValidationError(`dropsToXrp: invalid value '${drops}',` +
|
||||
` should be a number matching (^-?[0-9]*\\.?[0-9]*$).`)
|
||||
throw new ValidationError(
|
||||
`dropsToXrp: invalid value '${drops}',` +
|
||||
` should be a number matching (^-?[0-9]*\\.?[0-9]*$).`
|
||||
)
|
||||
} else if (drops === '.') {
|
||||
throw new ValidationError(`dropsToXrp: invalid value '${drops}',` +
|
||||
` should be a BigNumber or string-encoded number.`)
|
||||
throw new ValidationError(
|
||||
`dropsToXrp: invalid value '${drops}',` +
|
||||
` should be a BigNumber or string-encoded number.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Converting to BigNumber and then back to string should remove any
|
||||
// decimal point followed by zeros, e.g. '1.00'.
|
||||
// Important: specify base 10 to avoid exponential notation, e.g. '1e-7'.
|
||||
drops = (new BigNumber(drops)).toString(10)
|
||||
drops = new BigNumber(drops).toString(10)
|
||||
|
||||
// drops are only whole units
|
||||
if (drops.includes('.')) {
|
||||
throw new ValidationError(`dropsToXrp: value '${drops}' has` +
|
||||
` too many decimal places.`)
|
||||
throw new ValidationError(
|
||||
`dropsToXrp: value '${drops}' has` + ` too many decimal places.`
|
||||
)
|
||||
}
|
||||
|
||||
// This should never happen; the value has already been
|
||||
// validated above. This just ensures BigNumber did not do
|
||||
// something unexpected.
|
||||
if (!drops.match(/^-?[0-9]+$/)) {
|
||||
throw new ValidationError(`dropsToXrp: failed sanity check -` +
|
||||
` value '${drops}',` +
|
||||
` does not match (^-?[0-9]+$).`)
|
||||
throw new ValidationError(
|
||||
`dropsToXrp: failed sanity check -` +
|
||||
` value '${drops}',` +
|
||||
` does not match (^-?[0-9]+$).`
|
||||
)
|
||||
}
|
||||
|
||||
return (new BigNumber(drops)).dividedBy(1000000.0).toString(10)
|
||||
return new BigNumber(drops).dividedBy(1000000.0).toString(10)
|
||||
}
|
||||
|
||||
function xrpToDrops(xrp: string | BigNumber): string {
|
||||
function xrpToDrops(xrp: BigNumber.Value): string {
|
||||
if (typeof xrp === 'string') {
|
||||
if (!xrp.match(/^-?[0-9]*\.?[0-9]*$/)) {
|
||||
throw new ValidationError(`xrpToDrops: invalid value '${xrp}',` +
|
||||
` should be a number matching (^-?[0-9]*\\.?[0-9]*$).`)
|
||||
throw new ValidationError(
|
||||
`xrpToDrops: invalid value '${xrp}',` +
|
||||
` should be a number matching (^-?[0-9]*\\.?[0-9]*$).`
|
||||
)
|
||||
} else if (xrp === '.') {
|
||||
throw new ValidationError(`xrpToDrops: invalid value '${xrp}',` +
|
||||
` should be a BigNumber or string-encoded number.`)
|
||||
throw new ValidationError(
|
||||
`xrpToDrops: invalid value '${xrp}',` +
|
||||
` should be a BigNumber or string-encoded number.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Important: specify base 10 to avoid exponential notation, e.g. '1e-7'.
|
||||
xrp = (new BigNumber(xrp)).toString(10)
|
||||
xrp = new BigNumber(xrp).toString(10)
|
||||
|
||||
// This should never happen; the value has already been
|
||||
// validated above. This just ensures BigNumber did not do
|
||||
// something unexpected.
|
||||
if (!xrp.match(/^-?[0-9.]+$/)) {
|
||||
throw new ValidationError(`xrpToDrops: failed sanity check -` +
|
||||
` value '${xrp}',` +
|
||||
` does not match (^-?[0-9.]+$).`)
|
||||
throw new ValidationError(
|
||||
`xrpToDrops: failed sanity check -` +
|
||||
` value '${xrp}',` +
|
||||
` does not match (^-?[0-9.]+$).`
|
||||
)
|
||||
}
|
||||
|
||||
const components = xrp.split('.')
|
||||
if (components.length > 2) {
|
||||
throw new ValidationError(`xrpToDrops: failed sanity check -` +
|
||||
` value '${xrp}' has` +
|
||||
` too many decimal points.`)
|
||||
throw new ValidationError(
|
||||
`xrpToDrops: failed sanity check -` +
|
||||
` value '${xrp}' has` +
|
||||
` too many decimal points.`
|
||||
)
|
||||
}
|
||||
|
||||
const fraction = components[1] || '0'
|
||||
if (fraction.length > 6) {
|
||||
throw new ValidationError(`xrpToDrops: value '${xrp}' has` +
|
||||
` too many decimal places.`)
|
||||
throw new ValidationError(
|
||||
`xrpToDrops: value '${xrp}' has` + ` too many decimal places.`
|
||||
)
|
||||
}
|
||||
|
||||
return (new BigNumber(xrp)).times(1000000.0).integerValue(BigNumber.ROUND_FLOOR).toString(10)
|
||||
return new BigNumber(xrp)
|
||||
.times(1000000.0)
|
||||
.integerValue(BigNumber.ROUND_FLOOR)
|
||||
.toString(10)
|
||||
}
|
||||
|
||||
function toRippledAmount(amount: Amount): RippledAmount {
|
||||
@@ -95,8 +114,11 @@ function toRippledAmount(amount: Amount): RippledAmount {
|
||||
}
|
||||
return {
|
||||
currency: amount.currency,
|
||||
issuer: amount.counterparty ? amount.counterparty :
|
||||
(amount.issuer ? amount.issuer : undefined),
|
||||
issuer: amount.counterparty
|
||||
? amount.counterparty
|
||||
: amount.issuer
|
||||
? amount.issuer
|
||||
: undefined,
|
||||
value: amount.value
|
||||
}
|
||||
}
|
||||
@@ -105,16 +127,20 @@ function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
|
||||
if (typeof obj === 'object') {
|
||||
const accumulator = Array.isArray(obj) ? [] : {}
|
||||
let newKey
|
||||
return _.reduce(obj, (result, value, key) => {
|
||||
newKey = key
|
||||
// taking this out of function leads to error in PhantomJS
|
||||
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g
|
||||
if (FINDSNAKE.test(key)) {
|
||||
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase())
|
||||
}
|
||||
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value)
|
||||
return result
|
||||
}, accumulator)
|
||||
return _.reduce(
|
||||
obj,
|
||||
(result, value, key) => {
|
||||
newKey = key
|
||||
// taking this out of function leads to error in PhantomJS
|
||||
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g
|
||||
if (FINDSNAKE.test(key)) {
|
||||
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase())
|
||||
}
|
||||
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value)
|
||||
return result
|
||||
},
|
||||
accumulator
|
||||
)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
@@ -128,7 +154,7 @@ function removeUndefined<T extends object>(obj: T): T {
|
||||
* @return {Number} ms since unix epoch
|
||||
*/
|
||||
function rippleToUnixTimestamp(rpepoch: number): number {
|
||||
return (rpepoch + 0x386D4380) * 1000
|
||||
return (rpepoch + 0x386d4380) * 1000
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +162,7 @@ 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 {
|
||||
@@ -161,4 +187,3 @@ export {
|
||||
iso8601ToRippleTime,
|
||||
isValidSecret
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,11 @@ function error(text) {
|
||||
}
|
||||
|
||||
function validateLedgerRange(options) {
|
||||
if (!_.isUndefined(options) && !_.isUndefined(options.minLedgerVersion)
|
||||
&& !_.isUndefined(options.maxLedgerVersion)) {
|
||||
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')
|
||||
}
|
||||
@@ -20,110 +23,143 @@ function validateOptions(schema, instance) {
|
||||
validateLedgerRange(instance.options)
|
||||
}
|
||||
|
||||
export const getPaths =
|
||||
_.partial(schemaValidate, 'getPathsParameters')
|
||||
export const getPaths = _.partial(schemaValidate, 'getPathsParameters')
|
||||
|
||||
export const getTransactions =
|
||||
_.partial(validateOptions, 'getTransactionsParameters')
|
||||
export const getTransactions = _.partial(
|
||||
validateOptions,
|
||||
'getTransactionsParameters'
|
||||
)
|
||||
|
||||
export const getSettings =
|
||||
_.partial(validateOptions, 'getSettingsParameters')
|
||||
export const getSettings = _.partial(validateOptions, 'getSettingsParameters')
|
||||
|
||||
export const getAccountInfo =
|
||||
_.partial(validateOptions, 'getAccountInfoParameters')
|
||||
export const getAccountInfo = _.partial(
|
||||
validateOptions,
|
||||
'getAccountInfoParameters'
|
||||
)
|
||||
|
||||
export const getTrustlines =
|
||||
_.partial(validateOptions, 'getTrustlinesParameters')
|
||||
export const getTrustlines = _.partial(
|
||||
validateOptions,
|
||||
'getTrustlinesParameters'
|
||||
)
|
||||
|
||||
export const getBalances =
|
||||
_.partial(validateOptions, 'getBalancesParameters')
|
||||
export const getBalances = _.partial(validateOptions, 'getBalancesParameters')
|
||||
|
||||
export const getBalanceSheet =
|
||||
_.partial(validateOptions, 'getBalanceSheetParameters')
|
||||
export const getBalanceSheet = _.partial(
|
||||
validateOptions,
|
||||
'getBalanceSheetParameters'
|
||||
)
|
||||
|
||||
export const getOrders =
|
||||
_.partial(validateOptions, 'getOrdersParameters')
|
||||
export const getOrders = _.partial(validateOptions, 'getOrdersParameters')
|
||||
|
||||
export const getOrderbook =
|
||||
_.partial(validateOptions, 'getOrderbookParameters')
|
||||
export const getOrderbook = _.partial(validateOptions, 'getOrderbookParameters')
|
||||
|
||||
export const getTransaction =
|
||||
_.partial(validateOptions, 'getTransactionParameters')
|
||||
export const getTransaction = _.partial(
|
||||
validateOptions,
|
||||
'getTransactionParameters'
|
||||
)
|
||||
|
||||
export const getPaymentChannel =
|
||||
_.partial(validateOptions, 'getPaymentChannelParameters')
|
||||
export const getPaymentChannel = _.partial(
|
||||
validateOptions,
|
||||
'getPaymentChannelParameters'
|
||||
)
|
||||
|
||||
export const getLedger =
|
||||
_.partial(validateOptions, 'getLedgerParameters')
|
||||
export const getLedger = _.partial(validateOptions, 'getLedgerParameters')
|
||||
|
||||
export const preparePayment =
|
||||
_.partial(schemaValidate, 'preparePaymentParameters')
|
||||
export const preparePayment = _.partial(
|
||||
schemaValidate,
|
||||
'preparePaymentParameters'
|
||||
)
|
||||
|
||||
export const prepareOrder =
|
||||
_.partial(schemaValidate, 'prepareOrderParameters')
|
||||
export const prepareOrder = _.partial(schemaValidate, 'prepareOrderParameters')
|
||||
|
||||
export const prepareOrderCancellation =
|
||||
_.partial(schemaValidate, 'prepareOrderCancellationParameters')
|
||||
export const prepareOrderCancellation = _.partial(
|
||||
schemaValidate,
|
||||
'prepareOrderCancellationParameters'
|
||||
)
|
||||
|
||||
export const prepareTrustline =
|
||||
_.partial(schemaValidate, 'prepareTrustlineParameters')
|
||||
export const prepareTrustline = _.partial(
|
||||
schemaValidate,
|
||||
'prepareTrustlineParameters'
|
||||
)
|
||||
|
||||
export const prepareSettings =
|
||||
_.partial(schemaValidate, 'prepareSettingsParameters')
|
||||
export const prepareSettings = _.partial(
|
||||
schemaValidate,
|
||||
'prepareSettingsParameters'
|
||||
)
|
||||
|
||||
export const prepareEscrowCreation =
|
||||
_.partial(schemaValidate, 'prepareEscrowCreationParameters')
|
||||
export const prepareEscrowCreation = _.partial(
|
||||
schemaValidate,
|
||||
'prepareEscrowCreationParameters'
|
||||
)
|
||||
|
||||
export const prepareEscrowCancellation =
|
||||
_.partial(schemaValidate, 'prepareEscrowCancellationParameters')
|
||||
export const prepareEscrowCancellation = _.partial(
|
||||
schemaValidate,
|
||||
'prepareEscrowCancellationParameters'
|
||||
)
|
||||
|
||||
export const prepareEscrowExecution =
|
||||
_.partial(schemaValidate, 'prepareEscrowExecutionParameters')
|
||||
export const prepareEscrowExecution = _.partial(
|
||||
schemaValidate,
|
||||
'prepareEscrowExecutionParameters'
|
||||
)
|
||||
|
||||
export const preparePaymentChannelCreate =
|
||||
_.partial(schemaValidate, 'preparePaymentChannelCreateParameters')
|
||||
export const preparePaymentChannelCreate = _.partial(
|
||||
schemaValidate,
|
||||
'preparePaymentChannelCreateParameters'
|
||||
)
|
||||
|
||||
export const preparePaymentChannelFund =
|
||||
_.partial(schemaValidate, 'preparePaymentChannelFundParameters')
|
||||
export const preparePaymentChannelFund = _.partial(
|
||||
schemaValidate,
|
||||
'preparePaymentChannelFundParameters'
|
||||
)
|
||||
|
||||
export const preparePaymentChannelClaim =
|
||||
_.partial(schemaValidate, 'preparePaymentChannelClaimParameters')
|
||||
export const preparePaymentChannelClaim = _.partial(
|
||||
schemaValidate,
|
||||
'preparePaymentChannelClaimParameters'
|
||||
)
|
||||
|
||||
export const prepareCheckCreate =
|
||||
_.partial(schemaValidate, 'prepareCheckCreateParameters')
|
||||
export const prepareCheckCreate = _.partial(
|
||||
schemaValidate,
|
||||
'prepareCheckCreateParameters'
|
||||
)
|
||||
|
||||
export const prepareCheckCash =
|
||||
_.partial(schemaValidate, 'prepareCheckCashParameters')
|
||||
export const prepareCheckCash = _.partial(
|
||||
schemaValidate,
|
||||
'prepareCheckCashParameters'
|
||||
)
|
||||
|
||||
export const prepareCheckCancel =
|
||||
_.partial(schemaValidate, 'prepareCheckCancelParameters')
|
||||
export const prepareCheckCancel = _.partial(
|
||||
schemaValidate,
|
||||
'prepareCheckCancelParameters'
|
||||
)
|
||||
|
||||
export const sign =
|
||||
_.partial(schemaValidate, 'signParameters')
|
||||
export const sign = _.partial(schemaValidate, 'signParameters')
|
||||
|
||||
export const combine =
|
||||
_.partial(schemaValidate, 'combineParameters')
|
||||
export const combine = _.partial(schemaValidate, 'combineParameters')
|
||||
|
||||
export const submit =
|
||||
_.partial(schemaValidate, 'submitParameters')
|
||||
export const submit = _.partial(schemaValidate, 'submitParameters')
|
||||
|
||||
export const computeLedgerHash =
|
||||
_.partial(schemaValidate, 'computeLedgerHashParameters')
|
||||
export const computeLedgerHash = _.partial(
|
||||
schemaValidate,
|
||||
'computeLedgerHashParameters'
|
||||
)
|
||||
|
||||
export const generateAddress =
|
||||
_.partial(schemaValidate, 'generateAddressParameters')
|
||||
export const generateAddress = _.partial(
|
||||
schemaValidate,
|
||||
'generateAddressParameters'
|
||||
)
|
||||
|
||||
export const signPaymentChannelClaim =
|
||||
_.partial(schemaValidate, 'signPaymentChannelClaimParameters')
|
||||
export const signPaymentChannelClaim = _.partial(
|
||||
schemaValidate,
|
||||
'signPaymentChannelClaimParameters'
|
||||
)
|
||||
|
||||
export const verifyPaymentChannelClaim =
|
||||
_.partial(schemaValidate, 'verifyPaymentChannelClaimParameters')
|
||||
export const verifyPaymentChannelClaim = _.partial(
|
||||
schemaValidate,
|
||||
'verifyPaymentChannelClaimParameters'
|
||||
)
|
||||
|
||||
export const apiOptions =
|
||||
_.partial(schemaValidate, 'api-options')
|
||||
export const apiOptions = _.partial(schemaValidate, 'api-options')
|
||||
|
||||
export const instructions =
|
||||
_.partial(schemaValidate, 'instructions')
|
||||
export const instructions = _.partial(schemaValidate, 'instructions')
|
||||
|
||||
export const tx_json =
|
||||
_.partial(schemaValidate, 'tx-json')
|
||||
export const tx_json = _.partial(schemaValidate, 'tx-json')
|
||||
|
||||
@@ -17,7 +17,6 @@ declare class WebSocket {
|
||||
* same, as `ws` package provides.
|
||||
*/
|
||||
class WSWrapper extends EventEmitter {
|
||||
|
||||
private _ws: WebSocket
|
||||
static CONNECTING = 0
|
||||
static OPEN = 1
|
||||
@@ -60,8 +59,6 @@ class WSWrapper extends EventEmitter {
|
||||
get readyState() {
|
||||
return this._ws.readyState
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export = WSWrapper
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
export {RippleAPI} from './api'
|
||||
|
||||
export {
|
||||
FormattedTransactionType
|
||||
} from './transaction/types'
|
||||
export {FormattedTransactionType} from './transaction/types'
|
||||
|
||||
// Broadcast api is experimental
|
||||
export {RippleAPIBroadcast} from './broadcast'
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import {validate, removeUndefined, dropsToXrp, ensureClassicAddress} from '../common'
|
||||
import {
|
||||
validate,
|
||||
removeUndefined,
|
||||
dropsToXrp,
|
||||
ensureClassicAddress
|
||||
} from '../common'
|
||||
import {RippleAPI} from '..'
|
||||
import {AccountInfoResponse} from '../common/types/commands/account_info'
|
||||
|
||||
@@ -7,11 +12,11 @@ export type GetAccountInfoOptions = {
|
||||
}
|
||||
|
||||
export type FormattedGetAccountInfoResponse = {
|
||||
sequence: number,
|
||||
xrpBalance: string,
|
||||
ownerCount: number,
|
||||
previousInitiatedTransactionID: string,
|
||||
previousAffectingTransactionID: string,
|
||||
sequence: number
|
||||
xrpBalance: string
|
||||
ownerCount: number
|
||||
previousInitiatedTransactionID: string
|
||||
previousAffectingTransactionID: string
|
||||
previousAffectingTransactionLedgerVersion: number
|
||||
}
|
||||
|
||||
@@ -30,7 +35,9 @@ function formatAccountInfo(
|
||||
}
|
||||
|
||||
export default async function getAccountInfo(
|
||||
this: RippleAPI, address: string, options: GetAccountInfoOptions = {}
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: GetAccountInfoOptions = {}
|
||||
): Promise<FormattedGetAccountInfoResponse> {
|
||||
// 1. Validate
|
||||
validate.getAccountInfo({address, options})
|
||||
|
||||
@@ -14,14 +14,17 @@ export default async function getAccountObjects(
|
||||
// through to rippled. rippled validates requests.
|
||||
|
||||
// Make Request
|
||||
const response = await this.request('account_objects', removeUndefined({
|
||||
account: address,
|
||||
type: options.type,
|
||||
ledger_hash: options.ledgerHash,
|
||||
ledger_index: options.ledgerIndex,
|
||||
limit: options.limit,
|
||||
marker: options.marker
|
||||
}))
|
||||
const response = await this.request(
|
||||
'account_objects',
|
||||
removeUndefined({
|
||||
account: address,
|
||||
type: options.type,
|
||||
ledger_hash: options.ledgerHash,
|
||||
ledger_index: options.ledgerIndex,
|
||||
limit: options.limit,
|
||||
marker: options.marker
|
||||
})
|
||||
)
|
||||
// Return Response
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -5,17 +5,17 @@ import {ensureLedgerVersion} from './utils'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type BalanceSheetOptions = {
|
||||
excludeAddresses?: Array<string>,
|
||||
excludeAddresses?: Array<string>
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type GetBalanceSheet = {
|
||||
balances?: Array<Amount>,
|
||||
assets?: Array<Amount>,
|
||||
balances?: Array<Amount>
|
||||
assets?: Array<Amount>
|
||||
obligations?: Array<{
|
||||
currency: string,
|
||||
value: string
|
||||
}>
|
||||
currency: string
|
||||
value: string
|
||||
}>
|
||||
}
|
||||
|
||||
function formatBalanceSheet(balanceSheet): GetBalanceSheet {
|
||||
@@ -48,7 +48,9 @@ function formatBalanceSheet(balanceSheet): GetBalanceSheet {
|
||||
}
|
||||
|
||||
async function getBalanceSheet(
|
||||
this: RippleAPI, address: string, options: BalanceSheetOptions = {}
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: BalanceSheetOptions = {}
|
||||
): Promise<GetBalanceSheet> {
|
||||
// 1. Validate
|
||||
validate.getBalanceSheet({address, options})
|
||||
|
||||
@@ -6,8 +6,8 @@ import {FormattedTrustline} from '../common/types/objects/trustlines'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type Balance = {
|
||||
value: string,
|
||||
currency: string,
|
||||
value: string
|
||||
currency: string
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ function getTrustlineBalanceAmount(trustline: FormattedTrustline) {
|
||||
|
||||
function formatBalances(options, balances) {
|
||||
const result = balances.trustlines.map(getTrustlineBalanceAmount)
|
||||
if (!(options.counterparty ||
|
||||
(options.currency && options.currency !== 'XRP')
|
||||
)) {
|
||||
if (
|
||||
!(options.counterparty || (options.currency && options.currency !== 'XRP'))
|
||||
) {
|
||||
const xrpBalance = {
|
||||
currency: 'XRP',
|
||||
value: balances.xrp
|
||||
@@ -39,7 +39,9 @@ function formatBalances(options, balances) {
|
||||
return result
|
||||
}
|
||||
|
||||
function getLedgerVersionHelper(connection: Connection, optionValue?: number
|
||||
function getLedgerVersionHelper(
|
||||
connection: Connection,
|
||||
optionValue?: number
|
||||
): Promise<number> {
|
||||
if (optionValue !== undefined && optionValue !== null) {
|
||||
return Promise.resolve(optionValue)
|
||||
@@ -47,7 +49,10 @@ function getLedgerVersionHelper(connection: Connection, optionValue?: number
|
||||
return connection.getLedgerVersion()
|
||||
}
|
||||
|
||||
function getBalances(this: RippleAPI, address: string, options: GetTrustlinesOptions = {}
|
||||
function getBalances(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: GetTrustlinesOptions = {}
|
||||
): Promise<GetBalances> {
|
||||
validate.getTrustlines({address, options})
|
||||
|
||||
@@ -59,12 +64,16 @@ function getBalances(this: RippleAPI, address: string, options: GetTrustlinesOpt
|
||||
address = ensureClassicAddress(address)
|
||||
|
||||
return Promise.all([
|
||||
getLedgerVersionHelper(this.connection, options.ledgerVersion).then(
|
||||
ledgerVersion =>
|
||||
utils.getXRPBalance(this.connection, address, ledgerVersion)),
|
||||
getLedgerVersionHelper(
|
||||
this.connection,
|
||||
options.ledgerVersion
|
||||
).then(ledgerVersion =>
|
||||
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]})
|
||||
)
|
||||
}
|
||||
|
||||
export default getBalances
|
||||
|
||||
@@ -3,15 +3,16 @@ import {FormattedLedger, parseLedger} from './parse/ledger'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type GetLedgerOptions = {
|
||||
ledgerHash?: string,
|
||||
ledgerVersion?: number,
|
||||
includeAllData?: boolean,
|
||||
includeTransactions?: boolean,
|
||||
ledgerHash?: string
|
||||
ledgerVersion?: number
|
||||
includeAllData?: boolean
|
||||
includeTransactions?: boolean
|
||||
includeState?: boolean
|
||||
}
|
||||
|
||||
async function getLedger(
|
||||
this: RippleAPI, options: GetLedgerOptions = {}
|
||||
this: RippleAPI,
|
||||
options: GetLedgerOptions = {}
|
||||
): Promise<FormattedLedger> {
|
||||
// 1. Validate
|
||||
validate.getLedger({options})
|
||||
|
||||
@@ -11,7 +11,7 @@ import {RippleAPI} from '..'
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
export type FormattedOrderbook = {
|
||||
bids: FormattedOrderbookOrder[],
|
||||
bids: FormattedOrderbookOrder[]
|
||||
asks: FormattedOrderbookOrder[]
|
||||
}
|
||||
|
||||
@@ -34,13 +34,18 @@ function flipOrder(order: FormattedOrderbookOrder) {
|
||||
return _.merge({}, order, {specification: newSpecification})
|
||||
}
|
||||
|
||||
function alignOrder(base: Issue, order: FormattedOrderbookOrder): FormattedOrderbookOrder {
|
||||
function alignOrder(
|
||||
base: Issue,
|
||||
order: FormattedOrderbookOrder
|
||||
): FormattedOrderbookOrder {
|
||||
const quantity = order.specification.quantity
|
||||
return isSameIssue(quantity, base) ? order : flipOrder(order)
|
||||
}
|
||||
|
||||
export function formatBidsAndAsks(
|
||||
orderbook: OrderbookInfo, offers: BookOffer[]) {
|
||||
orderbook: OrderbookInfo,
|
||||
offers: BookOffer[]
|
||||
) {
|
||||
// the "base" currency is the currency that you are buying or selling
|
||||
// the "counter" is the currency that the "base" is priced in
|
||||
// a "bid"/"ask" is an order to buy/sell the base, respectively
|
||||
@@ -51,9 +56,11 @@ export function formatBidsAndAsks(
|
||||
// for asks: lowest quality => lowest totalPrice/quantity => lowest price
|
||||
// for both bids and asks, lowest quality is closest to mid-market
|
||||
// we sort the orders so that earlier orders are closer to mid-market
|
||||
const orders = offers.sort((a, b) => {
|
||||
return (new BigNumber(a.quality)).comparedTo(b.quality)
|
||||
}).map(parseOrderbookOrder)
|
||||
const orders = offers
|
||||
.sort((a, b) => {
|
||||
return new BigNumber(a.quality).comparedTo(b.quality)
|
||||
})
|
||||
.map(parseOrderbookOrder)
|
||||
|
||||
const alignedOrders = orders.map(_.partial(alignOrder, orderbook.base))
|
||||
const bids = alignedOrders.filter(_.partial(directionFilter, 'buy'))
|
||||
@@ -64,8 +71,11 @@ export function formatBidsAndAsks(
|
||||
// account is to specify a "perspective", which affects which unfunded offers
|
||||
// are returned
|
||||
async function makeRequest(
|
||||
api: RippleAPI, taker: string, options: GetOrderbookOptions,
|
||||
takerGets: Issue, takerPays: Issue
|
||||
api: RippleAPI,
|
||||
taker: string,
|
||||
options: GetOrderbookOptions,
|
||||
takerGets: Issue,
|
||||
takerPays: Issue
|
||||
) {
|
||||
const orderData = utils.renameCounterpartyToIssuerInOrder({
|
||||
taker_gets: takerGets,
|
||||
@@ -80,14 +90,13 @@ async function makeRequest(
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export type GetOrderbookOptions = {
|
||||
limit?: number,
|
||||
limit?: number
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
export type OrderbookInfo = {
|
||||
base: Issue,
|
||||
base: Issue
|
||||
counter: Issue
|
||||
}
|
||||
|
||||
@@ -105,10 +114,13 @@ export async function getOrderbook(
|
||||
makeRequest(this, address, options, orderbook.counter, orderbook.base)
|
||||
])
|
||||
// 3. Return Formatted Response
|
||||
const directOffers = _.flatMap(directOfferResults,
|
||||
directOfferResult => directOfferResult.offers)
|
||||
const reverseOffers = _.flatMap(reverseOfferResults,
|
||||
reverseOfferResult => reverseOfferResult.offers)
|
||||
return formatBidsAndAsks(orderbook,
|
||||
[...directOffers, ...reverseOffers])
|
||||
const directOffers = _.flatMap(
|
||||
directOfferResults,
|
||||
directOfferResult => directOfferResult.offers
|
||||
)
|
||||
const reverseOffers = _.flatMap(
|
||||
reverseOfferResults,
|
||||
reverseOfferResult => reverseOfferResult.offers
|
||||
)
|
||||
return formatBidsAndAsks(orderbook, [...directOffers, ...reverseOffers])
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import {RippleAPI} from '..'
|
||||
import {AccountOffersResponse} from '../common/types/commands'
|
||||
|
||||
export type GetOrdersOptions = {
|
||||
limit?: number,
|
||||
limit?: number
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
function formatResponse(
|
||||
address: string, responses: AccountOffersResponse[]
|
||||
address: string,
|
||||
responses: AccountOffersResponse[]
|
||||
): FormattedAccountOrder[] {
|
||||
let orders: FormattedAccountOrder[] = []
|
||||
for (const response of responses) {
|
||||
@@ -23,14 +24,16 @@ function formatResponse(
|
||||
}
|
||||
|
||||
export default async function getOrders(
|
||||
this: RippleAPI, address: string, options: GetOrdersOptions = {}
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: GetOrdersOptions = {}
|
||||
): Promise<FormattedAccountOrder[]> {
|
||||
// 1. Validate
|
||||
validate.getOrders({address, options})
|
||||
// 2. Make Request
|
||||
const responses = await this._requestAll('account_offers', {
|
||||
account: address,
|
||||
ledger_index: options.ledgerVersion || await this.getLedgerVersion(),
|
||||
ledger_index: options.ledgerVersion || (await this.getLedgerVersion()),
|
||||
limit: options.limit
|
||||
})
|
||||
// 3. Return Formatted Response, from the perspective of `address`
|
||||
|
||||
34
src/ledger/parse/account-delete.ts
Normal file
34
src/ledger/parse/account-delete.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import * as assert from 'assert'
|
||||
import {removeUndefined} from '../../common'
|
||||
import {classicAddressToXAddress} from 'ripple-address-codec'
|
||||
|
||||
export type FormattedAccountDelete = {
|
||||
// account (address) of an account to receive any leftover XRP after deleting the sending account.
|
||||
// Must be a funded account in the ledger, and must not be the sending account.
|
||||
destination: string
|
||||
|
||||
// (Optional) Arbitrary destination tag that identifies a hosted recipient or other information
|
||||
// for the recipient of the deleted account's leftover XRP. NB: Ensure that the hosted recipient is
|
||||
// able to account for AccountDelete transactions; if not, your balance may not be properly credited.
|
||||
destinationTag?: number
|
||||
|
||||
// X-address of an account to receive any leftover XRP after deleting the sending account.
|
||||
// Must be a funded account in the ledger, and must not be the sending account.
|
||||
destinationXAddress: string
|
||||
}
|
||||
|
||||
function parseAccountDelete(tx: any): FormattedAccountDelete {
|
||||
assert.ok(tx.TransactionType === 'AccountDelete')
|
||||
|
||||
return removeUndefined({
|
||||
destination: tx.Destination,
|
||||
destinationTag: tx.DestinationTag,
|
||||
destinationXAddress: classicAddressToXAddress(
|
||||
tx.Destination,
|
||||
tx.DestinationTag === undefined ? false : tx.DestinationTag,
|
||||
false
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default parseAccountDelete
|
||||
@@ -6,10 +6,10 @@ import {orderFlags} from './flags'
|
||||
import {FormattedOrderSpecification} from '../../common/types/objects'
|
||||
|
||||
export type FormattedAccountOrder = {
|
||||
specification: FormattedOrderSpecification,
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
specification: FormattedOrderSpecification
|
||||
properties: {
|
||||
maker: string
|
||||
sequence: number
|
||||
makerExchangeRate: string
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,14 @@ function computeQuality(takerGets, takerPays) {
|
||||
// rippled 'account_offers' returns a different format for orders than 'tx'
|
||||
// the flags are also different
|
||||
export function parseAccountOrder(
|
||||
address: string, order: any
|
||||
address: string,
|
||||
order: any
|
||||
): FormattedAccountOrder {
|
||||
const direction = (order.flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(order.taker_gets)
|
||||
const takerPaysAmount = parseAmount(order.taker_pays)
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount
|
||||
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
|
||||
@@ -37,15 +38,18 @@ export function parseAccountOrder(
|
||||
direction: direction,
|
||||
quantity: quantity,
|
||||
totalPrice: totalPrice,
|
||||
passive: ((order.flags & orderFlags.Passive) !== 0) || undefined,
|
||||
passive: (order.flags & orderFlags.Passive) !== 0 || undefined,
|
||||
// rippled currently does not provide "expiration" in account_offers
|
||||
expirationTime: parseTimestamp(order.expiration)
|
||||
})
|
||||
|
||||
const makerExchangeRate = order.quality ?
|
||||
adjustQualityForXRP(order.quality.toString(),
|
||||
takerGetsAmount.currency, takerPaysAmount.currency) :
|
||||
computeQuality(takerGetsAmount, takerPaysAmount)
|
||||
const makerExchangeRate = order.quality
|
||||
? adjustQualityForXRP(
|
||||
order.quality.toString(),
|
||||
takerGetsAmount.currency,
|
||||
takerPaysAmount.currency
|
||||
)
|
||||
: computeQuality(takerGetsAmount, takerPaysAmount)
|
||||
const properties = {
|
||||
maker: address,
|
||||
sequence: order.seq,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
function parseAmendment(tx: any) {
|
||||
return {
|
||||
amendment: tx.Amendment
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as common from '../../common'
|
||||
import {Amount, RippledAmount} from '../../common/types/objects'
|
||||
|
||||
|
||||
function parseAmount(amount: RippledAmount): Amount {
|
||||
if (typeof amount === 'string') {
|
||||
return {
|
||||
|
||||
@@ -2,7 +2,6 @@ import * as assert from 'assert'
|
||||
import {removeUndefined} from '../../common'
|
||||
|
||||
export type FormattedCheckCancel = {
|
||||
|
||||
// ID of the Check ledger object to cancel.
|
||||
checkID: string
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@ import parseAmount from './amount'
|
||||
import {Amount} from '../../common/types/objects'
|
||||
|
||||
export type FormattedCheckCash = {
|
||||
|
||||
// ID of the Check ledger object to cash.
|
||||
checkID: string,
|
||||
checkID: string
|
||||
|
||||
// (Optional) redeem the Check for exactly this amount, if possible.
|
||||
// The currency must match that of the `SendMax` of the corresponding
|
||||
// `CheckCreate` transaction.
|
||||
amount: Amount,
|
||||
amount: Amount
|
||||
|
||||
// (Optional) redeem the Check for at least this amount and
|
||||
// for as much as possible.
|
||||
|
||||
@@ -5,19 +5,18 @@ import parseAmount from './amount'
|
||||
import {Amount} from '../../common/types/objects'
|
||||
|
||||
export type FormattedCheckCreate = {
|
||||
|
||||
// account that can cash the check.
|
||||
destination: string,
|
||||
destination: string
|
||||
|
||||
// amount the check is allowed to debit the sender,
|
||||
// including transfer fees on non-XRP currencies.
|
||||
sendMax: Amount,
|
||||
sendMax: Amount
|
||||
|
||||
// (Optional) identifies the reason for the check, or a hosted recipient.
|
||||
destinationTag?: string,
|
||||
destinationTag?: string
|
||||
|
||||
// (Optional) time in seconds since the Ripple Epoch.
|
||||
expiration?: string,
|
||||
expiration?: string
|
||||
|
||||
// (Optional) 256-bit hash representing a specific reason or identifier.
|
||||
invoiceID?: string
|
||||
|
||||
@@ -3,7 +3,7 @@ import {removeUndefined} from '../../common'
|
||||
|
||||
export type FormattedDepositPreauth = {
|
||||
// account (address) of the sender to preauthorize
|
||||
authorize: string,
|
||||
authorize: string
|
||||
|
||||
// account (address) of the sender whose preauthorization should be revoked
|
||||
unauthorize: string
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
|
||||
import BigNumber from 'bignumber.js'
|
||||
import {dropsToXrp} from '../../common'
|
||||
|
||||
function parseFeeUpdate(tx: any) {
|
||||
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString()
|
||||
const baseFeeDrops = new BigNumber(tx.BaseFee, 16).toString()
|
||||
return {
|
||||
baseFeeXRP: dropsToXrp(baseFeeDrops),
|
||||
referenceFeeUnits: tx.ReferenceFeeUnits,
|
||||
|
||||
@@ -4,11 +4,12 @@ import {constants} from '../../common'
|
||||
const AccountFields = constants.AccountFields
|
||||
|
||||
function parseField(info, value) {
|
||||
if (info.encoding === 'hex' && !info.length) { // e.g. "domain"
|
||||
if (info.encoding === 'hex' && !info.length) {
|
||||
// e.g. "domain"
|
||||
return Buffer.from(value, 'hex').toString('ascii')
|
||||
}
|
||||
if (info.shift) {
|
||||
return (new BigNumber(value)).shiftedBy(-info.shift).toNumber()
|
||||
return new BigNumber(value).shiftedBy(-info.shift).toNumber()
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -42,7 +43,8 @@ function parseFields(data: any): object {
|
||||
address: entry.SignerEntry.Account,
|
||||
weight: entry.SignerEntry.SignerWeight
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
return settings
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
const orderFlags = {
|
||||
Passive: 0x00010000,
|
||||
Sell: 0x00020000 // offer was placed as a sell
|
||||
@@ -16,7 +14,4 @@ const trustlineFlags = {
|
||||
HighFreeze: 0x00800000
|
||||
}
|
||||
|
||||
export {
|
||||
orderFlags,
|
||||
trustlineFlags
|
||||
}
|
||||
export {orderFlags, trustlineFlags}
|
||||
|
||||
@@ -7,19 +7,19 @@ export type FormattedLedger = {
|
||||
// TODO: properties in type don't match response object. Fix!
|
||||
// accepted: boolean,
|
||||
// closed: boolean,
|
||||
stateHash: string,
|
||||
closeTime: string,
|
||||
closeTimeResolution: number,
|
||||
closeFlags: number,
|
||||
ledgerHash: string,
|
||||
ledgerVersion: number,
|
||||
parentLedgerHash: string,
|
||||
parentCloseTime: string,
|
||||
totalDrops: string,
|
||||
transactionHash: string,
|
||||
transactions?: Array<object>,
|
||||
transactionHashes?: Array<string>,
|
||||
rawState?: string,
|
||||
stateHash: string
|
||||
closeTime: string
|
||||
closeTimeResolution: number
|
||||
closeFlags: number
|
||||
ledgerHash: string
|
||||
ledgerVersion: number
|
||||
parentLedgerHash: string
|
||||
parentCloseTime: string
|
||||
totalDrops: string
|
||||
transactionHash: string
|
||||
transactions?: Array<object>
|
||||
transactionHashes?: Array<string>
|
||||
rawState?: string
|
||||
stateHashes?: Array<string>
|
||||
}
|
||||
|
||||
@@ -44,8 +44,10 @@ function parseTransactions(transactions, ledgerVersion) {
|
||||
return {transactionHashes: transactions}
|
||||
}
|
||||
return {
|
||||
transactions: _.map(transactions,
|
||||
_.partial(parseTransactionWrapper, ledgerVersion))
|
||||
transactions: _.map(
|
||||
transactions,
|
||||
_.partial(parseTransactionWrapper, ledgerVersion)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,20 +68,22 @@ function parseState(state) {
|
||||
*/
|
||||
export function parseLedger(ledger: Ledger): FormattedLedger {
|
||||
const ledgerVersion = parseInt(ledger.ledger_index || ledger.seqNum, 10)
|
||||
return removeUndefined(Object.assign(
|
||||
{
|
||||
stateHash: ledger.account_hash,
|
||||
closeTime: rippleTimeToISO8601(ledger.close_time),
|
||||
closeTimeResolution: ledger.close_time_resolution,
|
||||
closeFlags: ledger.close_flags,
|
||||
ledgerHash: ledger.hash || ledger.ledger_hash,
|
||||
ledgerVersion: ledgerVersion,
|
||||
parentLedgerHash: ledger.parent_hash,
|
||||
parentCloseTime: rippleTimeToISO8601(ledger.parent_close_time),
|
||||
totalDrops: ledger.total_coins || ledger.totalCoins,
|
||||
transactionHash: ledger.transaction_hash
|
||||
},
|
||||
parseTransactions(ledger.transactions, ledgerVersion),
|
||||
parseState(ledger.accountState)
|
||||
))
|
||||
return removeUndefined(
|
||||
Object.assign(
|
||||
{
|
||||
stateHash: ledger.account_hash,
|
||||
closeTime: rippleTimeToISO8601(ledger.close_time),
|
||||
closeTimeResolution: ledger.close_time_resolution,
|
||||
closeFlags: ledger.close_flags,
|
||||
ledgerHash: ledger.hash || ledger.ledger_hash,
|
||||
ledgerVersion: ledgerVersion,
|
||||
parentLedgerHash: ledger.parent_hash,
|
||||
parentCloseTime: rippleTimeToISO8601(ledger.parent_close_time),
|
||||
totalDrops: ledger.total_coins || ledger.totalCoins,
|
||||
transactionHash: ledger.transaction_hash
|
||||
},
|
||||
parseTransactions(ledger.transactions, ledgerVersion),
|
||||
parseState(ledger.accountState)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,17 +15,16 @@ function parseOrder(tx: OfferCreateTransaction): FormattedOrderSpecification {
|
||||
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 quantity = direction === 'buy' ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = direction === 'buy' ? takerGetsAmount : takerPaysAmount
|
||||
|
||||
return removeUndefined({
|
||||
direction: direction,
|
||||
quantity: quantity,
|
||||
totalPrice: totalPrice,
|
||||
passive: ((tx.Flags & flags.Passive) !== 0) || undefined,
|
||||
immediateOrCancel: ((tx.Flags & flags.ImmediateOrCancel) !== 0)
|
||||
|| undefined,
|
||||
fillOrKill: ((tx.Flags & flags.FillOrKill) !== 0) || undefined,
|
||||
passive: (tx.Flags & flags.Passive) !== 0 || undefined,
|
||||
immediateOrCancel: (tx.Flags & flags.ImmediateOrCancel) !== 0 || undefined,
|
||||
fillOrKill: (tx.Flags & flags.FillOrKill) !== 0 || undefined,
|
||||
expirationTime: parseTimestamp(tx.Expiration)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,27 +8,25 @@ import {BookOffer} from '../../common/types/commands'
|
||||
import {Amount, FormattedOrderSpecification} from '../../common/types/objects'
|
||||
|
||||
export type FormattedOrderbookOrder = {
|
||||
specification: FormattedOrderSpecification,
|
||||
specification: FormattedOrderSpecification
|
||||
properties: {
|
||||
maker: string,
|
||||
sequence: number,
|
||||
maker: string
|
||||
sequence: number
|
||||
makerExchangeRate: string
|
||||
},
|
||||
}
|
||||
state?: {
|
||||
fundedAmount: Amount,
|
||||
fundedAmount: Amount
|
||||
priceOfFundedAmount: Amount
|
||||
},
|
||||
}
|
||||
data: BookOffer
|
||||
}
|
||||
|
||||
export function parseOrderbookOrder(
|
||||
data: BookOffer
|
||||
): FormattedOrderbookOrder {
|
||||
export function parseOrderbookOrder(data: BookOffer): FormattedOrderbookOrder {
|
||||
const direction = (data.Flags & orderFlags.Sell) === 0 ? 'buy' : 'sell'
|
||||
const takerGetsAmount = parseAmount(data.TakerGets)
|
||||
const takerPaysAmount = parseAmount(data.TakerPays)
|
||||
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount
|
||||
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount
|
||||
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
|
||||
@@ -36,21 +34,26 @@ export function parseOrderbookOrder(
|
||||
direction: direction,
|
||||
quantity: quantity,
|
||||
totalPrice: totalPrice,
|
||||
passive: ((data.Flags & orderFlags.Passive) !== 0) || undefined,
|
||||
passive: (data.Flags & orderFlags.Passive) !== 0 || undefined,
|
||||
expirationTime: parseTimestamp(data.Expiration)
|
||||
})
|
||||
|
||||
const properties = {
|
||||
maker: data.Account,
|
||||
sequence: data.Sequence,
|
||||
makerExchangeRate: adjustQualityForXRP(data.quality,
|
||||
takerGetsAmount.currency, takerPaysAmount.currency)
|
||||
makerExchangeRate: adjustQualityForXRP(
|
||||
data.quality,
|
||||
takerGetsAmount.currency,
|
||||
takerPaysAmount.currency
|
||||
)
|
||||
}
|
||||
|
||||
const takerGetsFunded = data.taker_gets_funded ?
|
||||
parseAmount(data.taker_gets_funded) : undefined
|
||||
const takerPaysFunded = data.taker_pays_funded ?
|
||||
parseAmount(data.taker_pays_funded) : undefined
|
||||
const takerGetsFunded = data.taker_gets_funded
|
||||
? parseAmount(data.taker_gets_funded)
|
||||
: undefined
|
||||
const takerPaysFunded = data.taker_pays_funded
|
||||
? parseAmount(data.taker_pays_funded)
|
||||
: undefined
|
||||
const available = removeUndefined({
|
||||
fundedAmount: takerGetsFunded,
|
||||
priceOfFundedAmount: takerPaysFunded
|
||||
|
||||
@@ -4,33 +4,48 @@ import {Amount, RippledAmount} from '../../common/types/objects'
|
||||
import {Path, GetPaths, RippledPathsResponse} from '../pathfind-types'
|
||||
|
||||
function parsePaths(paths) {
|
||||
return paths.map(steps => steps.map(step =>
|
||||
_.omit(step, ['type', 'type_hex'])))
|
||||
return paths.map(steps =>
|
||||
steps.map(step => _.omit(step, ['type', 'type_hex']))
|
||||
)
|
||||
}
|
||||
|
||||
function removeAnyCounterpartyEncoding(address: string, amount: Amount) {
|
||||
return amount.counterparty === address ?
|
||||
_.omit(amount, 'counterparty') : amount
|
||||
return amount.counterparty === address
|
||||
? _.omit(amount, 'counterparty')
|
||||
: amount
|
||||
}
|
||||
|
||||
function createAdjustment(
|
||||
address: string, adjustmentWithoutAddress: object): any {
|
||||
address: string,
|
||||
adjustmentWithoutAddress: object
|
||||
): any {
|
||||
const amountKey = _.keys(adjustmentWithoutAddress)[0]
|
||||
const amount = adjustmentWithoutAddress[amountKey]
|
||||
return _.set({address: address}, amountKey,
|
||||
removeAnyCounterpartyEncoding(address, amount))
|
||||
return _.set(
|
||||
{address: address},
|
||||
amountKey,
|
||||
removeAnyCounterpartyEncoding(address, amount)
|
||||
)
|
||||
}
|
||||
|
||||
function parseAlternative(sourceAddress: string, destinationAddress: string,
|
||||
destinationAmount: RippledAmount, alternative: any
|
||||
function parseAlternative(
|
||||
sourceAddress: string,
|
||||
destinationAddress: string,
|
||||
destinationAmount: RippledAmount,
|
||||
alternative: any
|
||||
): Path {
|
||||
// we use "maxAmount"/"minAmount" here so that the result can be passed
|
||||
// directly to preparePayment
|
||||
const amounts = (alternative.destination_amount !== undefined) ?
|
||||
{source: {amount: parseAmount(alternative.source_amount)},
|
||||
destination: {minAmount: parseAmount(alternative.destination_amount)}} :
|
||||
{source: {maxAmount: parseAmount(alternative.source_amount)},
|
||||
destination: {amount: parseAmount(destinationAmount)}}
|
||||
const amounts =
|
||||
alternative.destination_amount !== undefined
|
||||
? {
|
||||
source: {amount: parseAmount(alternative.source_amount)},
|
||||
destination: {minAmount: parseAmount(alternative.destination_amount)}
|
||||
}
|
||||
: {
|
||||
source: {maxAmount: parseAmount(alternative.source_amount)},
|
||||
destination: {amount: parseAmount(destinationAmount)}
|
||||
}
|
||||
|
||||
return {
|
||||
source: createAdjustment(sourceAddress, amounts.source),
|
||||
@@ -44,7 +59,8 @@ function parsePathfind(pathfindResult: RippledPathsResponse): GetPaths {
|
||||
const destinationAddress = pathfindResult.destination_account
|
||||
const destinationAmount = pathfindResult.destination_amount
|
||||
return pathfindResult.alternatives.map(alt =>
|
||||
parseAlternative(sourceAddress, destinationAddress, destinationAmount, alt))
|
||||
parseAlternative(sourceAddress, destinationAddress, destinationAmount, alt)
|
||||
)
|
||||
}
|
||||
|
||||
export default parsePathfind
|
||||
|
||||
@@ -3,17 +3,17 @@ import {removeUndefined, dropsToXrp} from '../../common'
|
||||
import {PayChannelLedgerEntry} from '../../common/types/objects'
|
||||
|
||||
export type FormattedPaymentChannel = {
|
||||
account: string,
|
||||
amount: string,
|
||||
balance: string,
|
||||
publicKey: string,
|
||||
destination: string,
|
||||
settleDelay: number,
|
||||
expiration?: string,
|
||||
cancelAfter?: string,
|
||||
sourceTag?: number,
|
||||
destinationTag?: number,
|
||||
previousAffectingTransactionID: string,
|
||||
account: string
|
||||
amount: string
|
||||
balance: string
|
||||
publicKey: string
|
||||
destination: string
|
||||
settleDelay: number
|
||||
expiration?: string
|
||||
cancelAfter?: string
|
||||
sourceTag?: number
|
||||
destinationTag?: number
|
||||
previousAffectingTransactionID: string
|
||||
previousAffectingTransactionLedgerVersion: number
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ function isQualityLimited(tx) {
|
||||
}
|
||||
|
||||
function removeGenericCounterparty(amount, address) {
|
||||
return amount.counterparty === address ?
|
||||
_.omit(amount, 'counterparty') : amount
|
||||
return amount.counterparty === address
|
||||
? _.omit(amount, 'counterparty')
|
||||
: amount
|
||||
}
|
||||
|
||||
// Payment specification
|
||||
@@ -24,12 +25,14 @@ function parsePayment(tx: any): object {
|
||||
const source = {
|
||||
address: tx.Account,
|
||||
maxAmount: removeGenericCounterparty(
|
||||
parseAmount(tx.SendMax || tx.Amount), tx.Account),
|
||||
parseAmount(tx.SendMax || tx.Amount),
|
||||
tx.Account
|
||||
),
|
||||
tag: tx.SourceTag
|
||||
}
|
||||
|
||||
const destination: {
|
||||
address: string,
|
||||
address: string
|
||||
tag: number | undefined
|
||||
} = {
|
||||
address: tx.Destination,
|
||||
|
||||
@@ -5,8 +5,9 @@ const AccountFlags = constants.AccountFlags
|
||||
import parseFields from './fields'
|
||||
|
||||
function getAccountRootModifiedNode(tx: any) {
|
||||
const modifiedNodes = tx.meta.AffectedNodes.filter(node =>
|
||||
node.ModifiedNode.LedgerEntryType === 'AccountRoot')
|
||||
const modifiedNodes = tx.meta.AffectedNodes.filter(
|
||||
node => node.ModifiedNode.LedgerEntryType === 'AccountRoot'
|
||||
)
|
||||
assert.ok(modifiedNodes.length === 1)
|
||||
return modifiedNodes[0].ModifiedNode
|
||||
}
|
||||
@@ -51,8 +52,11 @@ function parseFlags(tx: any): any {
|
||||
|
||||
function parseSettings(tx: any) {
|
||||
const txType = tx.TransactionType
|
||||
assert.ok(txType === 'AccountSet' || txType === 'SetRegularKey' ||
|
||||
txType === 'SignerListSet')
|
||||
assert.ok(
|
||||
txType === 'AccountSet' ||
|
||||
txType === 'SetRegularKey' ||
|
||||
txType === 'SignerListSet'
|
||||
)
|
||||
|
||||
return _.assign({}, parseFlags(tx), parseFields(tx))
|
||||
}
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import {parseOutcome} from './utils'
|
||||
import {removeUndefined} from '../../common'
|
||||
import parsePayment from './payment'
|
||||
import parseTrustline from './trustline'
|
||||
import parseOrder from './order'
|
||||
import parseOrderCancellation from './cancellation'
|
||||
|
||||
import parseSettings from './settings'
|
||||
import parseAccountDelete from './account-delete'
|
||||
import parseCheckCancel from './check-cancel'
|
||||
import parseCheckCash from './check-cash'
|
||||
import parseCheckCreate from './check-create'
|
||||
import parseDepositPreauth from './deposit-preauth'
|
||||
import parseEscrowCancellation from './escrow-cancellation'
|
||||
import parseEscrowCreation from './escrow-creation'
|
||||
import parseEscrowExecution from './escrow-execution'
|
||||
import parseEscrowCancellation from './escrow-cancellation'
|
||||
import parseCheckCreate from './check-create'
|
||||
import parseCheckCash from './check-cash'
|
||||
import parseCheckCancel from './check-cancel'
|
||||
import parseDepositPreauth from './deposit-preauth'
|
||||
import parseOrderCancellation from './cancellation'
|
||||
import parseOrder from './order'
|
||||
import parsePayment from './payment'
|
||||
import parsePaymentChannelClaim from './payment-channel-claim'
|
||||
import parsePaymentChannelCreate from './payment-channel-create'
|
||||
import parsePaymentChannelFund from './payment-channel-fund'
|
||||
import parsePaymentChannelClaim from './payment-channel-claim'
|
||||
import parseFeeUpdate from './fee-update'
|
||||
import parseAmendment from './amendment'
|
||||
import parseTrustline from './trustline'
|
||||
|
||||
import parseAmendment from './amendment' // pseudo-transaction
|
||||
import parseFeeUpdate from './fee-update' // pseudo-transaction
|
||||
|
||||
function parseTransactionType(type) {
|
||||
// Ordering matches https://developers.ripple.com/transaction-types.html
|
||||
const mapping = {
|
||||
AccountSet: 'settings',
|
||||
AccountDelete: 'accountDelete',
|
||||
CheckCancel: 'checkCancel',
|
||||
CheckCash: 'checkCash',
|
||||
CheckCreate: 'checkCreate',
|
||||
@@ -49,30 +53,35 @@ function parseTransactionType(type) {
|
||||
function parseTransaction(tx: any, includeRawTransaction: boolean): any {
|
||||
const type = parseTransactionType(tx.TransactionType)
|
||||
const mapping = {
|
||||
'payment': parsePayment,
|
||||
'trustline': parseTrustline,
|
||||
'order': parseOrder,
|
||||
'orderCancellation': parseOrderCancellation,
|
||||
'settings': parseSettings,
|
||||
'escrowCreation': parseEscrowCreation,
|
||||
'escrowExecution': parseEscrowExecution,
|
||||
'escrowCancellation': parseEscrowCancellation,
|
||||
'checkCreate': parseCheckCreate,
|
||||
'checkCash': parseCheckCash,
|
||||
'checkCancel': parseCheckCancel,
|
||||
'depositPreauth': parseDepositPreauth,
|
||||
'paymentChannelCreate': parsePaymentChannelCreate,
|
||||
'paymentChannelFund': parsePaymentChannelFund,
|
||||
'paymentChannelClaim': parsePaymentChannelClaim,
|
||||
'feeUpdate': parseFeeUpdate,
|
||||
'amendment': parseAmendment
|
||||
settings: parseSettings,
|
||||
accountDelete: parseAccountDelete,
|
||||
checkCancel: parseCheckCancel,
|
||||
checkCash: parseCheckCash,
|
||||
checkCreate: parseCheckCreate,
|
||||
depositPreauth: parseDepositPreauth,
|
||||
escrowCancellation: parseEscrowCancellation,
|
||||
escrowCreation: parseEscrowCreation,
|
||||
escrowExecution: parseEscrowExecution,
|
||||
orderCancellation: parseOrderCancellation,
|
||||
order: parseOrder,
|
||||
payment: parsePayment,
|
||||
paymentChannelClaim: parsePaymentChannelClaim,
|
||||
paymentChannelCreate: parsePaymentChannelCreate,
|
||||
paymentChannelFund: parsePaymentChannelFund,
|
||||
trustline: parseTrustline,
|
||||
|
||||
amendment: parseAmendment, // pseudo-transaction
|
||||
feeUpdate: parseFeeUpdate // pseudo-transaction
|
||||
}
|
||||
const parser: Function = mapping[type]
|
||||
|
||||
const specification = parser ? parser(tx) : {
|
||||
UNAVAILABLE: 'Unrecognized transaction type.',
|
||||
SEE_RAW_TRANSACTION: 'Since this type is unrecognized, `rawTransaction` is included in this response.'
|
||||
}
|
||||
const specification = parser
|
||||
? parser(tx)
|
||||
: {
|
||||
UNAVAILABLE: 'Unrecognized transaction type.',
|
||||
SEE_RAW_TRANSACTION:
|
||||
'Since this type is unrecognized, `rawTransaction` is included in this response.'
|
||||
}
|
||||
if (!parser) {
|
||||
includeRawTransaction = true
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ function parseTrustline(tx: any): object {
|
||||
qualityIn: parseQuality(tx.QualityIn),
|
||||
qualityOut: parseQuality(tx.QualityOut),
|
||||
ripplingDisabled: parseFlag(
|
||||
tx.Flags, flags.SetNoRipple, flags.ClearNoRipple),
|
||||
tx.Flags,
|
||||
flags.SetNoRipple,
|
||||
flags.ClearNoRipple
|
||||
),
|
||||
frozen: parseFlag(tx.Flags, flags.SetFreeze, flags.ClearFreeze),
|
||||
authorized: parseFlag(tx.Flags, flags.SetAuth, 0)
|
||||
})
|
||||
|
||||
@@ -7,25 +7,28 @@ import parseAmount from './amount'
|
||||
import {Amount, Memo} from '../../common/types/objects'
|
||||
|
||||
function adjustQualityForXRP(
|
||||
quality: string, takerGetsCurrency: string, takerPaysCurrency: string
|
||||
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 numeratorShift = takerPaysCurrency === 'XRP' ? -6 : 0
|
||||
const denominatorShift = takerGetsCurrency === 'XRP' ? -6 : 0
|
||||
const shift = numeratorShift - denominatorShift
|
||||
return shift === 0 ? quality :
|
||||
(new BigNumber(quality)).shiftedBy(shift).toString()
|
||||
return shift === 0
|
||||
? quality
|
||||
: new BigNumber(quality).shiftedBy(shift).toString()
|
||||
}
|
||||
|
||||
function parseQuality(quality?: number|null): number|undefined {
|
||||
function parseQuality(quality?: number | null): number | undefined {
|
||||
if (typeof quality !== 'number') {
|
||||
return undefined
|
||||
}
|
||||
return (new BigNumber(quality)).shiftedBy(-9).toNumber()
|
||||
return new BigNumber(quality).shiftedBy(-9).toNumber()
|
||||
}
|
||||
|
||||
function parseTimestamp(rippleTime?: number|null): string|undefined {
|
||||
function parseTimestamp(rippleTime?: number | null): string | undefined {
|
||||
if (typeof rippleTime !== 'number') {
|
||||
return undefined
|
||||
}
|
||||
@@ -57,14 +60,14 @@ function isPartialPayment(tx: any) {
|
||||
}
|
||||
|
||||
function parseDeliveredAmount(tx: any): Amount | void {
|
||||
|
||||
if (tx.TransactionType !== 'Payment' ||
|
||||
tx.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
if (
|
||||
tx.TransactionType !== 'Payment' ||
|
||||
tx.meta.TransactionResult !== 'tesSUCCESS'
|
||||
) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (tx.meta.delivered_amount &&
|
||||
tx.meta.delivered_amount === 'unavailable') {
|
||||
if (tx.meta.delivered_amount && tx.meta.delivered_amount === 'unavailable') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -96,7 +99,7 @@ function parseDeliveredAmount(tx: any): Amount | void {
|
||||
return undefined
|
||||
}
|
||||
|
||||
function parseOutcome(tx: any): any|undefined {
|
||||
function parseOutcome(tx: any): any | undefined {
|
||||
const metadata = tx.meta || tx.metaData
|
||||
if (!metadata) {
|
||||
return undefined
|
||||
@@ -121,11 +124,11 @@ function parseOutcome(tx: any): any|undefined {
|
||||
})
|
||||
}
|
||||
|
||||
function hexToString(hex: string): string|undefined {
|
||||
function hexToString(hex: string): string | undefined {
|
||||
return hex ? Buffer.from(hex, 'hex').toString('utf-8') : undefined
|
||||
}
|
||||
|
||||
function parseMemos(tx: any): Array<Memo>|undefined {
|
||||
function parseMemos(tx: any): Array<Memo> | undefined {
|
||||
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
|
||||
import {Amount, RippledAmount, Adjustment, MaxAdjustment,
|
||||
MinAdjustment} from '../common/types/objects'
|
||||
import {
|
||||
Amount,
|
||||
RippledAmount,
|
||||
Adjustment,
|
||||
MaxAdjustment,
|
||||
MinAdjustment
|
||||
} from '../common/types/objects'
|
||||
|
||||
// Amount where counterparty and value are optional
|
||||
export type LaxLaxAmount = {
|
||||
currency: string,
|
||||
value?: string,
|
||||
issuer?: string,
|
||||
currency: string
|
||||
value?: string
|
||||
issuer?: string
|
||||
counterparty?: string
|
||||
}
|
||||
|
||||
export type Path = {
|
||||
source: Adjustment | MaxAdjustment,
|
||||
destination: Adjustment | MinAdjustment,
|
||||
source: Adjustment | MaxAdjustment
|
||||
destination: Adjustment | MinAdjustment
|
||||
paths: string
|
||||
}
|
||||
|
||||
@@ -20,41 +24,43 @@ export type GetPaths = Array<Path>
|
||||
|
||||
export type PathFind = {
|
||||
source: {
|
||||
address: string,
|
||||
amount?: Amount,
|
||||
currencies?: Array<{currency: string, counterparty?:string}>
|
||||
},
|
||||
address: string
|
||||
amount?: Amount
|
||||
currencies?: Array<{currency: string; counterparty?: string}>
|
||||
}
|
||||
destination: {
|
||||
address: string,
|
||||
address: string
|
||||
amount: LaxLaxAmount
|
||||
}
|
||||
}
|
||||
|
||||
export type PathFindRequest = {
|
||||
command: string,
|
||||
source_account: string,
|
||||
destination_amount: RippledAmount,
|
||||
destination_account: string,
|
||||
source_currencies?: {currency: string, issuer?: string}[],
|
||||
command: string
|
||||
source_account: string
|
||||
destination_amount: RippledAmount
|
||||
destination_account: string
|
||||
source_currencies?: {currency: string; issuer?: string}[]
|
||||
send_max?: RippledAmount
|
||||
}
|
||||
|
||||
export type RippledPathsResponse = {
|
||||
alternatives: Array<{
|
||||
paths_computed: Array<Array<{
|
||||
type: number,
|
||||
type_hex: string,
|
||||
account?: string,
|
||||
issuer?: string,
|
||||
currency?: string
|
||||
}>>,
|
||||
paths_computed: Array<
|
||||
Array<{
|
||||
type: number
|
||||
type_hex: string
|
||||
account?: string
|
||||
issuer?: string
|
||||
currency?: string
|
||||
}>
|
||||
>
|
||||
source_amount: RippledAmount
|
||||
}>,
|
||||
type: string,
|
||||
destination_account: string,
|
||||
destination_amount: RippledAmount,
|
||||
destination_currencies?: Array<string>,
|
||||
source_account: string,
|
||||
source_currencies?: Array<{currency: string}>,
|
||||
}>
|
||||
type: string
|
||||
destination_account: string
|
||||
destination_amount: RippledAmount
|
||||
destination_currencies?: Array<string>
|
||||
source_account: string
|
||||
source_currencies?: Array<{currency: string}>
|
||||
full_reply?: boolean
|
||||
}
|
||||
|
||||
@@ -12,28 +12,37 @@ import {Connection} from '../common'
|
||||
import parsePathfind from './parse/pathfind'
|
||||
import {RippledAmount, Amount} from '../common/types/objects'
|
||||
import {
|
||||
GetPaths, PathFind, RippledPathsResponse, PathFindRequest
|
||||
GetPaths,
|
||||
PathFind,
|
||||
RippledPathsResponse,
|
||||
PathFindRequest
|
||||
} from './pathfind-types'
|
||||
import {RippleAPI} from '..'
|
||||
const NotFoundError = errors.NotFoundError
|
||||
const ValidationError = errors.ValidationError
|
||||
|
||||
|
||||
function addParams(request: PathFindRequest, result: RippledPathsResponse
|
||||
function addParams(
|
||||
request: PathFindRequest,
|
||||
result: RippledPathsResponse
|
||||
): RippledPathsResponse {
|
||||
return _.defaults(_.assign({}, result, {
|
||||
source_account: request.source_account,
|
||||
source_currencies: request.source_currencies
|
||||
}), {destination_amount: request.destination_amount})
|
||||
return _.defaults(
|
||||
_.assign({}, result, {
|
||||
source_account: request.source_account,
|
||||
source_currencies: request.source_currencies
|
||||
}),
|
||||
{destination_amount: request.destination_amount}
|
||||
)
|
||||
}
|
||||
|
||||
function requestPathFind(connection: Connection, pathfind: PathFind
|
||||
function requestPathFind(
|
||||
connection: Connection,
|
||||
pathfind: PathFind
|
||||
): Promise<RippledPathsResponse> {
|
||||
const destinationAmount: Amount = _.assign(
|
||||
{
|
||||
// This is converted back to drops by toRippledAmount()
|
||||
value: pathfind.destination.amount.currency === 'XRP' ?
|
||||
dropsToXrp('-1') : '-1'
|
||||
value:
|
||||
pathfind.destination.amount.currency === 'XRP' ? dropsToXrp('-1') : '-1'
|
||||
},
|
||||
pathfind.destination.amount
|
||||
)
|
||||
@@ -43,21 +52,26 @@ function requestPathFind(connection: Connection, pathfind: PathFind
|
||||
destination_account: pathfind.destination.address,
|
||||
destination_amount: toRippledAmount(destinationAmount)
|
||||
}
|
||||
if (typeof request.destination_amount === 'object'
|
||||
&& !request.destination_amount.issuer) {
|
||||
if (
|
||||
typeof request.destination_amount === 'object' &&
|
||||
!request.destination_amount.issuer
|
||||
) {
|
||||
// Convert blank issuer to sender's address
|
||||
// (Ripple convention for 'any issuer')
|
||||
// https://developers.ripple.com/payment.html#special-issuer-values-for-sendmax-and-amount
|
||||
request.destination_amount.issuer = request.destination_account
|
||||
}
|
||||
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
|
||||
request.source_currencies = pathfind.source.currencies.map(
|
||||
amount => renameCounterpartyToIssuer(amount))
|
||||
request.source_currencies = pathfind.source.currencies.map(amount =>
|
||||
renameCounterpartyToIssuer(amount)
|
||||
)
|
||||
}
|
||||
if (pathfind.source.amount) {
|
||||
if (pathfind.destination.amount.value !== undefined) {
|
||||
throw new ValidationError('Cannot specify both source.amount'
|
||||
+ ' and destination.amount.value in getPaths')
|
||||
throw new ValidationError(
|
||||
'Cannot specify both source.amount' +
|
||||
' and destination.amount.value in getPaths'
|
||||
)
|
||||
}
|
||||
request.send_max = toRippledAmount(pathfind.source.amount)
|
||||
if (typeof request.send_max !== 'string' && !request.send_max.issuer) {
|
||||
@@ -68,12 +82,14 @@ function requestPathFind(connection: Connection, pathfind: PathFind
|
||||
return connection.request(request).then(paths => addParams(request, paths))
|
||||
}
|
||||
|
||||
function addDirectXrpPath(paths: RippledPathsResponse, xrpBalance: string
|
||||
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
|
||||
// @ts-ignore: destinationAmount can be a currency amount object! Fix!
|
||||
if ((new BigNumber(xrpBalance)).isGreaterThanOrEqualTo(destinationAmount)) {
|
||||
if (new BigNumber(xrpBalance).isGreaterThanOrEqualTo(destinationAmount)) {
|
||||
paths.alternatives.unshift({
|
||||
paths_computed: [],
|
||||
source_amount: paths.destination_amount
|
||||
@@ -84,38 +100,49 @@ function addDirectXrpPath(paths: RippledPathsResponse, xrpBalance: string
|
||||
|
||||
function isRippledIOUAmount(amount: RippledAmount) {
|
||||
// rippled XRP amounts are specified as decimal strings
|
||||
return (typeof amount === 'object') &&
|
||||
amount.currency && (amount.currency !== 'XRP')
|
||||
return (
|
||||
typeof amount === 'object' && amount.currency && amount.currency !== 'XRP'
|
||||
)
|
||||
}
|
||||
|
||||
function conditionallyAddDirectXRPPath(connection: Connection, address: string,
|
||||
function conditionallyAddDirectXRPPath(
|
||||
connection: Connection,
|
||||
address: string,
|
||||
paths: RippledPathsResponse
|
||||
): Promise<RippledPathsResponse> {
|
||||
if (isRippledIOUAmount(paths.destination_amount)
|
||||
|| !_.includes(paths.destination_currencies, 'XRP')) {
|
||||
if (
|
||||
isRippledIOUAmount(paths.destination_amount) ||
|
||||
!_.includes(paths.destination_currencies, 'XRP')
|
||||
) {
|
||||
return Promise.resolve(paths)
|
||||
}
|
||||
return getXRPBalance(connection, address, undefined).then(
|
||||
xrpBalance => addDirectXrpPath(paths, xrpBalance))
|
||||
return getXRPBalance(connection, address, undefined).then(xrpBalance =>
|
||||
addDirectXrpPath(paths, xrpBalance)
|
||||
)
|
||||
}
|
||||
|
||||
function filterSourceFundsLowPaths(pathfind: PathFind,
|
||||
function filterSourceFundsLowPaths(
|
||||
pathfind: PathFind,
|
||||
paths: RippledPathsResponse
|
||||
): RippledPathsResponse {
|
||||
if (pathfind.source.amount &&
|
||||
pathfind.destination.amount.value === undefined && paths.alternatives) {
|
||||
if (
|
||||
pathfind.source.amount &&
|
||||
pathfind.destination.amount.value === undefined &&
|
||||
paths.alternatives
|
||||
) {
|
||||
paths.alternatives = _.filter(paths.alternatives, alt => {
|
||||
if (!alt.source_amount) {
|
||||
return false
|
||||
}
|
||||
const pathfindSourceAmountValue = new BigNumber(
|
||||
pathfind.source.amount.currency === 'XRP' ?
|
||||
xrpToDrops(pathfind.source.amount.value) :
|
||||
pathfind.source.amount.value)
|
||||
pathfind.source.amount.currency === 'XRP'
|
||||
? xrpToDrops(pathfind.source.amount.value)
|
||||
: pathfind.source.amount.value
|
||||
)
|
||||
const altSourceAmountValue = new BigNumber(
|
||||
typeof alt.source_amount === 'string' ?
|
||||
alt.source_amount :
|
||||
alt.source_amount.value
|
||||
typeof alt.source_amount === 'string'
|
||||
? alt.source_amount
|
||||
: alt.source_amount.value
|
||||
)
|
||||
return altSourceAmountValue.eq(pathfindSourceAmountValue)
|
||||
})
|
||||
@@ -127,24 +154,35 @@ function formatResponse(pathfind: PathFind, paths: RippledPathsResponse) {
|
||||
if (paths.alternatives && paths.alternatives.length > 0) {
|
||||
return parsePathfind(paths)
|
||||
}
|
||||
if (paths.destination_currencies !== undefined &&
|
||||
!_.includes(paths.destination_currencies,
|
||||
pathfind.destination.amount.currency)) {
|
||||
throw new NotFoundError('No paths found. ' +
|
||||
'The destination_account does not accept ' +
|
||||
pathfind.destination.amount.currency + ', they only accept: ' +
|
||||
paths.destination_currencies.join(', '))
|
||||
if (
|
||||
paths.destination_currencies !== undefined &&
|
||||
!_.includes(
|
||||
paths.destination_currencies,
|
||||
pathfind.destination.amount.currency
|
||||
)
|
||||
) {
|
||||
throw new NotFoundError(
|
||||
'No paths found. ' +
|
||||
'The destination_account does not accept ' +
|
||||
pathfind.destination.amount.currency +
|
||||
', they only accept: ' +
|
||||
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')
|
||||
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'
|
||||
)
|
||||
} 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')
|
||||
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'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,9 +190,10 @@ function getPaths(this: RippleAPI, pathfind: PathFind): Promise<GetPaths> {
|
||||
validate.getPaths({pathfind})
|
||||
|
||||
const address = pathfind.source.address
|
||||
return requestPathFind(this.connection, pathfind).then(paths =>
|
||||
conditionallyAddDirectXRPPath(this.connection, address, paths)
|
||||
)
|
||||
return requestPathFind(this.connection, pathfind)
|
||||
.then(paths =>
|
||||
conditionallyAddDirectXRPPath(this.connection, address, paths)
|
||||
)
|
||||
.then(paths => filterSourceFundsLowPaths(pathfind, paths))
|
||||
.then(paths => formatResponse(pathfind, paths))
|
||||
}
|
||||
|
||||
@@ -10,15 +10,18 @@ const NotFoundError = errors.NotFoundError
|
||||
function formatResponse(
|
||||
response: LedgerEntryResponse
|
||||
): FormattedPaymentChannel {
|
||||
if (response.node === undefined ||
|
||||
response.node.LedgerEntryType !== 'PayChannel') {
|
||||
if (
|
||||
response.node === undefined ||
|
||||
response.node.LedgerEntryType !== 'PayChannel'
|
||||
) {
|
||||
throw new NotFoundError('Payment channel ledger entry not found')
|
||||
}
|
||||
return parsePaymentChannel(response.node)
|
||||
}
|
||||
|
||||
async function getPaymentChannel(
|
||||
this: RippleAPI, id: string
|
||||
this: RippleAPI,
|
||||
id: string
|
||||
): Promise<FormattedPaymentChannel> {
|
||||
// 1. Validate
|
||||
validate.getPaymentChannel({id})
|
||||
|
||||
@@ -12,8 +12,9 @@ export type SettingsOptions = {
|
||||
}
|
||||
|
||||
export function parseAccountFlags(
|
||||
value: number,
|
||||
options: {excludeFalse?: boolean} = {}) {
|
||||
value: number,
|
||||
options: {excludeFalse?: boolean} = {}
|
||||
) {
|
||||
const settings = {}
|
||||
for (const flagName in AccountFlags) {
|
||||
if (value & AccountFlags[flagName]) {
|
||||
@@ -35,7 +36,9 @@ function formatSettings(response: AccountInfoResponse) {
|
||||
}
|
||||
|
||||
export async function getSettings(
|
||||
this: RippleAPI, address: string, options: SettingsOptions = {}
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: SettingsOptions = {}
|
||||
): Promise<FormattedSettings> {
|
||||
// 1. Validate
|
||||
validate.getSettings({address, options})
|
||||
|
||||
@@ -8,19 +8,20 @@ import {RippledError} from '../common/errors'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type TransactionOptions = {
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number,
|
||||
minLedgerVersion?: number
|
||||
maxLedgerVersion?: number
|
||||
includeRawTransaction?: boolean
|
||||
}
|
||||
type TransactionResponse = FormattedTransactionType & {
|
||||
hash: string,
|
||||
ledger_index: number,
|
||||
meta: any,
|
||||
validated?: boolean
|
||||
hash: string
|
||||
ledger_index: number
|
||||
meta: any
|
||||
validated?: boolean
|
||||
}
|
||||
|
||||
|
||||
function attachTransactionDate(connection: Connection, tx: any
|
||||
function attachTransactionDate(
|
||||
connection: Connection,
|
||||
tx: any
|
||||
): Promise<TransactionResponse> {
|
||||
if (tx.date) {
|
||||
return Promise.resolve(tx)
|
||||
@@ -31,7 +32,8 @@ function attachTransactionDate(connection: Connection, tx: any
|
||||
if (!ledgerVersion) {
|
||||
return new Promise(() => {
|
||||
const error = new errors.NotFoundError(
|
||||
'Transaction has not been validated yet; try again later')
|
||||
'Transaction has not been validated yet; try again later'
|
||||
)
|
||||
error.data = {
|
||||
details: '(ledger_index and LedgerSequence not found in tx)'
|
||||
}
|
||||
@@ -44,56 +46,74 @@ function attachTransactionDate(connection: Connection, tx: any
|
||||
ledger_index: ledgerVersion
|
||||
}
|
||||
|
||||
return connection.request(request).then(data => {
|
||||
if (typeof data.ledger.close_time === 'number') {
|
||||
return _.assign({date: data.ledger.close_time}, tx)
|
||||
}
|
||||
throw new errors.UnexpectedError('Ledger missing close_time')
|
||||
}).catch(error => {
|
||||
if (error instanceof errors.UnexpectedError) {
|
||||
throw error
|
||||
}
|
||||
throw new errors.NotFoundError('Transaction ledger not found')
|
||||
})
|
||||
return connection
|
||||
.request(request)
|
||||
.then(data => {
|
||||
if (typeof data.ledger.close_time === 'number') {
|
||||
return _.assign({date: data.ledger.close_time}, tx)
|
||||
}
|
||||
throw new errors.UnexpectedError('Ledger missing close_time')
|
||||
})
|
||||
.catch(error => {
|
||||
if (error instanceof errors.UnexpectedError) {
|
||||
throw error
|
||||
}
|
||||
throw new errors.NotFoundError('Transaction ledger not found')
|
||||
})
|
||||
}
|
||||
|
||||
function isTransactionInRange(tx: any, options: TransactionOptions) {
|
||||
return (!options.minLedgerVersion
|
||||
|| tx.ledger_index >= options.minLedgerVersion)
|
||||
&& (!options.maxLedgerVersion
|
||||
|| tx.ledger_index <= options.maxLedgerVersion)
|
||||
return (
|
||||
(!options.minLedgerVersion ||
|
||||
tx.ledger_index >= options.minLedgerVersion) &&
|
||||
(!options.maxLedgerVersion || tx.ledger_index <= options.maxLedgerVersion)
|
||||
)
|
||||
}
|
||||
|
||||
function convertError(connection: Connection, options: TransactionOptions,
|
||||
function convertError(
|
||||
connection: Connection,
|
||||
options: TransactionOptions,
|
||||
error: RippledError
|
||||
): Promise<Error> {
|
||||
let shouldUseNotFoundError = false
|
||||
if ((error.data && error.data.error === 'txnNotFound') || error.message === 'txnNotFound') {
|
||||
if (
|
||||
(error.data && error.data.error === 'txnNotFound') ||
|
||||
error.message === 'txnNotFound'
|
||||
) {
|
||||
shouldUseNotFoundError = true
|
||||
}
|
||||
|
||||
// In the future, we should deprecate this error, instead passing through the one from rippled.
|
||||
const _error = shouldUseNotFoundError ? new errors.NotFoundError('Transaction not found') : error
|
||||
const _error = shouldUseNotFoundError
|
||||
? new errors.NotFoundError('Transaction not found')
|
||||
: error
|
||||
|
||||
if (_error instanceof errors.NotFoundError) {
|
||||
return utils.hasCompleteLedgerRange(connection, options.minLedgerVersion,
|
||||
options.maxLedgerVersion).then(hasCompleteLedgerRange => {
|
||||
if (!hasCompleteLedgerRange) {
|
||||
return utils.isPendingLedgerVersion(
|
||||
connection, options.maxLedgerVersion)
|
||||
.then(isPendingLedgerVersion => {
|
||||
return isPendingLedgerVersion ?
|
||||
new errors.PendingLedgerVersionError() :
|
||||
new errors.MissingLedgerHistoryError()
|
||||
})
|
||||
}
|
||||
return _error
|
||||
})
|
||||
return utils
|
||||
.hasCompleteLedgerRange(
|
||||
connection,
|
||||
options.minLedgerVersion,
|
||||
options.maxLedgerVersion
|
||||
)
|
||||
.then(hasCompleteLedgerRange => {
|
||||
if (!hasCompleteLedgerRange) {
|
||||
return utils
|
||||
.isPendingLedgerVersion(connection, options.maxLedgerVersion)
|
||||
.then(isPendingLedgerVersion => {
|
||||
return isPendingLedgerVersion
|
||||
? new errors.PendingLedgerVersionError()
|
||||
: new errors.MissingLedgerHistoryError()
|
||||
})
|
||||
}
|
||||
return _error
|
||||
})
|
||||
}
|
||||
return Promise.resolve(_error)
|
||||
}
|
||||
|
||||
function formatResponse(options: TransactionOptions, tx: TransactionResponse
|
||||
function formatResponse(
|
||||
options: TransactionOptions,
|
||||
tx: TransactionResponse
|
||||
): FormattedTransactionType {
|
||||
if (tx.validated !== true || !isTransactionInRange(tx, options)) {
|
||||
throw new errors.NotFoundError('Transaction not found')
|
||||
@@ -101,7 +121,10 @@ function formatResponse(options: TransactionOptions, tx: TransactionResponse
|
||||
return parseTransaction(tx, options.includeRawTransaction)
|
||||
}
|
||||
|
||||
async function getTransaction(this: RippleAPI, id: string, options: TransactionOptions = {}
|
||||
async function getTransaction(
|
||||
this: RippleAPI,
|
||||
id: string,
|
||||
options: TransactionOptions = {}
|
||||
): Promise<FormattedTransactionType> {
|
||||
validate.getTransaction({id, options})
|
||||
const _options = await utils.ensureLedgerVersion.call(this, options)
|
||||
@@ -113,7 +136,7 @@ async function getTransaction(this: RippleAPI, id: string, options: TransactionO
|
||||
const txWithDate = await attachTransactionDate(this.connection, tx)
|
||||
return formatResponse(_options, txWithDate)
|
||||
} catch (error) {
|
||||
throw (await convertError(this.connection, _options, error))
|
||||
throw await convertError(this.connection, _options, error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as _ from 'lodash'
|
||||
import binary from 'ripple-binary-codec';
|
||||
import binary from 'ripple-binary-codec'
|
||||
import {computeTransactionHash} from '../common/hashes'
|
||||
import * as utils from './utils'
|
||||
import parseTransaction from './parse/transaction'
|
||||
@@ -9,17 +9,17 @@ import {FormattedTransactionType} from '../transaction/types'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type TransactionsOptions = {
|
||||
start?: string,
|
||||
limit?: number,
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number,
|
||||
earliestFirst?: boolean,
|
||||
excludeFailures?: boolean,
|
||||
initiated?: boolean,
|
||||
counterparty?: string,
|
||||
types?: Array<string>,
|
||||
includeRawTransactions?: boolean,
|
||||
binary?: boolean,
|
||||
start?: string
|
||||
limit?: number
|
||||
minLedgerVersion?: number
|
||||
maxLedgerVersion?: number
|
||||
earliestFirst?: boolean
|
||||
excludeFailures?: boolean
|
||||
initiated?: boolean
|
||||
counterparty?: string
|
||||
types?: Array<string>
|
||||
includeRawTransactions?: boolean
|
||||
binary?: boolean
|
||||
startTx?: FormattedTransactionType
|
||||
}
|
||||
|
||||
@@ -39,8 +39,10 @@ function parseBinaryTransaction(transaction) {
|
||||
function parseAccountTxTransaction(tx, includeRawTransaction: boolean) {
|
||||
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}), includeRawTransaction)
|
||||
return parseTransaction(
|
||||
_.assign({}, _tx.tx, {meta: _tx.meta, validated: _tx.validated}),
|
||||
includeRawTransaction
|
||||
)
|
||||
}
|
||||
|
||||
function counterpartyFilter(filters, tx: FormattedTransactionType) {
|
||||
@@ -48,15 +50,20 @@ function counterpartyFilter(filters, tx: FormattedTransactionType) {
|
||||
return true
|
||||
}
|
||||
const specification: any = tx.specification
|
||||
if (specification && ((specification.destination &&
|
||||
specification.destination.address === filters.counterparty) ||
|
||||
(specification.counterparty === filters.counterparty))) {
|
||||
return true
|
||||
if (
|
||||
specification &&
|
||||
((specification.destination &&
|
||||
specification.destination.address === filters.counterparty) ||
|
||||
specification.counterparty === filters.counterparty)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function transactionFilter(address: string, filters: TransactionsOptions,
|
||||
function transactionFilter(
|
||||
address: string,
|
||||
filters: TransactionsOptions,
|
||||
tx: FormattedTransactionType
|
||||
) {
|
||||
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
||||
@@ -78,15 +85,21 @@ function transactionFilter(address: string, filters: TransactionsOptions,
|
||||
}
|
||||
|
||||
function orderFilter(
|
||||
options: TransactionsOptions, tx: FormattedTransactionType
|
||||
options: TransactionsOptions,
|
||||
tx: FormattedTransactionType
|
||||
) {
|
||||
return !options.startTx || (options.earliestFirst ?
|
||||
utils.compareTransactions(tx, options.startTx) > 0 :
|
||||
utils.compareTransactions(tx, options.startTx) < 0)
|
||||
return (
|
||||
!options.startTx ||
|
||||
(options.earliestFirst
|
||||
? utils.compareTransactions(tx, options.startTx) > 0
|
||||
: utils.compareTransactions(tx, options.startTx) < 0)
|
||||
)
|
||||
}
|
||||
|
||||
function formatPartialResponse(address: string,
|
||||
options: TransactionsOptions, data
|
||||
function formatPartialResponse(
|
||||
address: string,
|
||||
options: TransactionsOptions,
|
||||
data
|
||||
) {
|
||||
const parse = tx =>
|
||||
parseAccountTxTransaction(tx, options.includeRawTransactions)
|
||||
@@ -100,8 +113,12 @@ function formatPartialResponse(address: string,
|
||||
}
|
||||
}
|
||||
|
||||
function getAccountTx(connection: Connection, address: string,
|
||||
options: TransactionsOptions, marker: string, limit: number
|
||||
function getAccountTx(
|
||||
connection: Connection,
|
||||
address: string,
|
||||
options: TransactionsOptions,
|
||||
marker: string,
|
||||
limit: number
|
||||
) {
|
||||
const request = {
|
||||
command: 'account_tx',
|
||||
@@ -116,12 +133,15 @@ function getAccountTx(connection: Connection, address: string,
|
||||
marker: marker
|
||||
}
|
||||
|
||||
return connection.request(request).then(response =>
|
||||
formatPartialResponse(address, options, response))
|
||||
return connection
|
||||
.request(request)
|
||||
.then(response => formatPartialResponse(address, options, response))
|
||||
}
|
||||
|
||||
function checkForLedgerGaps(connection: Connection,
|
||||
options: TransactionsOptions, transactions: GetTransactionsResponse
|
||||
function checkForLedgerGaps(
|
||||
connection: Connection,
|
||||
options: TransactionsOptions,
|
||||
transactions: GetTransactionsResponse
|
||||
) {
|
||||
let {minLedgerVersion, maxLedgerVersion} = options
|
||||
|
||||
@@ -136,25 +156,32 @@ function checkForLedgerGaps(connection: Connection,
|
||||
}
|
||||
}
|
||||
|
||||
return utils.hasCompleteLedgerRange(connection, minLedgerVersion,
|
||||
maxLedgerVersion).then(hasCompleteLedgerRange => {
|
||||
if (!hasCompleteLedgerRange) {
|
||||
throw new errors.MissingLedgerHistoryError()
|
||||
}
|
||||
})
|
||||
return utils
|
||||
.hasCompleteLedgerRange(connection, minLedgerVersion, maxLedgerVersion)
|
||||
.then(hasCompleteLedgerRange => {
|
||||
if (!hasCompleteLedgerRange) {
|
||||
throw new errors.MissingLedgerHistoryError()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function formatResponse(connection: Connection, options: TransactionsOptions,
|
||||
function formatResponse(
|
||||
connection: Connection,
|
||||
options: TransactionsOptions,
|
||||
transactions: GetTransactionsResponse
|
||||
) {
|
||||
const compare = options.earliestFirst ? utils.compareTransactions :
|
||||
_.rearg(utils.compareTransactions, 1, 0)
|
||||
const compare = options.earliestFirst
|
||||
? utils.compareTransactions
|
||||
: _.rearg(utils.compareTransactions, 1, 0)
|
||||
const sortedTransactions = transactions.sort(compare)
|
||||
return checkForLedgerGaps(connection, options, sortedTransactions).then(
|
||||
() => sortedTransactions)
|
||||
() => sortedTransactions
|
||||
)
|
||||
}
|
||||
|
||||
function getTransactionsInternal(connection: Connection, address: string,
|
||||
function getTransactionsInternal(
|
||||
connection: Connection,
|
||||
address: string,
|
||||
options: TransactionsOptions
|
||||
): Promise<GetTransactionsResponse> {
|
||||
const getter = _.partial(getAccountTx, connection, address, options)
|
||||
@@ -162,7 +189,10 @@ function getTransactionsInternal(connection: Connection, address: string,
|
||||
return utils.getRecursive(getter, options.limit).then(format)
|
||||
}
|
||||
|
||||
function getTransactions(this: RippleAPI, address: string, options: TransactionsOptions = {}
|
||||
function getTransactions(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: TransactionsOptions = {}
|
||||
): Promise<GetTransactionsResponse> {
|
||||
validate.getTransactions({address, options})
|
||||
|
||||
@@ -176,8 +206,9 @@ function getTransactions(this: RippleAPI, address: string, options: Transactions
|
||||
if (options.start) {
|
||||
return getTransaction.call(this, options.start).then(tx => {
|
||||
const ledgerVersion = tx.outcome.ledgerVersion
|
||||
const bound = options.earliestFirst ?
|
||||
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion}
|
||||
const bound = options.earliestFirst
|
||||
? {minLedgerVersion: ledgerVersion}
|
||||
: {maxLedgerVersion: ledgerVersion}
|
||||
const startOptions = _.assign({}, defaults, options, {startTx: tx}, bound)
|
||||
return getTransactionsInternal(this.connection, address, startOptions)
|
||||
})
|
||||
|
||||
@@ -5,9 +5,9 @@ import {RippleAPI} from '..'
|
||||
import {FormattedTrustline} from '../common/types/objects/trustlines'
|
||||
|
||||
export type GetTrustlinesOptions = {
|
||||
counterparty?: string,
|
||||
currency?: string,
|
||||
limit?: number,
|
||||
counterparty?: string
|
||||
currency?: string
|
||||
limit?: number
|
||||
ledgerVersion?: number
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ function currencyFilter(currency: string, trustline: FormattedTrustline) {
|
||||
}
|
||||
|
||||
async function getTrustlines(
|
||||
this: RippleAPI, address: string, options: GetTrustlinesOptions = {}
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
options: GetTrustlinesOptions = {}
|
||||
): Promise<FormattedTrustline[]> {
|
||||
// 1. Validate
|
||||
validate.getTrustlines({address, options})
|
||||
|
||||
@@ -4,10 +4,10 @@ import * as common from '../common'
|
||||
import {Connection} from '../common'
|
||||
import {FormattedTransactionType} from '../transaction/types'
|
||||
import {Issue} from '../common/types/objects'
|
||||
import {RippleAPI} from '..'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type RecursiveData = {
|
||||
marker: string,
|
||||
marker: string
|
||||
results: Array<any>
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(Math.max(value, min), max)
|
||||
}
|
||||
|
||||
function getXRPBalance(connection: Connection, address: string,
|
||||
function getXRPBalance(
|
||||
connection: Connection,
|
||||
address: string,
|
||||
ledgerVersion?: number
|
||||
): Promise<string> {
|
||||
const request = {
|
||||
@@ -26,13 +28,16 @@ function getXRPBalance(connection: Connection, address: string,
|
||||
account: address,
|
||||
ledger_index: ledgerVersion
|
||||
}
|
||||
return connection.request(request).then(data =>
|
||||
common.dropsToXrp(data.account_data.Balance))
|
||||
return connection
|
||||
.request(request)
|
||||
.then(data => common.dropsToXrp(data.account_data.Balance))
|
||||
}
|
||||
|
||||
// If the marker is omitted from a response, you have reached the end
|
||||
function getRecursiveRecur(
|
||||
getter: Getter, marker: string | undefined, limit: number
|
||||
getter: Getter,
|
||||
marker: string | undefined,
|
||||
limit: number
|
||||
): Promise<Array<any>> {
|
||||
return getter(marker, limit).then(data => {
|
||||
const remaining = limit - data.results.length
|
||||
@@ -50,17 +55,20 @@ function getRecursive(getter: Getter, limit?: number): Promise<Array<any>> {
|
||||
}
|
||||
|
||||
function renameCounterpartyToIssuer<T>(
|
||||
obj: T & {counterparty?: string, issuer?: string}
|
||||
): (T & {issuer?: string}) {
|
||||
const issuer = (obj.counterparty !== undefined) ?
|
||||
obj.counterparty :
|
||||
((obj.issuer !== undefined) ? obj.issuer : undefined)
|
||||
obj: T & {counterparty?: string; issuer?: string}
|
||||
): T & {issuer?: string} {
|
||||
const issuer =
|
||||
obj.counterparty !== undefined
|
||||
? obj.counterparty
|
||||
: obj.issuer !== undefined
|
||||
? obj.issuer
|
||||
: undefined
|
||||
const withIssuer = Object.assign({}, obj, {issuer})
|
||||
delete withIssuer.counterparty
|
||||
return withIssuer
|
||||
}
|
||||
|
||||
export type RequestBookOffersArgs = {taker_gets: Issue, taker_pays: Issue}
|
||||
export type RequestBookOffersArgs = {taker_gets: Issue; taker_pays: Issue}
|
||||
|
||||
function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
|
||||
const taker_gets = renameCounterpartyToIssuer(order.taker_gets)
|
||||
@@ -70,7 +78,7 @@ function renameCounterpartyToIssuerInOrder(order: RequestBookOffersArgs) {
|
||||
}
|
||||
|
||||
function signum(num) {
|
||||
return (num === 0) ? 0 : (num > 0 ? 1 : -1)
|
||||
return num === 0 ? 0 : num > 0 ? 1 : -1
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +88,8 @@ function signum(num) {
|
||||
* See: https://developers.ripple.com/transaction-metadata.html
|
||||
*/
|
||||
function compareTransactions(
|
||||
first: FormattedTransactionType, second: FormattedTransactionType
|
||||
first: FormattedTransactionType,
|
||||
second: FormattedTransactionType
|
||||
): number {
|
||||
if (!first.outcome || !second.outcome) {
|
||||
return 0
|
||||
@@ -91,30 +100,38 @@ function compareTransactions(
|
||||
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1
|
||||
}
|
||||
|
||||
function hasCompleteLedgerRange(connection: Connection,
|
||||
minLedgerVersion?: number, maxLedgerVersion?: number
|
||||
function hasCompleteLedgerRange(
|
||||
connection: Connection,
|
||||
minLedgerVersion?: number,
|
||||
maxLedgerVersion?: number
|
||||
): Promise<boolean> {
|
||||
const firstLedgerVersion = 32570 // earlier versions have been lost
|
||||
return connection.hasLedgerVersions(
|
||||
minLedgerVersion || firstLedgerVersion, maxLedgerVersion)
|
||||
minLedgerVersion || firstLedgerVersion,
|
||||
maxLedgerVersion
|
||||
)
|
||||
}
|
||||
|
||||
function isPendingLedgerVersion(connection: Connection,
|
||||
function isPendingLedgerVersion(
|
||||
connection: Connection,
|
||||
maxLedgerVersion?: number
|
||||
): Promise<boolean> {
|
||||
return connection.getLedgerVersion().then(ledgerVersion =>
|
||||
ledgerVersion < (maxLedgerVersion || 0))
|
||||
return connection
|
||||
.getLedgerVersion()
|
||||
.then(ledgerVersion => ledgerVersion < (maxLedgerVersion || 0))
|
||||
}
|
||||
|
||||
function ensureLedgerVersion(this: RippleAPI, options: any
|
||||
): Promise<object> {
|
||||
if (Boolean(options) && options.ledgerVersion !== undefined &&
|
||||
function ensureLedgerVersion(this: RippleAPI, options: any): Promise<object> {
|
||||
if (
|
||||
Boolean(options) &&
|
||||
options.ledgerVersion !== undefined &&
|
||||
options.ledgerVersion !== null
|
||||
) {
|
||||
return Promise.resolve(options)
|
||||
}
|
||||
return this.getLedgerVersion().then(ledgerVersion =>
|
||||
_.assign({}, options, {ledgerVersion}))
|
||||
_.assign({}, options, {ledgerVersion})
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {deriveKeypair, deriveAddress} from 'ripple-keypairs'
|
||||
import {classicAddressToXAddress} from 'ripple-address-codec'
|
||||
|
||||
function deriveXAddress(options: {publicKey: string, tag: number | false, test: boolean}): string {
|
||||
function deriveXAddress(options: {
|
||||
publicKey: string
|
||||
tag: number | false
|
||||
test: boolean
|
||||
}): string {
|
||||
const classicAddress = deriveAddress(options.publicKey)
|
||||
return classicAddressToXAddress(classicAddress, options.tag, options.test)
|
||||
}
|
||||
|
||||
export {
|
||||
deriveKeypair,
|
||||
deriveAddress,
|
||||
deriveXAddress
|
||||
}
|
||||
export {deriveKeypair, deriveAddress, deriveXAddress}
|
||||
|
||||
@@ -3,23 +3,23 @@ import keypairs from 'ripple-keypairs'
|
||||
import {errors, validate} from '../common'
|
||||
|
||||
export type GeneratedAddress = {
|
||||
xAddress: string,
|
||||
classicAddress?: string,
|
||||
address?: string, // @deprecated Use `classicAddress` instead.
|
||||
xAddress: string
|
||||
classicAddress?: string
|
||||
address?: string // @deprecated Use `classicAddress` instead.
|
||||
secret: string
|
||||
}
|
||||
|
||||
export interface GenerateAddressOptions {
|
||||
// The entropy to use to generate the seed.
|
||||
entropy?: Uint8Array,
|
||||
entropy?: Uint8Array | number[]
|
||||
|
||||
// The digital signature algorithm to generate an address for. Can be `ecdsa-secp256k1` (default) or `ed25519`.
|
||||
algorithm?: 'ecdsa-secp256k1' | 'ed25519',
|
||||
algorithm?: 'ecdsa-secp256k1' | 'ed25519'
|
||||
|
||||
// Specifies whether the address is intended for use on a test network such as Testnet or Devnet.
|
||||
// If `true`, the address should only be used for testing, and will start with `T`.
|
||||
// If `false` (default), the address should only be used on mainnet, and will start with `X`.
|
||||
test?: boolean,
|
||||
test?: boolean
|
||||
|
||||
// If `true`, return the classic address, in addition to the X-address.
|
||||
includeClassicAddress?: boolean
|
||||
@@ -32,7 +32,11 @@ function generateAddressAPI(options: GenerateAddressOptions): GeneratedAddress {
|
||||
const keypair = keypairs.deriveKeypair(secret)
|
||||
const classicAddress = keypairs.deriveAddress(keypair.publicKey)
|
||||
const returnValue: any = {
|
||||
xAddress: classicAddressToXAddress(classicAddress, false, options && options.test),
|
||||
xAddress: classicAddressToXAddress(
|
||||
classicAddress,
|
||||
false,
|
||||
options && options.test
|
||||
),
|
||||
secret
|
||||
}
|
||||
if (options.includeClassicAddress) {
|
||||
@@ -45,6 +49,4 @@ function generateAddressAPI(options: GenerateAddressOptions): GeneratedAddress {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
generateAddressAPI
|
||||
}
|
||||
export {generateAddressAPI}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import * as _ from 'lodash'
|
||||
import {computeLedgerHash, computeTransactionTreeHash, computeStateTreeHash} from '../common/hashes'
|
||||
import {
|
||||
computeLedgerHash,
|
||||
computeTransactionTreeHash,
|
||||
computeStateTreeHash
|
||||
} from '../common/hashes'
|
||||
import * as common from '../common'
|
||||
|
||||
function convertLedgerHeader(header): any {
|
||||
@@ -25,63 +29,79 @@ function hashLedgerHeader(ledgerHeader) {
|
||||
return computeLedgerHash(header)
|
||||
}
|
||||
|
||||
function computeTransactionHash(ledger,
|
||||
options: ComputeLedgerHeaderHashOptions) {
|
||||
function computeTransactionHash(
|
||||
ledger,
|
||||
options: ComputeLedgerHeaderHashOptions
|
||||
) {
|
||||
let transactions: any[]
|
||||
if (ledger.rawTransactions) {
|
||||
transactions = JSON.parse(ledger.rawTransactions)
|
||||
} else if (ledger.transactions) {
|
||||
try {
|
||||
transactions = ledger.transactions.map(tx =>
|
||||
JSON.parse(tx.rawTransaction))
|
||||
JSON.parse(tx.rawTransaction)
|
||||
)
|
||||
} catch (e) {
|
||||
if (e.toString() === 'SyntaxError: Unexpected' +
|
||||
' token u in JSON at position 0') {
|
||||
if (
|
||||
e.toString() ===
|
||||
'SyntaxError: Unexpected' + ' token u in JSON at position 0'
|
||||
) {
|
||||
// one or more of the `tx.rawTransaction`s is undefined
|
||||
throw new common.errors.ValidationError('ledger'
|
||||
+ ' is missing raw transactions')
|
||||
throw new common.errors.ValidationError(
|
||||
'ledger' + ' is missing raw transactions'
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (options.computeTreeHashes) {
|
||||
throw new common.errors.ValidationError('transactions'
|
||||
+ ' property is missing from the ledger')
|
||||
throw new common.errors.ValidationError(
|
||||
'transactions' + ' property is missing from the ledger'
|
||||
)
|
||||
}
|
||||
return ledger.transactionHash
|
||||
}
|
||||
const txs = _.map(transactions, tx => {
|
||||
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {})
|
||||
// rename `meta` back to `metaData`
|
||||
const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'),
|
||||
tx.meta ? {metaData: tx.meta} : {})
|
||||
const renameMeta = _.assign(
|
||||
{},
|
||||
_.omit(mergeTx, 'meta'),
|
||||
tx.meta ? {metaData: tx.meta} : {}
|
||||
)
|
||||
return renameMeta
|
||||
})
|
||||
const transactionHash = computeTransactionTreeHash(txs)
|
||||
if (ledger.transactionHash !== undefined
|
||||
&& ledger.transactionHash !== transactionHash) {
|
||||
throw new common.errors.ValidationError('transactionHash in header'
|
||||
+ ' does not match computed hash of transactions', {
|
||||
if (
|
||||
ledger.transactionHash !== undefined &&
|
||||
ledger.transactionHash !== transactionHash
|
||||
) {
|
||||
throw new common.errors.ValidationError(
|
||||
'transactionHash in header' +
|
||||
' does not match computed hash of transactions',
|
||||
{
|
||||
transactionHashInHeader: ledger.transactionHash,
|
||||
computedHashOfTransactions: transactionHash
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
return transactionHash
|
||||
}
|
||||
|
||||
function computeStateHash(ledger,
|
||||
options: ComputeLedgerHeaderHashOptions) {
|
||||
function computeStateHash(ledger, options: ComputeLedgerHeaderHashOptions) {
|
||||
if (ledger.rawState === undefined) {
|
||||
if (options.computeTreeHashes) {
|
||||
throw new common.errors.ValidationError('rawState'
|
||||
+ ' property is missing from the ledger')
|
||||
throw new common.errors.ValidationError(
|
||||
'rawState' + ' property is missing from the ledger'
|
||||
)
|
||||
}
|
||||
return ledger.stateHash
|
||||
}
|
||||
const state = JSON.parse(ledger.rawState)
|
||||
const stateHash = computeStateTreeHash(state)
|
||||
if (ledger.stateHash !== undefined && ledger.stateHash !== stateHash) {
|
||||
throw new common.errors.ValidationError('stateHash in header'
|
||||
+ ' does not match computed hash of state')
|
||||
throw new common.errors.ValidationError(
|
||||
'stateHash in header' + ' does not match computed hash of state'
|
||||
)
|
||||
}
|
||||
return stateHash
|
||||
}
|
||||
@@ -90,8 +110,10 @@ export type ComputeLedgerHeaderHashOptions = {
|
||||
computeTreeHashes?: boolean
|
||||
}
|
||||
|
||||
function computeLedgerHeaderHash(ledger: any,
|
||||
options: ComputeLedgerHeaderHashOptions = {}): string {
|
||||
function computeLedgerHeaderHash(
|
||||
ledger: any,
|
||||
options: ComputeLedgerHeaderHashOptions = {}
|
||||
): string {
|
||||
const subhashes = {
|
||||
transactionHash: computeTransactionHash(ledger, options),
|
||||
stateHash: computeStateHash(ledger, options)
|
||||
|
||||
@@ -3,7 +3,9 @@ import keypairs from 'ripple-keypairs'
|
||||
import binary from 'ripple-binary-codec'
|
||||
const {validate, xrpToDrops} = common
|
||||
|
||||
function signPaymentChannelClaim(channel: string, amount: string,
|
||||
function signPaymentChannelClaim(
|
||||
channel: string,
|
||||
amount: string,
|
||||
privateKey: string
|
||||
): string {
|
||||
validate.signPaymentChannelClaim({channel, amount, privateKey})
|
||||
|
||||
@@ -2,8 +2,11 @@ import keypairs from 'ripple-keypairs'
|
||||
import binary from 'ripple-binary-codec'
|
||||
import {validate, xrpToDrops} from '../common'
|
||||
|
||||
function verifyPaymentChannelClaim(channel: string, amount: string,
|
||||
signature: string, publicKey: string
|
||||
function verifyPaymentChannelClaim(
|
||||
channel: string,
|
||||
amount: string,
|
||||
signature: string,
|
||||
publicKey: string
|
||||
): string {
|
||||
validate.verifyPaymentChannelClaim({channel, amount, signature, publicKey})
|
||||
|
||||
|
||||
@@ -30,10 +30,4 @@ function formatLedgerClose(ledgerClose: any): object {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
connect,
|
||||
disconnect,
|
||||
isConnected,
|
||||
getLedgerVersion,
|
||||
formatLedgerClose
|
||||
}
|
||||
export {connect, disconnect, isConnected, getLedgerVersion, formatLedgerClose}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import {TransactionJSON, prepareTransaction} from './utils'
|
||||
import {prepareTransaction} from './utils'
|
||||
import {validate} from '../common'
|
||||
import {Instructions, Prepare} from './types'
|
||||
import {Instructions, Prepare, TransactionJSON} from './types'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type CheckCancelParameters = {
|
||||
checkID: string
|
||||
}
|
||||
|
||||
function createCheckCancelTransaction(account: string,
|
||||
function createCheckCancelTransaction(
|
||||
account: string,
|
||||
cancel: CheckCancelParameters
|
||||
): TransactionJSON {
|
||||
const txJSON = {
|
||||
@@ -19,15 +20,15 @@ function createCheckCancelTransaction(account: string,
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function prepareCheckCancel(this: RippleAPI, address: string,
|
||||
function prepareCheckCancel(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
checkCancel: CheckCancelParameters,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
validate.prepareCheckCancel(
|
||||
{address, checkCancel, instructions})
|
||||
const txJSON = createCheckCancelTransaction(
|
||||
address, checkCancel)
|
||||
validate.prepareCheckCancel({address, checkCancel, instructions})
|
||||
const txJSON = createCheckCancelTransaction(address, checkCancel)
|
||||
return prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
|
||||
@@ -7,17 +7,20 @@ import {Amount} from '../common/types/objects'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type CheckCashParameters = {
|
||||
checkID: string,
|
||||
amount?: Amount,
|
||||
checkID: string
|
||||
amount?: Amount
|
||||
deliverMin?: Amount
|
||||
}
|
||||
|
||||
function createCheckCashTransaction(account: string,
|
||||
function createCheckCashTransaction(
|
||||
account: string,
|
||||
checkCash: CheckCashParameters
|
||||
): TransactionJSON {
|
||||
if (checkCash.amount && checkCash.deliverMin) {
|
||||
throw new ValidationError('"amount" and "deliverMin" properties on '
|
||||
+ 'CheckCash are mutually exclusive')
|
||||
throw new ValidationError(
|
||||
'"amount" and "deliverMin" properties on ' +
|
||||
'CheckCash are mutually exclusive'
|
||||
)
|
||||
}
|
||||
|
||||
const txJSON: any = {
|
||||
@@ -37,15 +40,15 @@ function createCheckCashTransaction(account: string,
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function prepareCheckCash(this: RippleAPI, address: string,
|
||||
function prepareCheckCash(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
checkCash: CheckCashParameters,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
validate.prepareCheckCash(
|
||||
{address, checkCash, instructions})
|
||||
const txJSON = createCheckCashTransaction(
|
||||
address, checkCash)
|
||||
validate.prepareCheckCash({address, checkCash, instructions})
|
||||
const txJSON = createCheckCashTransaction(address, checkCash)
|
||||
return utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
|
||||
@@ -6,14 +6,15 @@ import {Amount} from '../common/types/objects'
|
||||
import {RippleAPI} from '..'
|
||||
|
||||
export type CheckCreateParameters = {
|
||||
destination: string,
|
||||
sendMax: Amount,
|
||||
destinationTag?: number,
|
||||
expiration?: string,
|
||||
destination: string
|
||||
sendMax: Amount
|
||||
destinationTag?: number
|
||||
expiration?: string
|
||||
invoiceID?: string
|
||||
}
|
||||
|
||||
function createCheckCreateTransaction(account: string,
|
||||
function createCheckCreateTransaction(
|
||||
account: string,
|
||||
check: CheckCreateParameters
|
||||
): TransactionJSON {
|
||||
const txJSON: any = {
|
||||
@@ -38,15 +39,15 @@ function createCheckCreateTransaction(account: string,
|
||||
return txJSON
|
||||
}
|
||||
|
||||
function prepareCheckCreate(this: RippleAPI, address: string,
|
||||
function prepareCheckCreate(
|
||||
this: RippleAPI,
|
||||
address: string,
|
||||
checkCreate: CheckCreateParameters,
|
||||
instructions: Instructions = {}
|
||||
): Promise<Prepare> {
|
||||
try {
|
||||
validate.prepareCheckCreate(
|
||||
{address, checkCreate, instructions})
|
||||
const txJSON = createCheckCreateTransaction(
|
||||
address, checkCreate)
|
||||
validate.prepareCheckCreate({address, checkCreate, instructions})
|
||||
const txJSON = createCheckCreateTransaction(address, checkCreate)
|
||||
return utils.prepareTransaction(txJSON, this, instructions)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user