Compare commits

...

214 Commits
1.1.0 ... 1.6.0

Author SHA1 Message Date
Hans Bergren
3c534d87c0 Release 1.6.0 2020-01-06 16:47:44 -05:00
Elliot Lee
138e7942da Add support for AccountDelete (#1120)
https://xrpl.org/accountdelete.html
2020-01-06 04:01:10 -08:00
dependabot-preview[bot]
23504821cf Bump @typescript-eslint/parser from 2.13.0 to 2.14.0 (#1147)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 2.13.0 to 2.14.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v2.14.0/packages/parser)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-05 19:54:52 -08:00
dependabot-preview[bot]
b09da3e8f1 Bump @types/node from 13.1.1 to 13.1.2 (#1148)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 13.1.1 to 13.1.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-05 19:54:37 -08:00
Elliot Lee
f3dd2fec99 Merge pull request #1098 from nickewansmith/fix-possible-unhandled-throw-on-send
Adds unit test for ripple#1092, fixes unhandled throw on upgraded ws send
2020-01-05 19:51:58 -08:00
Elliot Lee
462e375800 Add ripple-latest.js to npm 2019-12-28 11:51:00 -08:00
Elliot Lee
ca8c881375 Release 1.5.1 2019-12-28 11:47:57 -08:00
Elliot Lee
96605a57d4 Fix CDNs (#1142)
* Rename browser build output file to ripple-latest-min.js (the name prior to #1061)
* Add unpkg and jsdelivr
2019-12-28 11:46:52 -08:00
FKSRipple
491ce40081 Merge pull request #1136 from ripple/dependabot/npm_and_yarn/typescript-eslint/eslint-plugin-2.13.0
Bump @typescript-eslint/eslint-plugin from 2.5.0 to 2.13.0
2019-12-27 12:46:00 -08:00
FKSRipple
f33eb07bdd Merge pull request #1135 from ripple/dependabot/npm_and_yarn/https-proxy-agent-4.0.0
Bump https-proxy-agent from 3.0.1 to 4.0.0
2019-12-27 10:16:58 -08:00
dependabot-preview[bot]
8bb1dc9b47 Bump @typescript-eslint/eslint-plugin from 2.5.0 to 2.13.0
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 2.5.0 to 2.13.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v2.13.0/packages/eslint-plugin)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-27 18:03:54 +00:00
FKSRipple
78b50472da Merge pull request #1137 from ripple/dependabot/npm_and_yarn/types/node-13.1.1
Bump @types/node from 12.12.5 to 13.1.1
2019-12-27 10:02:11 -08:00
FKSRipple
e0259b37ed Merge pull request #1138 from ripple/dependabot/npm_and_yarn/eventemitter2-6.0.0
Bump eventemitter2 from 5.0.1 to 6.0.0
2019-12-27 10:01:27 -08:00
FKSRipple
bf863a2594 Merge pull request #1139 from ripple/dependabot/npm_and_yarn/typescript-eslint/parser-2.13.0
Bump @typescript-eslint/parser from 2.5.0 to 2.13.0
2019-12-27 10:01:10 -08:00
FKSRipple
edd174881e Merge pull request #1134 from ripple/dependabot/npm_and_yarn/types/lodash-4.14.149
Bump @types/lodash from 4.14.144 to 4.14.149
2019-12-27 09:57:50 -08:00
dependabot-preview[bot]
0bf747f6fc Bump @typescript-eslint/parser from 2.5.0 to 2.13.0
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 2.5.0 to 2.13.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v2.13.0/packages/parser)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-27 13:40:22 +00:00
dependabot-preview[bot]
ab4d2b5d58 Bump eventemitter2 from 5.0.1 to 6.0.0
Bumps [eventemitter2](https://github.com/hij1nx/EventEmitter2) from 5.0.1 to 6.0.0.
- [Release notes](https://github.com/hij1nx/EventEmitter2/releases)
- [Changelog](https://github.com/EventEmitter2/EventEmitter2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hij1nx/EventEmitter2/commits/v6.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-27 13:39:54 +00:00
dependabot-preview[bot]
1b81280358 Bump mocha from 6.2.0 to 6.2.2 (#1126)
Bumps [mocha](https://github.com/mochajs/mocha) from 6.2.0 to 6.2.2.
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v6.2.0...v6.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-26 12:49:31 -08:00
dependabot-preview[bot]
32f4eea3b8 Bump @types/node from 12.12.5 to 13.1.1
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 12.12.5 to 13.1.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-26 20:21:14 +00:00
dependabot-preview[bot]
1a3a49decb Bump @types/ws from 6.0.3 to 6.0.4 (#1125)
Bumps [@types/ws](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ws) from 6.0.3 to 6.0.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ws)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-26 12:19:32 -08:00
dependabot-preview[bot]
416717aff6 Bump https-proxy-agent from 3.0.1 to 4.0.0
Bumps [https-proxy-agent](https://github.com/TooTallNate/node-https-proxy-agent) from 3.0.1 to 4.0.0.
- [Release notes](https://github.com/TooTallNate/node-https-proxy-agent/releases)
- [Commits](https://github.com/TooTallNate/node-https-proxy-agent/compare/3.0.1...4.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-24 13:53:06 +00:00
dependabot-preview[bot]
769d955a40 Bump @types/lodash from 4.14.144 to 4.14.149
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.14.144 to 4.14.149.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-24 13:52:42 +00:00
dependabot-preview[bot]
6de85b841d Bump ts-node from 8.4.1 to 8.5.4 (#1124)
Bumps [ts-node](https://github.com/TypeStrong/ts-node) from 8.4.1 to 8.5.4.
- [Release notes](https://github.com/TypeStrong/ts-node/releases)
- [Commits](https://github.com/TypeStrong/ts-node/compare/v8.4.1...v8.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-23 11:40:59 -08:00
dependabot-preview[bot]
b4c6af29e4 Bump webpack from 4.41.2 to 4.41.4 (#1123)
Bumps [webpack](https://github.com/webpack/webpack) from 4.41.2 to 4.41.4.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v4.41.2...v4.41.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-22 15:53:29 -08:00
dependabot-preview[bot]
7192606e21 Bump webpack-cli from 3.3.9 to 3.3.10 (#1122)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 3.3.9 to 3.3.10.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/v3.3.10/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/v3.3.9...v3.3.10)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-22 15:52:01 -08:00
FKSRipple
f5196389e8 Merge pull request #1116 from ripple/prettier-format
run prettier format
2019-12-18 11:25:14 -08:00
FKSRipple
27be06c5c9 Merge pull request #1118 from ripple/eslint-fix
Fix incorrect eslint matching glob
2019-12-18 11:24:52 -08:00
Fred K. Schott
1d3ddb5e85 update eslint command 2019-12-17 10:36:32 -08:00
Fred K. Schott
2145c104fd run prettier format 2019-12-17 10:35:59 -08:00
FKSRipple
64e0d098e7 Merge pull request #1115 from ripple/connection-cleanup-config
Cleanup the connection config state
2019-12-17 10:31:04 -08:00
FKSRipple
50d8cbb0ee Merge pull request #1114 from ripple/connection-cleanup-trace
Cleanup the connection trace logic
2019-12-17 08:58:44 -08:00
Fred K. Schott
9580397558 cleanup the connection config 2019-12-16 17:26:00 -08:00
Fred K. Schott
cf544b74f5 fix msg abbreviation 2019-12-16 17:25:21 -08:00
Fred K. Schott
312f831efb cleanup the connection trace logic 2019-12-16 11:57:51 -08:00
Elliot Lee
f5bad5d28e Release 1.5.0 2019-12-14 22:45:12 -08:00
Elliot Lee
9b7d255200 Update webpack (#1112) 2019-12-14 10:24:32 -08:00
Elliot Lee
7a027bdd93 Update README (#1111) 2019-12-14 10:24:05 -08:00
FKSRipple
439a611a9e Add a heartbeat to detect hung connections (#1101)
* disconnect is now reconnect on heartbeat fail
2019-12-14 10:23:09 -08:00
RareData
5f92b230aa Add support for WalletLocator (#1083)
Being able to fetch the WalletLocator field opens up new use-cases. The field can store for example a transaction hash, referencing a transaction with memos containing useful data.
2019-12-11 23:47:41 -08:00
Elliot Lee
29bc5303ae Fix tests (#1109)
* Revert "[docs] Update getTransactions example request/response (#1106)"

This reverts commit 5314e5e7e9.

* Redo #1106 but with passing tests
2019-12-11 22:54:33 -08:00
Elliot Lee
5314e5e7e9 [docs] Update getTransactions example request/response (#1106) 2019-12-11 14:45:04 -08:00
Elliot Lee
c88462c99b [package.json] Require node 8 and yarn (#1107) 2019-12-11 14:43:04 -08:00
Elliot Lee
0b552f1a7e Update yarn.lock
ripple-lib-transactionparser@0.8.1
2019-12-10 11:36:34 -08:00
FKSRipple
552635a3c7 Merge pull request #1104 from ripple/all-tests
Migrate RippleAPI tests to new test runner
2019-12-09 11:00:34 -08:00
FKSRipple
ca769bee39 Merge pull request #1103 from ripple/test-runner-02
Make improvements to test runner
2019-12-09 11:00:06 -08:00
Elliot Lee
b7ca0a0a14 Merge pull request #1102 from ripple/test-runner-01
Small source fixes, based on issues found with test improvements
2019-12-09 09:16:58 -08:00
Fred K. Schott
84097a3179 move the remaining RippleAPI tests to the new test runner 2019-11-26 16:52:21 -08:00
Fred K. Schott
8ba36b2588 fix bad path 2019-11-26 16:52:05 -08:00
Fred K. Schott
e1d4ebc5f6 add docs 2019-11-26 16:50:12 -08:00
Fred K. Schott
9e712d6089 fix old ref 2019-11-26 16:44:11 -08:00
Fred K. Schott
90bea3dc6b fix old utils ref 2019-11-26 16:41:16 -08:00
Fred K. Schott
bf480bb971 remove outdated test utils 2019-11-26 16:37:56 -08:00
Fred K. Schott
a94b48be50 improve the test runner 2019-11-26 16:34:17 -08:00
Fred K. Schott
abed42d848 fix source directory, based on issues found with test improvements 2019-11-26 16:01:03 -08:00
FKSRipple
3d6e795ca5 Merge pull request #1096 from magmel48/typescript3.7-TransactionJSON-conflict-fix
TransactionJSON conflict fix
2019-11-19 15:04:10 -08:00
magmel
a3cbe8e9d4 back to ts3.6.4 2019-11-18 15:39:45 +03:00
FKSRipple
0a2000098a Merge pull request #1097 from r0bertz/develop
Bump ripple-lib-transactionparser to 0.8.1
2019-11-18 00:02:11 -08:00
FKSRipple
a2348b5133 revert package version change 2019-11-18 00:01:18 -08:00
FKSRipple
20d2f9d894 Merge pull request #1086 from ripple/refactor-tests
Add RippleAPI test runner, with support for multiple address testing
2019-11-17 23:49:22 -08:00
FKSRipple
321f908e76 Merge pull request #1084 from ripple/tests-to-ts-04
Complete move of tests to TS
2019-11-17 23:42:38 -08:00
FKSRipple
49875cb0e5 Update api-test.ts 2019-11-17 23:42:21 -08:00
Nicholas Smith
fa6a2c5bbb Adds unit test for ripple#1092, fixes unhandled throw when not connected on send due to upgraded ws module 2019-11-17 01:28:19 -05:00
Le Zhang
1074c00b60 Bump ripple-lib-transactionparser to 0.8.1 2019-11-16 01:05:48 -08:00
magmel
8a8b10541e yarn.lock 2019-11-15 15:47:14 +03:00
magmel
46cf4d677c typescript ^ in package.json 2019-11-15 15:46:11 +03:00
magmel
94587d7515 moved TransactionJSON to proper types.ts file 2019-11-15 15:44:31 +03:00
Elliot Lee
14ec58ef9a Fix link 2019-11-14 21:00:33 -08:00
Elliot Lee
8f4f6f3de0 Release 1.4.2 2019-11-14 20:50:29 -08:00
Elliot Lee
f8c0ac3ce0 Update docs
* Add tickSize parameter
* Fix formatting
2019-11-14 20:38:40 -08:00
RareData
8ebad98912 Add support for tick size (#1090) 2019-11-14 20:13:58 -08:00
FKSRipple
08429b6110 Merge pull request #1092 from nickewansmith/fix-unhandled-rejection-warning-on-send
Fix Unhandled Promise Rejection Warning on message _send
2019-11-13 19:54:48 -08:00
FKSRipple
0e128e15f1 Merge pull request #1089 from RareData/patch-2
Update email hash default to allow proper clearing
2019-11-13 19:51:53 -08:00
Fred K. Schott
b77a12fd0d Add test runner for RippleAPI, begin to break up large test file 2019-11-13 19:47:49 -08:00
Fred K. Schott
a98526b398 Revert "Revert "Merge pull request #1052 from FredKSchott/tests-to-ts-03""
This reverts commit b648387a57.
2019-11-13 19:47:18 -08:00
Fred K. Schott
5639bf9d48 merge xaddress tests into main test file 2019-11-13 19:47:18 -08:00
Fred K. Schott
c626685103 start running test/x-address-api-test.ts 2019-11-13 19:47:18 -08:00
FKSRipple
e233d15fbb Merge pull request #1087 from ripple/prettier
Add a prettier config
2019-11-13 09:51:45 -08:00
Fred K. Schott
a5d83900d9 set trailing trailingComma to none 2019-11-13 09:50:13 -08:00
Nicholas Smith
d8dbeedcc2 Adds an immediate catch to the _send promise passed to _whenReady in case there is rejection before async handlers are added 2019-11-13 01:24:09 -05:00
FKSRipple
56b67d62a3 Update Node.js Testing Versions (#1085)
Updated our testing matrix based on: https://nodejs.org/en/about/releases/

- Node 11 is no longer supported (not LTS)
- Node 12 added (active LTS)
- Node 13 added ("current" release)
2019-11-11 13:56:22 -08:00
RareData
dc084b4bd9 Add XRP Toolkit reference (#1088) 2019-11-11 13:54:27 -08:00
RareData
1bc0eab7ae Update email hash default to fix clearing bug 2019-11-11 19:09:32 +01:00
Fred K. Schott
ca14d1b108 add a prettier config 2019-11-10 13:56:42 -08:00
Elliot Lee
d6757aced2 Release 1.4.1 (#1079) 2019-11-06 21:30:14 -08:00
Keefer Taylor
5c84eed292 Fix Travis Build (#1076)
* Drop support for node 6

* Add build badge

* Remove `compile` command, no longer used
2019-11-06 16:44:57 -08:00
Elliot Lee
b648387a57 Revert "Merge pull request #1052 from FredKSchott/tests-to-ts-03"
This reverts commit e08367365f, reversing
changes made to 36a9e7a7cf.
2019-11-06 10:34:05 -08:00
Tyler Levine
5232f95c3f Change TypeScript compile target to es6 (#1071)
This allows for the use of Node 6. Note that Node v6 is no longer supported by Node.js (End-of-life'd in April 2019). We recommend updating to Node v8/v10 ASAP, to keep getting security updates and fixes from the Node.js team.
2019-11-05 09:05:47 -08:00
FKSRipple
0742960ec4 Merge pull request #1061 from ripple/webpack-update
Update Webpack
2019-11-05 08:13:44 -08:00
Fred K. Schott
4c41b7f8df revert name change 2019-11-05 08:13:27 -08:00
Fred K. Schott
c5d0c24237 update webpack flow 2019-11-04 21:33:39 -08:00
FKSRipple
8b5c51ceaa Merge pull request #1073 from ripple/update-ws
update ws dependency
2019-11-04 19:38:05 -08:00
Fred K. Schott
c09bceb66a fix type 2019-11-04 19:36:34 -08:00
Fred K. Schott
e7afd3ec76 respond to comments 2019-11-04 19:33:43 -08:00
Fred K. Schott
3d30be3472 update ws dependency 2019-11-04 19:33:43 -08:00
FKSRipple
e08367365f Merge pull request #1052 from FredKSchott/tests-to-ts-03
Convert the rest of the test helpers to TS
2019-11-04 19:30:02 -08:00
Fred K. Schott
6692fbeed4 respond to comments 2019-11-04 19:20:40 -08:00
FKSRipple
36a9e7a7cf Merge pull request #1074 from ripple/update-bignumber
update bignumber dependency
2019-11-04 18:59:43 -08:00
FKSRipple
49b5ff5fd9 Merge pull request #1075 from ripple/update-keypairs
update ripple-keypairs
2019-11-04 18:58:16 -08:00
Fred K. Schott
1bde56a11a update ripple-keypairs 2019-11-02 08:54:46 -07:00
Fred K. Schott
f47d7b6935 update bignumber dependency 2019-11-02 08:36:46 -07:00
Fred K. Schott
2dbad40a34 update assert-diff 2019-11-02 07:51:39 -07:00
Fred K. Schott
39f6a51794 convert the rest of the helper files to ts 2019-11-02 07:40:52 -07:00
Fred K. Schott
7ec128c2e4 move tests to TypeScript 2019-11-02 07:40:52 -07:00
FKSRipple
b55f0e849e Merge pull request #1069 from mDuo13/getAccountObjects_doc
getAccountObjects doc fix
2019-11-02 06:54:13 -07:00
mDuo13
f158390ba1 getAccountObjects doc fix
Add necessary blank line for the list to render properly. (xrpl.org's
Markdown parser won't recognize the list without it.)
2019-10-29 14:23:10 -07:00
Elliot Lee
e4b245104a Release 1.4.0 2019-10-28 17:10:03 -07:00
Elliot Lee
789497b07e Fix lint errors 2019-10-28 17:01:32 -07:00
FKSRipple
5cf01ba099 Merge pull request #1051 from FredKSchott/tests-to-ts-02
Move tests to TypeScript
2019-10-28 10:54:39 -07:00
Fred K. Schott
e8669891f8 small typo fixes 2019-10-28 10:54:06 -07:00
Fred K. Schott
ac0f265a5b move tests to TypeScript 2019-10-28 10:53:36 -07:00
Elliot Lee
fcd6b430e1 Reduce dependency size (#1057)
- Remove .npmignore since it is overridden by package.json 'files'
- Include build/ripple-latest-min.js, not everything in build/
2019-10-25 13:57:45 -07:00
Elliot Lee
f3ad8a9b80 Merge pull request #1060 from fix-test
Fix broken tests
2019-10-25 13:56:43 -07:00
Fred K. Schott
43ff824da1 fix broken tests 2019-10-25 10:18:46 -07:00
Fairy
b8022610ca Fix error in Safari (#869)
* Safari minify fix

* Update browser-hacks.ts
2019-10-24 10:41:21 -07:00
FKSRipple
03defe203a Merge pull request #773 from aMoniker/develop
unref timer so it doesnt hang the node process
2019-10-23 18:29:20 -07:00
FKSRipple
aedcbe56b3 Added small style changes 2019-10-23 18:29:07 -07:00
FKSRipple
c365db460a Merge pull request #1044 from ripple/connection-timeout
Add a 2-second timeout for connect()
2019-10-23 18:19:39 -07:00
Elliot Lee
cfdc4752d0 let -> const and reject with error 2019-10-23 12:25:02 -07:00
Elliot Lee
e1964ac5ed Add support for the X-address format (#1041)
* Update schema-validator

* Update to ripple-address-codec 4.0.0

* Update ./src/common/hashes/index.ts

* Add generateXAddress method

* Deprecate generateAddress method

* Add unit tests

* Add documentation
2019-10-23 12:03:59 -07:00
James Greenleaf
e17ab9cd8f Add conditional to timer.unref 2019-10-23 14:44:20 -04:00
James Greenleaf
edc15b8727 Merge remote-tracking branch 'upstream/develop' into develop 2019-10-23 14:42:05 -04:00
Fred K. Schott
034f8d41fc remove bad semicolon 2019-10-23 00:33:09 -07:00
Fred K. Schott
0fa70db1e1 Merge branch 'develop' into connection-timeout 2019-10-23 00:32:03 -07:00
FKSRipple
fa7ba9b72b Update connection.ts 2019-10-23 00:27:17 -07:00
FKSRipple
3a20123e0f Merge pull request #1046 from ripple/improve-tx-not-found
Improve getTransaction() error when tx has not been validated yet
2019-10-23 00:22:07 -07:00
FKSRipple
03510d1bc4 Update index.ts 2019-10-23 00:21:35 -07:00
Elliot Lee
8b116f637a Update yarn.lock 2019-10-22 00:57:26 -07:00
Elliot Lee
9c49de6552 Merge pull request #1054 from tylerlevine/update-https-proxy-agent
Update https-proxy-agent to 3.0.0
2019-10-22 00:56:33 -07:00
Elliot Lee
842347bcab Merge branch 'develop' into update-https-proxy-agent 2019-10-22 00:56:07 -07:00
Elliot Lee
628b9c4853 Merge pull request #1049 from FredKSchott/eslint
Replace tslint (since deprecated) with eslint
2019-10-21 11:01:53 -07:00
Fred K. Schott
d60b6ee33f Merge remote-tracking branch 'myfork/eslint' into eslint 2019-10-21 10:03:27 -07:00
Fred K. Schott
4f4fcbbc70 add tests to linting 2019-10-21 10:02:14 -07:00
Tyler Levine
cc896670dc Update https-proxy-agent to 3.0.0 2019-10-18 16:16:54 -07:00
Elliot Lee
eb2a497dee Release 1.3.4 2019-10-18 14:41:58 -07:00
Fred K. Schott
0cf5ce1416 Merge branch 'develop' into eslint 2019-10-17 11:23:26 -07:00
Elliot Lee
988381d584 Merge pull request #1048 from FredKSchott/tsc-update
Update TypeScript
2019-10-16 23:04:20 -07:00
Elliot Lee
0b163eae23 XRP Ledger Hashes: create README.md 2019-10-15 16:34:48 -07:00
Fred K. Schott
3a3ff8a65e Update utils.ts 2019-10-15 13:49:03 -07:00
Fred K. Schott
9f183a6dfc replace tslint (deprecated) with eslint 2019-10-13 16:44:22 -07:00
Fred K. Schott
fadfd4e06c update typescript 2019-10-13 16:19:45 -07:00
Sohail Salehi
eb521faa8d Doc update for sign() method (#1010)
* Add multi-signing example to the sign() method

Explains why the `signAs` option is compulsory for multi-signing scenarios.
2019-10-08 11:59:12 -07:00
Elliot Lee
6b572ca862 Improve getTransaction() error when tx has not been validated yet 2019-10-04 23:56:09 -07:00
Elliot Lee
d075ec6716 Add a 2-second timeout for connect() 2019-10-03 00:02:55 -07:00
Tyler Storm
14e6bf5ef9 Integrate ripple-hashes (#1039)
* Update TxParser and Mocha

* Convert ripple-hashes to TypeScript and add into ripple-lib along with unit tests

* Switch casing to camelCase

* Document intToVuc

* Convert Slots to numbers, add exception if number is outside 0-15

* Remove Shamap v2 support

* Improve naming
2019-10-01 23:35:11 -07:00
Elliot Lee
b6bddd3b0e [MINOR] Remove unnecessary semicolon 2019-09-26 03:18:54 -07:00
Elliot Lee
d5ed9b6cf5 Improve error message when signing fails
When there are multiple representations of the same value
(for example, trailing zeros) the verification will fail.

This points users to the error.data object for details about
the failure, and adds a diff so that the cause of the
discrepancy can be seen at a glance.
2019-09-24 09:58:24 -07:00
Tyler Storm
7a9912d4e0 Update TxParser and Mocha 2019-09-24 09:57:56 -07:00
Mo Morsi
4d2ddceb4e Change "wipple" to "xrp1ntel" (#1036)
The Wipple Analytics Engine is now accessed through the xrp1ntel website
2019-09-12 13:15:26 -07:00
Elliot Lee
ae2aed675a v1.3.3 2019-09-10 19:30:11 -07:00
Elliot Lee
1d7cb41218 Add rippleTimeToISO8601.md.ejs 2019-09-04 00:31:02 -07:00
Elliot Lee
76db002eb5 Expand node version compatibility
Previously the library could not be installed with node 12:

https://github.com/ripple/ripple-binary-codec/pull/33
2019-09-04 00:17:53 -07:00
Elliot Lee
ebb64ba177 v1.3.2 2019-09-03 16:43:31 -07:00
Elliot Lee
1a685e2b68 Fix #1032 (#1033)
* Update ripple-address-codec@latest

* Export and document rippleTimeToISO8601
2019-09-03 16:38:56 -07:00
Rome Reginelli
9c561885a1 Docs: update recommended Node ver. (#1031) 2019-08-29 20:34:25 -07:00
Elliot Lee
612e98b198 Release 1.3.1 2019-08-26 13:58:09 -07:00
Elliot Lee
0a41d5ccf1 Upgrade to gulp 4; remove http server (#1030)
* Update gulp version to ^4.0.2 and Gulpfile.js

* Remove http server
2019-08-26 13:50:36 -07:00
Elliot Lee
ba8fe1f32c Update HISTORY - rippled 1.3.1 2019-08-16 21:28:32 -07:00
Elliot Lee
0f840876a5 Update HISTORY 2019-08-16 21:11:02 -07:00
Elliot Lee
ac3900b6f4 Release 1.2.5 and 1.3.0 2019-08-16 21:09:08 -07:00
Elliot Lee
5e138b9937 Sign method - verify accurate encoding (#1026)
* Decode signed transactions and check field integrity

* Add tests (including signing a tx without Flags)

* Update tests to output more descriptive errors on failure

* Update ripple-binary-codec to 0.2.2
2019-08-16 16:22:25 -07:00
Elliot Lee
82d50cd903 Document setCanonicalFlag and export from src/transaction/utils 2019-08-09 10:16:33 -07:00
Elliot Lee
c5b1d4daac Update lodash to ^4.14.136, fix docs typo, update HISTORY.md 2019-08-07 12:20:56 -07:00
Namrata
b4a30d49d8 Support removing a signer list (#1021)
* Make weights an optional field
* Fix #971
2019-07-30 16:48:30 -07:00
Elliot Lee
229360d1b9 README - Update link 2019-07-18 21:50:58 -07:00
Rome Reginelli
d627d362af Merge pull request #1023 from mDuo13/doc_cleanup
Phrasing cleanup in schema descriptions
2019-07-16 15:11:01 -07:00
mDuo13
7ca7a07942 Phrasing cleanup in schema descriptions
- Change 'Ripple address'→'XRP Ledger address'
- Change 'is exclusive with'→'cannot be used with'
2019-07-15 14:26:43 -07:00
dependabot[bot]
09f81fa3cd Bump lodash from 4.17.11 to 4.17.13
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.13.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.13)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-13 13:26:48 -07:00
The XRP Scan Project
b03bf9c7f1 Updated APPLICATIONS.md and added xrpscan
Added xrpscan.com under Data and Visualization section.
2019-06-24 02:03:21 -07:00
Elliot Lee
4d696369fe APIOptions: extend ConnectionOptions (#1018)
Fix #1017
2019-06-21 01:45:47 -07:00
Elliot Lee
bcb80ea5f5 Fix getServerInfo (#1012)
* Return array for serverInfo.load.jobTypes

* Include start/end in invalid range assertion error
2019-06-14 14:57:36 -07:00
Elliot Lee
1be2ee5875 Docs: fix #574 (#1011)
destination.address
2019-06-14 14:57:14 -07:00
Elliot Lee
3554e807df Release 1.2.4 2019-06-06 16:01:24 -07:00
Elliot Lee
5ffbd6e86d Update dependencies (#1007)
* Update dependencies: @types/lodash@4.14.133, mocha-junit-reporter@1.22.0, tslint@5.17.0, nyc

Fix type errors
2019-06-06 15:56:29 -07:00
Elliot Lee
e2572c61cf Add details about transaction fees, master keys, and multi-signing 2019-06-05 00:27:25 -07:00
Elliot Lee
7df2b74d43 Update get-server-info.json 2019-05-27 14:37:38 -07:00
Elliot Lee
f51a69f080 Fix typo 2019-05-22 10:04:43 -07:00
Elliot Lee
c0a2d9fc2b Update README.md 2019-05-16 22:51:22 -07:00
Elliot Lee
51dad19f88 Release 1.2.3 2019-04-30 15:01:54 -07:00
Elliot Lee
3d1a530796 Fix browser builds (#1006)
tsconfig:
- Must set composite: false
- Must set declarationMap: false in order to use declaration: false

json-loader:
- Not needed with webpack >= v2.0.0 and in fact does not work

https-proxy-agent cannot be used in the browser
2019-04-29 23:19:05 -07:00
Elliot Lee
f6a22d2121 No working browser version for 1.2.2
Using `"noEmitOnError": true` in `tsconfig.json` prevents the browser build from being created
2019-04-18 00:53:28 -07:00
Elliot Lee
6f2d448059 Release 1.2.2 2019-04-15 12:30:20 -07:00
Elliot Lee
0d5103a3f3 Use TypeScript project reference (#1002)
* Add *.tsbuildinfo to .gitignore

* Bump versions of dependencies, nyc and yargs

* Drop support for node 9 (EOL 2018-06-30)

https://github.com/nodejs/Release

* Add getTransaction snippet
2019-04-15 11:06:31 -07:00
Elliot Lee
4da80028bf Prevent prepareTransaction from overwriting values in txJSON (#1000)
Fix #997
2019-04-13 11:33:16 -07:00
Daniel Chan
bb40dbde9d Add deliveredAmount as optional field for type Outcome (#996) 2019-04-11 17:13:42 -07:00
Elliot Lee
50fc36ec3e Add "strict": true to tsconfig.json (#994)
- Remove process.browser
2019-04-11 15:48:23 -07:00
Elliot Lee
1abcef73a0 Merge pull request #993 from adrianhopebailie/patch-1
fix: build fails with strict checks
2019-04-08 13:04:27 -07:00
Adrian Hope-Bailie
0d7879b25c fix: build fails with strict checks 2019-03-29 11:48:13 +02:00
Elliot Lee
8278dc5b5b Release 1.2.1 2019-03-23 15:50:26 -07:00
Elliot Lee
c90d486454 Update ripple-binary-codec to 0.2.1 to support tecKILLED 2019-03-23 15:12:22 -07:00
Elliot Lee
35f9b7ec8d Release 1.2.0 2019-03-19 01:28:42 -07:00
Elliot Lee
69e621af86 Remove coveralls from devDependencies 2019-03-19 01:21:36 -07:00
Elliot Lee
0e92e696d4 Remove unused http-server from devDependencies 2019-03-18 16:51:08 -07:00
Elliot Lee
0b1445bfe9 Remove sauce runner 2019-03-18 16:14:21 -07:00
Elliot Lee
db2d7ba1f5 Update mocha to 6.0.2 2019-03-18 16:09:26 -07:00
Elliot Lee
d82703f41b prepareTransaction should not overwrite Sequence (#990)
* Cleans up some code and fixes some type errors

* Clarify how null settings work

* Document updated RippledError

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

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

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

26
.eslintrc.json Normal file
View File

@@ -0,0 +1,26 @@
{
"env": {
"browser": true,
"es6": true,
"node": true,
"mocha": true
},
"extends": [
"eslint:recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"no-useless-constructor": 0,
"no-unused-vars": 0,
"no-prototype-builtins": 0,
"require-atomic-updates": 0,
"no-dupe-class-members": 0
}
}

7
.gitignore vendored
View File

@@ -1,5 +1,9 @@
# .gitignore
# Ignore package locks other than Yarn.
package-lock.json
npm-shrinkwrap.json
# Ignore vim swap files.
*.swp
@@ -54,6 +58,9 @@ npm-debug.log
# Ignore dist folder, built from tsc
dist/
# TypeScript incremental compilation cache
*.tsbuildinfo
# Ignore perf test cache
scripts/cache

View File

@@ -1,4 +0,0 @@
lib-cov
coverage.html
src
dist/bower

10
.prettierrc Normal file
View File

@@ -0,0 +1,10 @@
{
"parser": "typescript",
"printWidth": 80,
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"quoteProps": "consistent",
"bracketSpacing": false
}

View File

@@ -1,11 +1,10 @@
language: node_js
node_js:
- 6
- 8
- 9
- 10
- 12
- 13
script:
- yarn compile
- yarn test
- yarn build
- yarn lint

127
APPLICATIONS.md Normal file
View File

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

View File

@@ -1,216 +0,0 @@
/* eslint-disable no-var, no-param-reassign */
/* these eslint rules are disabled because gulp does not support babel yet */
'use strict';
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const gulp = require('gulp');
const rename = require('gulp-rename');
const webpack = require('webpack');
const bump = require('gulp-bump');
const argv = require('yargs').argv;
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
var pkg = require('./package.json');
var uglifyOptions = {
mangle: {
reserved: ['_', 'RippleError', 'RippledError', 'UnexpectedError',
'LedgerVersionError', 'ConnectionError', 'NotConnectedError',
'DisconnectedError', 'TimeoutError', 'ResponseFormatError',
'ValidationError', 'NotFoundError', 'MissingLedgerHistoryError',
'PendingLedgerVersionError'
]
}
};
function getWebpackConfig(extension, overrides) {
overrides = overrides || {};
let defaults = {
cache: true,
externals: [{
'lodash': '_'
}],
entry: './src/index.ts',
output: {
library: 'ripple',
path: path.join(__dirname, 'build/'),
filename: ['ripple-', extension].join(pkg.version)
},
plugins: [
new webpack.NormalModuleReplacementPlugin(/^ws$/, './wswrapper'),
new webpack.NormalModuleReplacementPlugin(/^\.\/wallet$/, './wallet-web'),
new webpack.NormalModuleReplacementPlugin(/^.*setup-api$/,
'./setup-api-web')
],
module: {
rules: [{
test: /jayson/,
use: 'null',
}, {
test: /\.ts$/,
use: [{
loader: 'ts-loader',
options: {
compilerOptions: {declaration: false}
},
}],
}, {
test: /\.json/,
use: 'json-loader',
}]
},
resolve: {
extensions: [ '.ts', '.js' ]
},
};
return _.assign({}, defaults, overrides);
}
function webpackConfigForWebTest(testFileName, path) {
var match = testFileName.match(/\/?([^\/]*)-test.js$/);
if (!match) {
assert(false, 'wrong filename:' + testFileName);
}
var configOverrides = {
externals: [{
'lodash': '_',
'ripple-api': 'ripple',
'net': 'null'
}],
entry: testFileName,
output: {
library: match[1].replace(/-/g, '_'),
path: './test-compiled-for-web/' + (path ? path : ''),
filename: match[1] + '-test.js'
}
};
return getWebpackConfig('.js', configOverrides);
}
gulp.task('build-tests', function(callback) {
var times = 0;
function done() {
if (++times >= 5) {
callback();
}
}
webpack(webpackConfigForWebTest('./test/rangeset-test.js'), done);
webpack(webpackConfigForWebTest('./test/connection-test.js'), done);
webpack(webpackConfigForWebTest('./test/api-test.js'), done);
webpack(webpackConfigForWebTest('./test/broadcast-api-test.js'), done);
webpack(webpackConfigForWebTest('./test/integration/integration-test.js',
'integration/'), done);
});
function createLink(from, to) {
if (fs.existsSync(to)) {
fs.unlinkSync(to);
}
fs.linkSync(from, to);
}
function createBuildLink(callback) {
return function(err, res) {
createLink('./build/ripple-' + pkg.version + '.js',
'./build/ripple-latest.js');
callback(err, res);
};
}
gulp.task('build', function(callback) {
webpack(getWebpackConfig('.js'), createBuildLink(callback));
});
gulp.task('build-min', function(callback) {
const webpackConfig = getWebpackConfig('-min.js');
webpackConfig.plugins.push(new UglifyJsPlugin({uglifyOptions}));
webpack(webpackConfig, function() {
createLink('./build/ripple-' + pkg.version + '-min.js',
'./build/ripple-latest-min.js');
callback();
});
});
gulp.task('build-debug', function(callback) {
const webpackConfig = getWebpackConfig('-debug.js', {devtool: 'eval'});
webpackConfig.plugins.unshift(new webpack.LoaderOptionsPlugin({debug: true}));
webpack(webpackConfig, callback);
});
/**
* Generate a WebPack external for a given unavailable module which replaces
* that module's constructor with an error-thrower
*/
function buildUseError(cons) {
return ('var {<CONS>:function(){throw new Error('
+ '"Class is unavailable in this build: <CONS>")}}')
.replace(new RegExp('<CONS>', 'g'), cons);
}
gulp.task('build-core', function(callback) {
var configOverrides = {
cache: false,
entry: './src/remote.ts',
externals: [{
'./transaction': buildUseError('Transaction'),
'./orderbook': buildUseError('OrderBook'),
'./account': buildUseError('Account'),
'./serializedobject': buildUseError('SerializedObject')
}],
plugins: [
new UglifyJsPlugin()
]
};
webpack(getWebpackConfig('-core.js', configOverrides), callback);
});
gulp.task('bower-build', ['build'], function() {
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
.pipe(rename('ripple.js'))
.pipe(gulp.dest('./dist/bower'));
});
gulp.task('bower-build-min', ['build-min'], function() {
return gulp.src(['./build/ripple-', '-min.js'].join(pkg.version))
.pipe(rename('ripple-min.js'))
.pipe(gulp.dest('./dist/bower'));
});
gulp.task('bower-build-debug', ['build-debug'], function() {
return gulp.src(['./build/ripple-', '-debug.js'].join(pkg.version))
.pipe(rename('ripple-debug.js'))
.pipe(gulp.dest('./dist/bower'));
});
gulp.task('bower-version', function() {
gulp.src('./dist/bower/bower.json')
.pipe(bump({version: pkg.version}))
.pipe(gulp.dest('./dist/bower'));
});
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug',
'bower-version']);
gulp.task('watch', function() {
gulp.watch('src/*', ['build-debug']);
});
gulp.task('version-bump', function() {
if (!argv.type) {
throw new Error('No type found, pass it in using the --type argument');
}
gulp.src('./package.json')
.pipe(bump({type: argv.type}))
.pipe(gulp.dest('./'));
});
gulp.task('version-beta', function() {
gulp.src('./package.json')
.pipe(bump({version: pkg.version + '-beta'}))
.pipe(gulp.dest('./'));
});
gulp.task('default', ['build', 'build-debug', 'build-min']);

View File

@@ -1,5 +1,425 @@
# 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)
* Update email hash default to allow proper clearing (#1089) (thanks @RareData)
* Fix Unhandled Promise Rejection Warning on message `_send`
* Add an immediate catch to the `_send` promise passed to `_whenReady` in case there is rejection before async handlers are added (#1092) (thanks @nickewansmith)
* Docs improvements
* Add XRP Toolkit reference (#1088)
* Internal improvements
* Add a prettier config
* Update Node.js Testing Versions (#1085)
* Testing matrix based on: https://nodejs.org/en/about/releases/
- Node 11 is no longer supported (not LTS)
- Node 12 added (active LTS)
- Node 13 added ("current" release)
## 1.4.1 (2019-11-06)
* Compatibility: Change TypeScript compile target back to `es6` (#1071)
* WARNING: This allows for the use of Node v6, which is no longer supported by Node.js, as it was end-of-life'd in April 2019
* We recommend updating to Node v8/v10 ASAP in order to get security updates and fixes from the Node.js team
* We are not actively running tests against Node v6 (ref #1076)
* Docs: `getAccountObjects` doc fix
* Dependencies:
* Update `bignumber.js`
* Update `ripple-keypairs`
* Update `ws`
* Build process: Update `webpack` flow
## 1.4.0 (2019-10-28)
* Unref timer so it does not hang the Node.js process
* Add a 2-second timeout for connect()
* Improve getTransaction() error when tx has not been validated yet
* Add support for the new X-address format
* Fix error in Safari, Chrome 78, Firefox 70
* Some error messages have changed slightly. For example:
* `-instance.Account is not of a type(s) string,instance.Account does not conform to the "address" format`
* `+instance.Account is not of a type(s) string,instance.Account is not exactly one from <xAddress>,<classicAddress>`
### Internal improvements
* Reduce dependency size
* Move tests to TypeScript
* Replace tslint with eslint
* Update https-proxy-agent
* Add tests
## 1.3.4 (2019-10-18)
* Update ripple-lib-transactionparser
* Improve error message when signing fails (e.g. due to trailing zeros)
* Integrate ripple-hashes (in TypeScript with improved naming and docs)
* Add multi-signing example to sign() method docs
* Update TypeScript
## 1.3.3 (2019-09-10)
* Expand node version compatibility to support Node.js 12 ([ripple-binary-codec#32](https://github.com/ripple/ripple-binary-codec/issues/32))
## 1.3.2 (2019-09-03)
* Export and document `rippleTimeToISO8601()` method
* Add type for isValidAddress (fixes error TS7016, #1032)
* Docs: update recommended Node.js version (#1031)
When using this release with [rippled](https://github.com/ripple/rippled), we recommend using [rippled version 1.3.1](https://github.com/ripple/rippled/releases/tag/1.3.1) or later.
## 1.3.1 (2019-08-26)
* Upgrade to gulp 4 (#1030)
* Remove http server (unused)
* Update dependencies
There are no changes in the browser version with this release. The npm package for Node.js should be slightly smaller.
When using this release with [rippled](https://github.com/ripple/rippled), we recommend using [rippled version 1.3.1](https://github.com/ripple/rippled/releases/tag/1.3.1).
## 1.3.0 (2019-08-16)
### Bug fixes:
* Breaking change: Fix `getServerInfo` (#1012)
Before:
```
{
// ...
"load": {
"jobTypes": {
"0": {"jobType": "untrustedValidation", "perSecond": 10},
"1": {"jobType": "ledgerData", "peakTime": 2, "perSecond": 2},
"2": {"inProgress": 1, "jobType": "clientCommand", "perSecond": 1},
"3": {"jobType": "transaction", "perSecond": 1},
// ...
},
"threads": 6
},
// ...
}
```
After:
```
{
// ...
"load": {
"jobTypes": [
{
"jobType": "untrustedValidation",
"perSecond": 8
},
{
"avgTime": 2,
"jobType": "ledgerData",
"peakTime": 72,
"perSecond": 2
},
{
"inProgress": 1,
"jobType": "clientCommand",
"perSecond": 1
},
{
"jobType": "transaction",
"perSecond": 1
},
// ...
],
"threads": 6
},
// ...
}
```
* Sign method - verify accurate encoding (#1026)
* In previous versions, the following could be encoded incorrectly:
* Amounts of XRP with more than 6 decimal places
* Amounts of XRP drops with any decimal places
* In versions 1.2.5 and 1.3.0, amounts that are invalid in this way will throw an error
* Expand `APIOptions` by extending `ConnectionOptions` (#1018, fixes #1017)
* Fix docs for destination.address (#1011)
### New features:
* Support removing a signer list (#1021)
* Export `setCanonicalFlag` method from `src/transaction/utils`
### Improvements:
* Clean up phrasing in schema descriptions (#1023)
* Improve docs
* Update dependencies
Since this release fixes a bug that could cause transactions to be serialized incorrectly during the signing process, it has also been simultaneously released as version 1.2.5 (patch release).
When using this release with [rippled](https://github.com/ripple/rippled), we recommend using [rippled version 1.3.1](https://github.com/ripple/rippled/releases/tag/1.3.1).
## 1.2.4 (2019-06-06)
* Update README.md
* Clarify docs
* Update dependencies
* Fix typos
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
4f09c056ccc51bc6cf17b128b559112e9c5adf19cc96ac8f9a06faee185697a7 ripple-1.2.4-debug.js
5da1c75a02d76b0b105d98355ee4561f5d5036e8d5d0237efd5960812dcaa1fd ripple-1.2.4-min.js
e147f303e880a65db149d2a5b9183b75814bd8145cd00740bcc4679d867192c8 ripple-1.2.4.js
```
## 1.2.3 (2019-04-30)
* Fix browser builds
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
efb0f29cde94534a015d8a2171abb11b9a4345ba01418bf5b6ab6042a6d51dde ripple-1.2.3-debug.js
b86145c0e30099b966ed8d3830ba25988d72877f1f87044d9954d6707be098ac ripple-1.2.3-min.js
e027d91c7321d41ba94bb1bdc77dcff0107a5fd9eb833c6dbd06f1bbedef3900 ripple-1.2.3.js
```
## 1.2.2 (2019-04-15)
* Prevent `prepareTransaction` from overwriting `Fee` and/or `LastLedgerSequence` (#997)
* Add `deliveredAmount` as optional field for type `Outcome` (#996)
* Fix build failure with TS strict checks (#993)
Minor changes:
* Use TypeScript project references
* Travis: Drop node 9 and add node 11 for testing
* Bump versions of devDependencies
Note: There is no browser version of this release.
## 1.2.1 (2019-03-23)
* Update `ripple-binary-codec` to 0.2.1 to support `tecKILLED`
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
531c2a8f4bf6d6b5bd4afe6a40b6a68a77179a343902cfa4210d7e35b5697af0 ripple-1.2.1-debug.js
201ee99922b16b7e32afb5317ef4bb9facc23b20c272bb5c4ed7010f5d996cab ripple-1.2.1-min.js
c1b984581299bf00e0e3c8ac4e62eadfc9b190bd78a2458a76e59ceb56046148 ripple-1.2.1.js
```
## 1.2.0 (2019-03-19)
This release:
* changes the way you handle errors for the `prepare*` methods.
* improves the `message` field of `RippledError`s.
* allows `Sequence` to be set in the transaction JSON provided to
`prepareTransaction`.
For details, continue reading:
### [BREAKING CHANGE] `prepare*` methods reject the Promise on error
The `prepare*` methods now always reject the Promise when an error occurs, instead of throwing.
Previously, the methods would synchronously throw on validation errors, despite being asynchronous methods that return Promises.
In other words, to handle errors in the past, you would need to use a try/catch block:
```
// OBSOLETE - no need for try/catch anymore
try {
api.preparePayment(address, payment, instructions).then(prepared => {
res.send(prepared.txJSON);
}).catch(error => {
// Handle asynchronous error
});
} catch (error) {
// Handle synchronous error
}
```
Now, you can rely on the Promise's `catch` handler, which is called with the error when the Promise is rejected:
```
api.preparePayment(address, payment, instructions).then(prepared => {
res.send(prepared.txJSON);
}).catch(error => {
// Handle error
});
```
This applies to:
* preparePayment
* prepareTrustline
* prepareOrder
* prepareOrderCancellation
* prepareSettings
* prepareEscrowCreation
* prepareEscrowExecution
* prepareCheckCreate
* prepareCheckCash
* prepareCheckCancel
* preparePaymentChannelCreate
* preparePaymentChannelClaim
* preparePaymentChannelFund
### Improved `RippledError` `message`
Previously, `RippledErrors` (errors from rippled) used rippled's `error` field as the `message`.
Now, the `error_message` field is used as the `message`.
This helps to surface the specific cause of an error.
For example, before:
```
[RippledError(invalidParams, { error: 'invalidParams',
error_code: 31,
error_message: 'Missing field \'account\'.',
id: 3,
request: { command: 'account_info', id: 3 },
status: 'error',
type: 'response' })]
```
After:
```
[RippledError(Missing field 'account'., { error: 'invalidParams',
error_code: 31,
error_message: 'Missing field \'account\'.',
id: 3,
request: { command: 'account_info', id: 3 },
status: 'error',
type: 'response' })]
```
In this case, you can see at a glance that `account` is the missing field.
The `error` field is still available in `errorObject.data.error`.
When `error_message` is not set (as with e.g. error 'entryNotFound'), the `error` field is used as the `message`.
### [BUG FIX] `prepareTransaction` does not overwrite the `Sequence` field
The `prepareTransaction` method now allows `Sequence` to be set in the Transaction JSON object, instead of overwriting it with the account's expected sequence based on the state of the ledger.
Previously, you had to use the `sequence` field in the `instructions` object to manually set a transaction's sequence number.
### New in rippled 1.2.1
As this is the first release of ripple-lib following the release of rippled 1.2.1, we would like to highlight the following API improvements:
1. The [`delivered_amount` field](https://developers.ripple.com/partial-payments.html#the-delivered-amount-field) has been added to the `ledger` method, and to transaction subscriptions.
api.getLedger({includeTransactions: true, includeAllData: true, ledgerVersion: 17718771}).then(...)
You can also call `ledger` directly:
request('ledger', {...}).then(...)
2. [Support for Ed25519 seeds encoded using ripple-lib](https://github.com/ripple/rippled/pull/2734)
You have access to these improvements when you use a rippled server running version 1.2.1 or later. At the time of writing, we recommend using rippled version **1.2.2** or later.
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
13021fe3efbdd59faf68597b0b18204b39847b285cca82f84c737e3d19922cc2 ripple-1.2.0-debug.js
0070225e731afd8c2c0a0976111ebf326c19a96ee1549368de9f016abdd53d2f ripple-1.2.0-min.js
d440268397c03ad5137a3294e53a07b959ef93cd23b1990d6f82621c4776ba9f ripple-1.2.0.js
```
## 1.1.2 (2018-12-12)
+ Update `submit` response (#978)
+ Includes the full object returned by rippled, while keeping the existing
fields for backward compatibility
+ Add `getLedger` option for ledger hash (#980)
+ Use the `ledgerHash` option to get a specific ledger by hash
Thanks to @alexchiriac for the contributions in this release.
When using `ripple-lib` with `rippled`, we recommend using `rippled` version
1.1.2 or later.
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
e6cc52395d0c3e205263777ba2e528e50f4d1f84bb4b16763a3bf7f5fcc290f5 ripple-1.1.2-debug.js
82df879bc2970e0e4fd161975a99448b4859b0cde751d8ea34e9f51d672090b9 ripple-1.1.2-min.js
12f56330dc71bba8ac3004025cbc9698413a0c619df302dda105b31228a67319 ripple-1.1.2.js
```
## 1.1.1 (2018-11-27)
+ Fix `getOrderbook` offer sorting (#970)
+ **BREAKING CHANGE:** The ordering of offers returned by `getOrderbook` has
been changed so that offers with the best quality are sorted first
+ Add new helper methods for working with the `rippled` APIs:
+ `formatBidsAndAsks`: Takes offers and returns a formatted order book object
with bids and asks
+ `renameCounterpartyToIssuer`: Takes an object and renames the `counterparty`
field to `issuer`
+ TypeScript: Add return type for `generateAddress` (#968)
When using `ripple-lib` with `rippled`, we recommend using `rippled` version 1.1.1 or
later.
The SHA-256 checksums for the browser version of this release can be found
below.
```
% shasum -a 256 *
e151900e49bb5482b02bef5b0b1542ea586076363b072ae616f6d4d2f7f5b8a1 ripple-1.1.1-debug.js
6aee3757b29de285f361e20862261090033c07a13fd09f4a3cc4c097b6e84b55 ripple-1.1.1-min.js
bea4a889fb9ee4092324c6667490ea66469bdde869ddc1aaddf5e9d12b0cf091 ripple-1.1.1.js
```
## 1.1.0 (2018-10-31)
+ Add support for Node.js v10 LTS (#964)

View File

@@ -1,21 +1,21 @@
# ripple-lib
# ripple-lib (RippleAPI)
A JavaScript API for interacting with the XRP Ledger
A JavaScript/TypeScript API for interacting with the XRP Ledger
[![NPM](https://nodei.co/npm/ripple-lib.png)](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
+ Issue [rippled API](https://ripple.com/build/rippled-apis/) requests
+ Listen to events on the XRP Ledger (transaction, ledger, etc.)
+ Helpers for creating requests and parsing responses for the [rippled API](https://developers.ripple.com/rippled-api.html)
+ Listen to events on the XRP Ledger (transactions, ledger, validations, etc.)
+ Sign and submit transactions to the XRP Ledger
+ Type definitions for TypeScript
## Getting Started
See also: [RippleAPI Beginners Guide](https://ripple.com/build/rippleapi-beginners-guide/)
### Requirements
+ **[Node v10](https://nodejs.org/)** is recommended. Other versions may work but are not frequently tested.
@@ -28,7 +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
+ [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
@@ -42,34 +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/`.
For more details, see the `scripts` in `package.json`.
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`
### 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.
`npm` may be used instead of `yarn` in the commands above.
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
+ [Ripple Developer Center](https://ripple.com/build/)
+ [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/)
[![Build Status](https://travis-ci.org/ripple/ripple-lib.svg?branch=master)](https://travis-ci.org/ripple/ripple-lib)

View File

@@ -1,9 +0,0 @@
/**
* This is an extension of Node's `process` object to include the browser
* property, which is added by webpack.
*/
interface AmbiguousProcess extends NodeJS.Process {
browser?: true
}
declare var process: AmbiguousProcess;

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,19 @@
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
```
Every XRP Ledger account has an *address*, which is a base58-encoding of a hash of the account's public key. XRP Ledger addresses always start with the lowercase letter `r`.
```json
"X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ"
```
An *address* refers to a specific XRP Ledger account. It is a base-58 encoding of a hash of the account's public key. There are two kinds of addresses in common use:
### Classic Address
A *classic address* encodes a hash of the account's public key and a checksum. It has no other data. This kind of address always starts with the lowercase letter `r`.
### X-address
An *X-address* encodes a hash of the account's public key, a tag, and a checksum. This kind of address starts with the uppercase letter `X` if it is intended for use on the production XRP Ledger (mainnet). It starts with the uppercase letter `T` if it is intended for use on a test network such as Testnet or Devnet.
## Account Sequence Number

View File

@@ -26,7 +26,7 @@ api.connect().then(() => {
}).catch(console.error);
```
RippleAPI is designed to work in [Node.js](https://nodejs.org) version **6.11.3**. RippleAPI may work on older Node.js versions if you use [Babel](https://babeljs.io/) for [ECMAScript 6](https://babeljs.io/docs/learn-es2015/) support.
RippleAPI is designed to work in [Node.js](https://nodejs.org) version 6 or higher. Ripple recommends Node.js v10 LTS.
The code samples in this documentation are written with ECMAScript 6 (ES6) features, but `RippleAPI` also works with ECMAScript 5 (ES5). Regardless of whether you use ES5 or ES6, the methods that return Promises return [ES6-style promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).

View File

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

View File

@@ -1,6 +1,8 @@
## generateAddress
`generateAddress(): {address: string, secret: string}`
`generateAddress(options?: object): {address: string, secret: string}`
Deprecated: This method returns a classic address. If you do not need the classic address, use `generateXAddress` instead.
Generate a new XRP Ledger address and corresponding secret.

View File

@@ -0,0 +1,23 @@
## generateXAddress
`generateXAddress(options?: object): {address: string, secret: string}`
Generate a new XRP Ledger address and corresponding secret.
### Parameters
<%- renderSchema('input/generate-x-address.json') %>
### Return Value
This method returns an object with the following structure:
<%- renderSchema('output/generate-x-address.json') %>
### Example
```javascript
return api.generateAddress();
```
<%- renderFixture('responses/generate-x-address.json') %>

View File

@@ -15,12 +15,13 @@ This method returns a promise that resolves with an object with the following st
<%- renderSchema('output/get-account-objects.json') %>
The types of objects that may be returned include:
* Offer objects for orders that are currently live, unfunded, or expired but not yet removed.
* RippleState objects for trust lines where this account's side is not in the default state.
* A SignerList object if the account has multi-signing enabled.
* Escrow objects for held payments that have not yet been executed or canceled.
* PayChannel objects for open payment channels.
* Check objects for pending checks.
* `Offer` objects for orders that are currently live, unfunded, or expired but not yet removed.
* `RippleState` objects for trust lines where this account's side is not in the default state.
* A `SignerList` object if the account has multi-signing enabled.
* `Escrow` objects for held payments that have not yet been executed or canceled.
* `PayChannel` objects for open payment channels.
* `Check` objects for pending checks.
### Example

View File

@@ -4,6 +4,10 @@
Returns open orders for the specified account. Open orders are orders that have not yet been fully executed and are still in the order book.
**Breaking change:** In ripple-lib 1.1.0 and earlier, orders returned by this method were not sorted correctly. Orders are now sorted correctly, from best to worst.
**See also:** An alternative way to get orderbooks is with `request` and [`formatBidsAndAsks`](#formatbidsandasks).
### Parameters
<%- renderSchema('input/get-orderbook.json') %>
@@ -14,9 +18,7 @@ This method returns a promise that resolves with an object with the following st
<%- renderSchema('output/get-orderbook.json') %>
### Raw order data
(Requires ripple-lib 0.22.0 or higher.) The response includes a `data` property containing the raw order data. This may include `owner_funds`, `Flags`, and other fields.
**Raw order data:** The response includes a `data` property containing the raw order data. This may include `owner_funds`, `Flags`, and other fields.
For details, see the rippled method [book_offers](https://ripple.com/build/rippled-apis/#book-offers).

View File

@@ -8,6 +8,11 @@
<% include request.md.ejs %>
<% include hasNextPage.md.ejs %>
<% include requestNextPage.md.ejs %>
<% include staticMethods.md.ejs %>
<% include renameCounterpartyToIssuer.md.ejs %>
<% include formatBidsAndAsks.md.ejs %>
<% include methods.md.ejs %>
<% include connect.md.ejs %>
<% include disconnect.md.ejs %>
@@ -47,6 +52,7 @@
<% include sign.md.ejs %>
<% include combine.md.ejs %>
<% include submit.md.ejs %>
<% include generateXAddress.md.ejs %>
<% include generateAddress.md.ejs %>
<% include isValidAddress.md.ejs %>
<% include isValidSecret.md.ejs %>
@@ -57,6 +63,7 @@
<% include computeLedgerHash.md.ejs %>
<% include xrpToDropsAndDropsToXrp.md.ejs %>
<% include iso8601ToRippleTime.md.ejs %>
<% include rippleTimeToISO8601.md.ejs %>
<% include txFlags.md.ejs %>
<% include schemaValidator.md.ejs %>
<% include events.md.ejs %>

View File

@@ -1,6 +1,7 @@
# Introduction
RippleAPI (ripple-lib) is the official client library to the XRP Ledger. Currently, RippleAPI is only available in JavaScript.
RippleAPI (ripple-lib) is the official client library to the XRP Ledger. Currently, RippleAPI is only available in JavaScript/TypeScript.
Using RippleAPI, you can:
* [Query transactions from the XRP Ledger history](#gettransaction)
@@ -8,3 +9,7 @@ Using RippleAPI, you can:
* [Submit](#submit) transactions to the XRP Ledger, including [Payments](#payment), [Orders](#order), [Settings changes](#settings), and [other types](#transaction-types)
* [Generate a new XRP Ledger Address](#generateaddress)
* ... and [much more](#api-methods).
This page contains documentation for ripple-lib. To use ripple-lib with npm/yarn, begin with the [Getting Started](https://github.com/ripple/ripple-lib#getting-started) steps.
**What is ripple-lib used for?** Here's a [list of applications that use `ripple-lib`](https://github.com/ripple/ripple-lib/blob/develop/APPLICATIONS.md). Open a PR to add your app or project to the list!

View File

@@ -2,7 +2,7 @@
`isValidAddress(address: string): boolean`
Checks if the specified string contains a valid address.
Checks if the specified string contains a valid address. X-addresses are considered valid with ripple-lib v1.4.0 and higher.
### Parameters

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ Returns the response from invoking the specified command, with the specified opt
Refer to [rippled APIs](https://ripple.com/build/rippled-apis/) for commands and options. All XRP amounts must be specified in drops. One drop is equal to 0.000001 XRP. See [Specifying Currency Amounts](https://ripple.com/build/rippled-apis/#specifying-currency-amounts).
Most commands return data for the `current` (in-progress, open) ledger by default. Do not rely on this. Always specify a ledger version in your request. In the example below, the 'validated' ledger is requested, which is the most recent ledger that has been validated by the whole network. See [Specifying Ledgers](https://ripple.com/build/rippled-apis/#specifying-ledgers).
Most commands return data for the `current` (in-progress, open) ledger by default. Do not rely on this. Always specify a ledger version in your request. In the example below, the 'validated' ledger is requested, which is the most recent ledger that has been validated by the whole network. See [Specifying Ledgers](https://xrpl.org/basic-data-types.html#specifying-ledgers).
### Return Value

View File

@@ -0,0 +1,27 @@
## rippleTimeToISO8601
`rippleTimeToISO8601(rippleTime: number): string`
This method takes the number of seconds since the "Ripple Epoch" of January 1, 2000 (00:00 UTC) and returns a string representation of a date.
The Ripple Epoch is 946684800 seconds after the Unix Epoch.
This method is useful for interpreting timestamps returned by the rippled APIs. The rippled APIs represent time as an unsigned integer of the number of seconds since the Ripple Epoch.
### Parameters
`rippleTime`: A number of seconds since the Ripple Epoch.
### Return Value
A string representing a date and time, created by calling a `Date` object's `toISOString()` method.
### Example
```javascript
api.rippleTimeToISO8601(540659097);
```
```json
'2017-02-17T15:04:57.000Z'
```

View File

@@ -1,11 +1,13 @@
# rippled APIs
ripple-lib relies on [rippled APIs](https://ripple.com/build/rippled-apis/) for all online functionality. With ripple-lib version 1.0.0 and higher, you can easily access rippled APIs through ripple-lib. Use the `request()`, `hasNextPage()`, and `requestNextPage()` methods:
* Use `request()` to issue any `rippled` command, including `account_currencies`, `subscribe`, and `unsubscribe`. [Full list of API Methods](https://ripple.com/build/rippled-apis/#api-methods).
ripple-lib relies on [rippled APIs](https://ripple.com/build/rippled-apis/) for online functionality. In addition to ripple-lib's own methods, you can also access rippled APIs through ripple-lib. Use the `request()`, `hasNextPage()`, and `requestNextPage()` methods:
* Use `request()` to issue any `rippled` command, including `account_currencies`, `subscribe`, and `unsubscribe`. [Full list of API Methods](https://ripple.com/build/rippled-apis/#api-methods).
* Use `hasNextPage()` to determine whether a response has more pages. This is true when the response includes a [`marker` field](https://ripple.com/build/rippled-apis/#markers-and-pagination).
* Use `requestNextPage()` to request the next page of data.
When using rippled APIs:
* [Specify XRP amounts in drops](https://developers.ripple.com/basic-data-types.html#specifying-currency-amounts).
* [Specify timestamps as the number of seconds since the "Ripple Epoch"](https://developers.ripple.com/basic-data-types.html#specifying-time).
* Instead of `counterparty`, use `issuer`.

View File

@@ -15,6 +15,8 @@ This method can sign any of [the transaction types supported by ripple-binary-co
<%- renderSchema("input/sign.json") %>
When this method is used for multisigning, the `options` parameter is required. See the multisigning example in this section for more details.
### Return Value
This method returns an object with the following structure:
@@ -31,3 +33,91 @@ return api.sign(txJSON, secret); // or: api.sign(txJSON, keypair);
```
<%- renderFixture("responses/sign.json") %>
### Example (multisigning)
```javascript
const RippleAPI = require('ripple-lib').RippleAPI;
// jon's address will have a multi-signing setup with a quorum of 2
const jon = {
account: 'rJKpme4m2zBQceBuU89d7vLMzgoUw2Ptj',
secret: 'sh4Va7b1wQof8knHFV2sxwX12fSgK'
};
const aya = {
account: 'rnrPdBjs98fFFfmRpL6hM7exT788SWQPFN',
secret: 'snaMuMrXeVc2Vd4NYvHofeGNjgYoe'
};
const bran = {
account: 'rJ93RLnT1t5A8fCr7HTScw7WtfKJMRXodH',
secret: 'shQtQ8Um5MS218yvEU3Ehy1eZQKqH'
};
// Setup the signers list with a quorum of 2
const multiSignSetupTransaction = {
"Flags": 0,
"TransactionType": "SignerListSet",
"Account": "rJKpme4m2zBQceBuU89d7vLMzgoUw2Ptj",
"Fee": "120",
"SignerQuorum": 2,
"SignerEntries": [
{
"SignerEntry": {
"Account": "rnrPdBjs98fFFfmRpL6hM7exT788SWQPFN",
"SignerWeight": 2
}
},
{
"SignerEntry": {
"Account": "rJ93RLnT1t5A8fCr7HTScw7WtfKJMRXodH",
"SignerWeight": 1
}
},
]
};
// a transaction which requires multi signing
const multiSignPaymentTransaction = {
TransactionType: 'Payment',
Account: 'rJKpme4m2zBQceBuU89d7vLMzgoUw2Ptj',
Destination: 'rJ93RLnT1t5A8fCr7HTScw7WtfKJMRXodH',
Amount: '88000000'
};
const api = new RippleAPI({
server: 'wss://s.altnet.rippletest.net:51233'
});
api.connect().then(() => {
// adding the multi signing feature to jon's account
api.prepareTransaction(multiSignSetupTransaction).then((prepared) => {
console.log(prepared);
jonSign = api.sign(prepared.txJSON, jon.secret).signedTransaction;
api.submit(jonSign).then( response => {
console.log(response.resultCode, response.resultMessage);
// multi sign a transaction
api.prepareTransaction(multiSignPaymentTransaction).then(prepared => {
console.log(prepared);
// Aya and Bran sign it too but with 'signAs' set to their own account
let ayaSign = api.sign(prepared.txJSON, aya.secret, {'signAs': aya.account}).signedTransaction;
let branSign = api.sign(prepared.txJSON, bran.secret, {'signAs': bran.account}).signedTransaction;
// signatures are combined and submitted
let combinedTx = api.combine([ayaSign, branSign]);
api.submit(combinedTx.signedTransaction).then(response => {
console.log(response.tx_json.hash);
return api.disconnect();
}).catch(console.error);
}).catch(console.error);
}).catch(console.error)
}).catch(console.error);
}).catch(console.error);
```
Assuming the multisigning account was setup properly, the above example will respond with `resultCode: 'tesSUCCESS'` and the hash for the transaction.
If any of `{signAs: some_address}` options were missing the code will return a validation error as follow:
```
[ValidationError(txJSON is not the same for all signedTransactions)]
```

View File

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

View File

@@ -15,7 +15,7 @@ Type | Description
[escrowCancellation](#escrow-cancellation) | An `escrowCancellation` transaction unlocks the funds in an escrow and sends them back to the creator of the escrow, but it will only work after the escrow expires.
[escrowExecution](#escrow-execution) | An `escrowExecution` transaction unlocks the funds in an escrow and sends them to the destination of the escrow, but it will only work if the cryptographic condition is provided.
[checkCreate](#check-create) | A `checkCreate` transaction creates a check on the ledger, which is a deferred payment that can be cashed by its intended destination.
[checkCancel](#check-cancel) | A `checkCancel` transaction cancels an unreedemed Check, removing it from the ledger without sending any money.
[checkCancel](#check-cancel) | A `checkCancel` transaction cancels an unredeemed Check, removing it from the ledger without sending any money.
[checkCash](#check-cash) | A `checkCash` transaction redeems a Check to receive up to the amount authorized by the corresponding `checkCreate` transaction. Only the `destination` address of a Check can cash it.
[paymentChannelCreate](#payment-channel-create) | A `paymentChannelCreate` transaction opens a payment channel between two addresses with XRP set aside for asynchronous payments.
[paymentChannelFund](#payment-channel-fund) | A `paymentChannelFund` transaction adds XRP to a payment channel and optionally sets a new expiration for the channel.
@@ -43,17 +43,19 @@ Executing a transaction with `RippleAPI` requires the following four steps:
## Transaction Fees
Every transaction must destroy a small amount of XRP as a cost to send the transaction. This is also called a *transaction fee*. The transaction cost is designed to increase along with the load on the XRP Ledger, making it very expensive to deliberately or inadvertently overload the peer-to-peer network that powers the XRP Ledger.
Every transaction must destroy a small amount of XRP as a cost to apply the transaction to the ledger. This is also called a *transaction fee*. The transaction cost is designed to increase along with the load on the XRP Ledger, making it very expensive to deliberately or inadvertently overload the peer-to-peer network that powers the XRP Ledger.
You can choose the size of the fee you want to pay or let a default be used. You can get an estimate of the fee required to be included in the next ledger closing with the [getFee](#getfee) method.
For a multi-signed transaction, ripple-lib automatically multiplies the `fee` by (1 + Number of Signatures Provided). For example, if you set `instructions.fee = '0.000020'` and `instructions.signersCount = 2`, the prepared transaction's `Fee` will be 20 drops × (1 + 2 Signatures) = 60 drops. See [Transaction Cost](https://developers.ripple.com/transaction-cost.html).
## Transaction Instructions
Transaction instructions indicate how to execute a transaction, complementary with the [transaction specification](#transaction-specifications).
<%- renderSchema("objects/instructions.json") %>
We recommend that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the XRP Ledger's consensus-validated ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare\*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare\*" method.
We recommend that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeed in the future. It is impossible for a transaction to succeed after the XRP Ledger's consensus-validated ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare\*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare\*" method.
## Transaction ID

View File

@@ -1,77 +1,76 @@
{
"name": "ripple-lib",
"version": "1.1.0",
"version": "1.6.0",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
"files": [
"dist/npm/*",
"build/*"
"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"
"ws": "./dist/npm/common/wswrapper.js",
"https-proxy-agent": false
},
"directories": {
"test": "test"
},
"dependencies": {
"@types/lodash": "^4.14.85",
"@types/ws": "^3.2.0",
"bignumber.js": "^4.1.0",
"https-proxy-agent": "2.2.1",
"@types/lodash": "^4.14.136",
"@types/ws": "^6.0.3",
"bignumber.js": "^9.0.0",
"https-proxy-agent": "^4.0.0",
"jsonschema": "1.2.2",
"lodash": "^4.17.4",
"ripple-address-codec": "^2.0.1",
"ripple-binary-codec": "0.2.0",
"ripple-hashes": "^0.3.1",
"ripple-keypairs": "^0.10.1",
"ripple-lib-transactionparser": "0.7.1",
"ws": "^3.3.1"
"lodash.isequal": "^4.5.0",
"ripple-address-codec": "^4.0.0",
"ripple-binary-codec": "^0.2.5",
"ripple-keypairs": "^0.11.0",
"ripple-lib-transactionparser": "0.8.1",
"ws": "^7.2.0"
},
"devDependencies": {
"@types/node": "^8.0.53",
"assert-diff": "^1.0.1",
"coveralls": "^2.13.1",
"@types/mocha": "^5.2.7",
"@types/node": "^13.1.1",
"@typescript-eslint/eslint-plugin": "^2.3.3",
"@typescript-eslint/parser": "^2.3.3",
"assert-diff": "^2.0.3",
"doctoc": "^0.15.0",
"ejs": "^2.3.4",
"eventemitter2": "^0.4.14",
"gulp": "^3.8.10",
"gulp-bump": "^0.1.13",
"gulp-rename": "^1.2.0",
"http-server": "^0.8.5",
"jayson": "^1.2.2",
"json-loader": "^0.5.2",
"eslint": "^6.5.1",
"eventemitter2": "^6.0.0",
"json-schema-to-markdown-table": "^0.4.0",
"mocha": "^2.1.0",
"mocha-in-sauce": "^0.0.1",
"mocha": "6.2.2",
"mocha-junit-reporter": "^1.9.1",
"null-loader": "^0.1.1",
"nyc": "^11.3.0",
"source-map-support": "^0.5.0",
"ts-loader": "^3.2.0",
"ts-node": "^3.3.0",
"tslint": "^5.8.0",
"tslint-eslint-rules": "^4.1.1",
"typescript": "2.9.2",
"uglifyjs-webpack-plugin": "^1.1.4",
"webpack": "3.12.0",
"yargs": "^8.0.2"
"nyc": "^14.1.1",
"prettier": "^1.19.1",
"ts-node": "^8.4.1",
"typescript": "^3.6.4",
"webpack": "^4.41.2",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-cli": "^3.3.9"
},
"scripts": {
"build": "gulp",
"build:schemas": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/",
"build:lib": "tsc --build",
"build:web": "webpack",
"build": "yarn build:schemas && yarn build:lib && yarn build:web",
"analyze": "yarn build:web --analyze",
"watch": "yarn build:lib --watch",
"clean": "rm -rf dist/npm",
"doctoc": "doctoc docs/index.md --title '# RippleAPI Reference' --github --maxlevel 2",
"docgen": "node --harmony scripts/build_docs.js",
"clean": "rm -rf dist/npm",
"compile": "mkdir -p dist/npm/common && cp -r src/common/schemas dist/npm/common/ && tsc",
"watch": "tsc -w",
"prepublish": "npm run clean && npm run compile && npm run build",
"test": "nyc mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "tslint -p ./",
"prepublish": "yarn clean && yarn build",
"test": "TS_NODE_PROJECT=src/tsconfig.json nyc mocha --exit",
"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",
"sauce": "node scripts/sauce-runner.js"
"start": "node scripts/http.js"
},
"repository": {
"type": "git",
@@ -79,6 +78,7 @@
},
"readmeFilename": "README.md",
"engines": {
"node": ">=6.12.3"
"node": ">=8",
"yarn": "^1.15.2"
}
}

View File

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

View File

@@ -1,16 +0,0 @@
'use strict';
const createHTTPServer = require('../dist/npm/http').createHTTPServer;
const port = 5990;
const serverUrl = 'wss://s1.ripple.com';
function main() {
const server = createHTTPServer({server: serverUrl}, port);
server.start().then(() => {
console.log('Server started on port ' + String(port));
});
}
main();

View File

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

View File

@@ -0,0 +1,17 @@
import {RippleAPI} from '../../dist/npm'
const api = new RippleAPI({
server: 'wss://s.altnet.rippletest.net:51233'
})
getTransaction()
async function getTransaction() {
await api.connect()
const ledger = await api.getLedger({includeTransactions: true})
console.log(ledger)
const tx = await api.getTransaction(ledger.transactionHashes[0])
console.log(tx)
console.log('deliveredAmount:', tx.outcome.deliveredAmount)
process.exit(0)
}

View File

@@ -1,4 +1,5 @@
const RippleAPI = require('../dist/npm').RippleAPI
import {RippleAPI} from '../../dist/npm'
const api = new RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
parseAccountFlags()
@@ -8,4 +9,5 @@ async function parseAccountFlags() {
const account_info = await api.request('account_info', {account: 'rKsdkGhyZH6b2Zzd5hNnEqSv2wpznn4n6N'})
const flags = api.parseAccountFlags(account_info.account_data.Flags)
console.log(JSON.stringify(flags, null, 2))
process.exit(0)
}

13
snippets/tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"extends": "../tsconfig-base",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"references": [
{ "path": "../src" }
],
"include": [
"./src/**/*.ts"
]
}

View File

@@ -5,8 +5,10 @@ import {
validate,
xrpToDrops,
dropsToXrp,
rippleTimeToISO8601,
iso8601ToRippleTime,
txFlags
txFlags,
ensureClassicAddress
} from './common'
import {
connect,
@@ -22,7 +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 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'
@@ -44,40 +46,55 @@ import prepareSettings from './transaction/settings'
import sign from './transaction/sign'
import combine from './transaction/combine'
import submit from './transaction/submit'
import {generateAddressAPI} from './offline/generate-address'
import {deriveKeypair, deriveAddress} from './offline/derive'
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'
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'
import * as schemaValidator from './common/schema-validator'
import {getServerInfo, getFee} from './common/serverinfo'
import {clamp} from './ledger/utils'
import {Instructions, Prepare} from './transaction/types'
import {clamp, renameCounterpartyToIssuer} from './ledger/utils'
import {TransactionJSON, Instructions, Prepare} from './transaction/types'
import {ConnectionUserOptions} from './common/connection'
import {isValidXAddress, isValidClassicAddress} from 'ripple-address-codec'
export type APIOptions = {
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
}
@@ -86,7 +103,7 @@ export type APIOptions = {
* 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':
@@ -114,6 +131,9 @@ class RippleAPI extends EventEmitter {
schemaValidator
}
static renameCounterpartyToIssuer = renameCounterpartyToIssuer
static formatBidsAndAsks = formatBidsAndAsks
constructor(options: APIOptions = {}) {
super()
validate.apiOptions(options)
@@ -132,7 +152,14 @@ class RippleAPI extends EventEmitter {
this.emit('connected')
})
this.connection.on('disconnected', code => {
this.emit('disconnected', code)
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
}
this.emit('disconnected', finalCode)
})
} else {
// use null object pattern to provide better error message if user
@@ -141,35 +168,56 @@ 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,
command
command,
account: params.account ? ensureClassicAddress(params.account) : undefined
})
}
@@ -189,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')
@@ -206,8 +254,10 @@ class RippleAPI extends EventEmitter {
*
* You can later submit the transaction with `submit()`.
*/
async prepareTransaction(txJSON: object, instructions: Instructions = {}):
Promise<Prepare> {
async prepareTransaction(
txJSON: TransactionJSON,
instructions: Instructions = {}
): Promise<Prepare> {
return transactionUtils.prepareTransaction(txJSON, this, instructions)
}
@@ -235,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)
@@ -253,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
@@ -278,10 +334,19 @@ class RippleAPI extends EventEmitter {
} else {
lastBatchLength = 0
}
} while(!!marker && count < countTo && lastBatchLength !== 0)
} while (!!marker && count < countTo && lastBatchLength !== 0)
return results
}
// @deprecated Use X-addresses instead
generateAddress(options: GenerateAddressOptions = {}): GeneratedAddress {
return generateAddressAPI({...options, includeClassicAddress: true})
}
generateXAddress(options: GenerateAddressOptions = {}): GeneratedAddress {
return generateAddressAPI(options)
}
connect = connect
disconnect = disconnect
isConnected = isConnected
@@ -295,8 +360,8 @@ class RippleAPI extends EventEmitter {
getBalances = getBalances
getBalanceSheet = getBalanceSheet
getPaths = getPaths
getOrders = getOrders
getOrderbook = getOrderbook
getOrders = getOrders
getSettings = getSettings
getAccountInfo = getAccountInfo
getAccountObjects = getAccountObjects
@@ -322,7 +387,6 @@ class RippleAPI extends EventEmitter {
combine = combine
submit = submit
generateAddress = generateAddressAPI
deriveKeypair = deriveKeypair
deriveAddress = deriveAddress
computeLedgerHash = computeLedgerHash
@@ -330,8 +394,17 @@ class RippleAPI extends EventEmitter {
verifyPaymentChannelClaim = verifyPaymentChannelClaim
errors = errors
static deriveXAddress = deriveXAddress
// RippleAPI.deriveClassicAddress (static) is a new name for api.deriveAddress
static deriveClassicAddress = deriveAddress
static isValidXAddress = isValidXAddress
static isValidClassicAddress = isValidClassicAddress
xrpToDrops = xrpToDrops
dropsToXrp = dropsToXrp
rippleTimeToISO8601 = rippleTimeToISO8601
iso8601ToRippleTime = iso8601ToRippleTime
txFlags = txFlags
@@ -339,6 +412,4 @@ class RippleAPI extends EventEmitter {
isValidSecret = schemaValidator.isValidSecret
}
export {
RippleAPI
}
export {RippleAPI}

View File

@@ -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}

View File

@@ -1,20 +1,20 @@
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 {
// hack for internet explorer
if (!object.constructor.name) {
return object.constructor.toString().match(/^function\s+([^(]*)/)![1]
if (object.constructor.name) {
return object.constructor.name
}
return object.constructor.name
// try to guess it on legacy browsers (ie)
const constructorString = object.constructor.toString()
const functionConstructor = constructorString.match(/^function\s+([^(]*)/)
const classConstructor = constructorString.match(/^class\s([^\s]*)/)
return functionConstructor ? functionConstructor[1] : classConstructor[1]
}
export {
getConstructorName,
setPrototypeOf
}
export {getConstructorName, setPrototypeOf}

View File

@@ -1,14 +1,23 @@
import * as _ from 'lodash'
import {EventEmitter} from 'events'
import {parse as parseUrl} from 'url'
import * as WebSocket from 'ws'
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,59 +25,57 @@ export interface ConnectionOptions {
key?: string
passphrase?: string
certificate?: string
timeout?: 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 _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 _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)
}
_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)
}
@@ -101,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)
@@ -150,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() {
@@ -179,6 +184,13 @@ class Connection extends EventEmitter {
}
}
_clearConnectTimer() {
if (this._connectTimer !== null) {
clearTimeout(this._connectTimer)
this._connectTimer = null
}
}
_onOpen() {
if (!this._ws) {
return Promise.reject(new DisconnectedError())
@@ -202,16 +214,10 @@ class Connection extends EventEmitter {
this._updateLedgerVersions(data)
this._updateFees(data)
this._rebindOnUnxpectedClose()
this._rebindOnUnexpectedClose()
this._retry = 0
this._ws.on('error', error => {
// TODO: "type" does not exist on official error type, safe to remove?
if (process.browser && error && (<any>error).type === 'error') {
// we are in browser, ignore error - `close` event will be fired
// after error
return
}
this.emit('error', 'websocket', error.message, error)
})
@@ -222,16 +228,20 @@ class Connection extends EventEmitter {
})
}
_rebindOnUnxpectedClose() {
_rebindOnUnexpectedClose() {
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)
}
_unbindOnUnxpectedClose() {
_unbindOnUnexpectedClose() {
if (this._onUnexpectedCloseBound) {
this._ws.removeListener('close', this._onUnexpectedCloseBound)
}
@@ -240,24 +250,27 @@ class Connection extends EventEmitter {
_onOpenError(reject, error) {
this._onOpenErrorBound = null
this._unbindOnUnxpectedClose()
this._unbindOnUnexpectedClose()
reject(new NotConnectedError(error.message, error))
}
_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 {
@@ -267,16 +280,19 @@ class Connection extends EventEmitter {
}
options.agent = new HttpsProxyAgent(proxyOptions)
}
if (this._authorization !== undefined) {
const base64 = new Buffer(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,
@@ -287,47 +303,83 @@ class Connection extends EventEmitter {
return websocket
}
connect() {
connect(): Promise<void> {
this._clearConnectTimer()
this._clearReconnectTimer()
return new Promise((resolve, reject) => {
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', () => 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()
})
.catch(err => {
this._clearConnectTimer()
throw err
})
)
}
disconnect() {
disconnect(): Promise<void> {
return this._disconnect(true)
}
_disconnect(calledByUser) {
_disconnect(calledByUser): Promise<void> {
this._clearHeartbeatInterval()
if (calledByUser) {
this._clearConnectTimer()
this._clearReconnectTimer()
this._retry = 0
}
@@ -355,11 +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)
if (!this._shouldBeConnected) {
reject(new NotConnectedError())
} else if (this._state === WebSocket.OPEN && this._isReady) {
@@ -375,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> {
@@ -393,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))
}
})
}
@@ -445,12 +527,18 @@ class Connection extends EventEmitter {
this.once(eventName, response => {
if (response.status === 'error') {
_reject(new RippledError(response.error, response))
_reject(
new RippledError(response.error_message || response.error, response)
)
} else if (response.status === 'success') {
_resolve(response.result)
} else {
_reject(new ResponseFormatError(
'unrecognized status: ' + response.status, response))
_reject(
new ResponseFormatError(
'unrecognized status: ' + response.status,
response
)
)
}
})
@@ -459,10 +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)
}).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)
})
}
}

View File

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

View File

@@ -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'
)
}
}

View File

@@ -0,0 +1,49 @@
# XRP Ledger Hashes
Methods to hash XRP Ledger objects
## Methods
### computeBinaryTransactionHash = (txBlobHex: string): string
Compute the hash of a binary transaction blob.
### computeTransactionHash = (txJSON: any): string
Compute the hash of a transaction in txJSON format.
### computeBinaryTransactionSigningHash = (txBlobHex: string): string
### computeTransactionSigningHash = (txJSON: any): string
### computeAccountHash = (address: string): string
Compute the hash of an account, given the account's classic address (starting with `r`).
### computeSignerListHash = (address: string): string
Compute the hash of an account's SignerList.
### computeOrderHash = (address: string, sequence: number): string
Compute the hash of an order, given the owner's classic address (starting with `r`) and the account sequence number of the `OfferCreate` order transaction.
### computeTrustlineHash = (address1: string, address2: string, currency: string): string
Compute the hash of a trustline, given the two parties' classic addresses (starting with `r`) and the currency code.
### computeTransactionTreeHash = (transactions: any[]): string
### computeStateTreeHash = (entries: any[]): string
### computeLedgerHash = (ledgerHeader): string
Compute the hash of a ledger.
### computeEscrowHash = (address, sequence): string
Compute the hash of an escrow, given the owner's classic address (starting with `r`) and the account sequence number of the `EscrowCreate` escrow transaction.
### computePaymentChannelHash = (address, dstAddress, sequence): string
Compute the hash of a payment channel, given the owner's classic address (starting with `r`), the classic address of the destination, and the account sequence number of the `PaymentChannelCreate` payment channel transaction.

View File

@@ -0,0 +1,40 @@
/**
* Prefix for hashing functions.
*
* These prefixes are inserted before the source material used to
* generate various hashes. This is done to put each hash in its own
* "space." This way, two different types of objects with the
* same binary data will produce different hashes.
*
* Each prefix is a 4-byte value with the last byte set to zero
* and the first three bytes formed from the ASCII equivalent of
* some arbitrary string. For example "TXN".
*/
enum HashPrefix {
// transaction plus signature to give transaction ID
TRANSACTION_ID = 0x54584e00, // 'TXN'
// transaction plus metadata
TRANSACTION_NODE = 0x534e4400, // 'TND'
// inner node in tree
INNER_NODE = 0x4d494e00, // 'MIN'
// leaf node in tree
LEAF_NODE = 0x4d4c4e00, // 'MLN'
// inner transaction to sign
TRANSACTION_SIGN = 0x53545800, // 'STX'
// inner transaction to sign (TESTNET)
TRANSACTION_SIGN_TESTNET = 0x73747800, // 'stx'
// inner transaction to multisign
TRANSACTION_MULTISIGN = 0x534d5400, // 'SMT'
// ledger
LEDGER = 0x4c575200 // 'LWR'
}
export default HashPrefix

179
src/common/hashes/index.ts Normal file
View File

@@ -0,0 +1,179 @@
import BigNumber from 'bignumber.js'
import {decodeAccountID} from 'ripple-address-codec'
import sha512Half from './sha512Half'
import HashPrefix from './hash-prefix'
import {SHAMap, NodeType} from './shamap'
import {encode} from 'ripple-binary-codec'
import ledgerspaces from './ledgerspaces'
const padLeftZero = (string: string, length: number): string => {
return Array(length - string.length + 1).join('0') + string
}
const intToHex = (integer: number, byteLength: number): string => {
return padLeftZero(Number(integer).toString(16), byteLength * 2)
}
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)
return padLeftZero(hex, byteLength * 2)
}
const ledgerSpaceHex = (name: string): string => {
return intToHex(ledgerspaces[name].charCodeAt(0), 2)
}
const addressToHex = (address: string): string => {
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)
bytes[12] = currency.charCodeAt(0) & 0xff
bytes[13] = currency.charCodeAt(1) & 0xff
bytes[14] = currency.charCodeAt(2) & 0xff
return bytesToHex(bytes)
}
return currency
}
const addLengthPrefix = (hex: string): string => {
const length = hex.length / 2
if (length <= 192) {
return bytesToHex([length]) + hex
} else if (length <= 12480) {
const x = length - 193
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
}
throw new Error('Variable integer overflow.')
}
export const computeBinaryTransactionHash = (txBlobHex: string): string => {
const prefix = HashPrefix.TRANSACTION_ID.toString(16).toUpperCase()
return sha512Half(prefix + txBlobHex)
}
export const computeTransactionHash = (txJSON: any): string => {
return computeBinaryTransactionHash(encode(txJSON))
}
export const computeBinaryTransactionSigningHash = (
txBlobHex: string
): string => {
const prefix = HashPrefix.TRANSACTION_SIGN.toString(16).toUpperCase()
return sha512Half(prefix + txBlobHex)
}
export const computeTransactionSigningHash = (txJSON: any): string => {
return computeBinaryTransactionSigningHash(encode(txJSON))
}
export const computeAccountHash = (address: string): string => {
return sha512Half(ledgerSpaceHex('account') + addressToHex(address))
}
export const computeSignerListHash = (address: string): string => {
return sha512Half(
ledgerSpaceHex('signerList') + addressToHex(address) + '00000000'
) // uint32(0) signer list index
}
export const computeOrderHash = (address: string, sequence: number): string => {
const prefix = '00' + intToHex(ledgerspaces.offer.charCodeAt(0), 1)
return sha512Half(prefix + addressToHex(address) + intToHex(sequence, 4))
}
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 lowAddressHex = swap ? address2Hex : address1Hex
const highAddressHex = swap ? address1Hex : address2Hex
const prefix = ledgerSpaceHex('rippleState')
return sha512Half(
prefix + lowAddressHex + highAddressHex + currencyToHex(currency)
)
}
export const computeTransactionTreeHash = (transactions: any[]): string => {
const shamap = new SHAMap()
transactions.forEach(txJSON => {
const txBlobHex = encode(txJSON)
const metaHex = encode(txJSON.metaData)
const txHash = computeBinaryTransactionHash(txBlobHex)
const data = addLengthPrefix(txBlobHex) + addLengthPrefix(metaHex)
shamap.addItem(txHash, data, NodeType.TRANSACTION_METADATA)
})
return shamap.hash
}
export const computeStateTreeHash = (entries: any[]): string => {
const shamap = new SHAMap()
entries.forEach(ledgerEntry => {
const data = encode(ledgerEntry)
shamap.addItem(ledgerEntry.index, data, NodeType.ACCOUNT_STATE)
})
return shamap.hash
}
// 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)
)
}
export const computeEscrowHash = (address, sequence): string => {
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)
)
}

View File

@@ -0,0 +1,24 @@
/**
* Ripple ledger namespace prefixes.
*
* The Ripple ledger is a key-value store. In order to avoid name collisions,
* names are partitioned into namespaces.
*
* 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'
}

View File

@@ -0,0 +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)
}
export default sha512Half

181
src/common/hashes/shamap.ts Normal file
View File

@@ -0,0 +1,181 @@
import hashPrefix from './hash-prefix'
import sha512Half from './sha512Half'
const HEX_ZERO =
'0000000000000000000000000000000000000000000000000000000000000000'
export enum NodeType {
INNER = 1,
TRANSACTION_NO_METADATA = 2,
TRANSACTION_METADATA = 3,
ACCOUNT_STATE = 4
}
export abstract class Node {
/**
* Abstract constructor representing a node in a SHAMap tree.
* Can be either InnerNode or Leaf.
* @constructor
*/
public constructor() {}
public addItem(_tag: string, _node: Node): void {
throw new Error(
'Called unimplemented virtual method SHAMapTreeNode#addItem.'
)
}
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 type: NodeType
public depth: number
public empty: boolean
/**
* Define an Inner (non-leaf) node in a SHAMap tree.
* @param {number} depth i.e. how many parent inner nodes
* @constructor
*/
public constructor(depth: number = 0) {
super()
this.leaves = {}
this.type = NodeType.INNER
this.depth = depth
this.empty = true
}
/**
* @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))
if (existingNode) {
// A node already exists in this slot
if (existingNode instanceof InnerNode) {
// There is an inner node, so we need to go deeper
existingNode.addItem(tag, node)
} else if (existingNode instanceof Leaf) {
if (existingNode.tag === tag) {
// Collision
throw new Error(
'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)
}
}
} else {
// Neat, we have a nice open spot for the new node
this.setNode(parseInt(tag[this.depth], 16), node)
}
}
/**
* Overwrite the node that is currently in a given slot.
* @param {number} slot a number 0-15
* @param {Node} node to place
* @return {void}
*/
public setNode(slot: number, node: Node): void {
if (slot < 0 || slot > 15) {
throw new Error('Invalid slot: slot must be between 0-15.')
}
this.leaves[slot] = node
this.empty = false
}
/**
* Get the node that is currently in a given slot.
* @param {number} slot a number 0-15
* @return {Node}
*/
public getNode(slot: number): Node {
if (slot < 0 || slot > 15) {
throw new Error('Invalid slot: slot must be between 0-15.')
}
return this.leaves[slot]
}
public get hash(): string {
if (this.empty) return HEX_ZERO
let hex = ''
for (let i = 0; i < 16; i++) {
hex += this.leaves[i] ? this.leaves[i].hash : HEX_ZERO
}
const prefix = hashPrefix.INNER_NODE.toString(16)
return sha512Half(prefix + hex)
}
}
export class Leaf extends Node {
public tag: string
public type: NodeType
public data: string
/**
* Leaf node in a SHAMap tree.
* @param {string} tag equates to a ledger entry `index`
* @param {string} data hex of account state, transaction etc
* @param {number} type one of TYPE_ACCOUNT_STATE, TYPE_TRANSACTION_MD etc
* @constructor
*/
public constructor(tag: string, data: string, type: NodeType) {
super()
this.tag = tag
this.type = type
this.data = data
}
public get hash(): string | void {
switch (this.type) {
case NodeType.ACCOUNT_STATE: {
const leafPrefix = hashPrefix.LEAF_NODE.toString(16)
return sha512Half(leafPrefix + this.data + this.tag)
}
case NodeType.TRANSACTION_NO_METADATA: {
const txIDPrefix = hashPrefix.TRANSACTION_ID.toString(16)
return sha512Half(txIDPrefix + this.data)
}
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 {
public root: InnerNode
/**
* SHAMap tree.
* @constructor
*/
public constructor() {
this.root = new InnerNode(0)
}
public addItem(tag: string, data: string, type: NodeType): void {
this.root.addItem(tag, new Leaf(tag, data, type))
}
public get hash(): string {
return this.root.hash
}
}

View File

@@ -2,13 +2,29 @@ import * as constants from './constants'
import * as errors from './errors'
import * as validate from './validate'
import * as serverInfo from './serverinfo'
export {
constants,
errors,
validate,
serverInfo
import {xAddressToClassicAddress, isValidXAddress} from 'ripple-address-codec'
export function ensureClassicAddress(account: string): string {
if (isValidXAddress(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.'
)
}
// For rippled requests that use an account, always use a classic address.
return classicAddress
} else {
return account
}
}
export {constants, errors, validate, serverInfo}
export {
dropsToXrp,
xrpToDrops,
@@ -20,4 +36,3 @@ export {
} from './utils'
export {default as Connection} from './connection'
export {txFlags} from './txflags'

View File

@@ -18,7 +18,6 @@ function mergeIntervals(intervals: Interval[]): Interval[] {
}
class RangeSet {
ranges: Array<[number, number]>
constructor() {
@@ -30,12 +29,13 @@ 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) {
assert(start <= end, 'invalid range')
assert.ok(start <= end, `invalid range ${start} <= ${end}`)
this.ranges = mergeIntervals(this.ranges.concat([[start, end]]))
}

View File

@@ -2,7 +2,7 @@ import * as _ from 'lodash'
import * as assert from 'assert'
const {Validator} = require('jsonschema')
import {ValidationError} from './errors'
import {isValidAddress} from 'ripple-address-codec'
import {isValidClassicAddress, isValidXAddress} from 'ripple-address-codec'
import {isValidSecret} from './utils'
function loadSchemas() {
@@ -34,6 +34,8 @@ function loadSchemas() {
require('./schemas/objects/destination-address-tag.json'),
require('./schemas/objects/transaction-hash.json'),
require('./schemas/objects/address.json'),
require('./schemas/objects/x-address.json'),
require('./schemas/objects/classic-address.json'),
require('./schemas/objects/adjustment.json'),
require('./schemas/objects/quality.json'),
require('./schemas/objects/amount.json'),
@@ -60,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'),
@@ -121,17 +125,28 @@ function loadSchemas() {
]
const titles = schemas.map(schema => schema.title)
const duplicates = _.keys(_.pickBy(_.countBy(titles), count => count > 1))
assert(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates)
assert.ok(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates)
const validator = new Validator()
// Register custom format validators that ignore undefined instances
// since jsonschema will still call the format validator on a missing
// (optional) property
validator.customFormats.address = function(instance) {
// This relies on "format": "xAddress" in `x-address.json`!
validator.customFormats.xAddress = function(instance) {
if (instance === undefined) {
return true
}
return isValidXAddress(instance)
}
// This relies on "format": "classicAddress" in `classic-address.json`!
validator.customFormats.classicAddress = function(instance) {
if (instance === undefined) {
return true
}
return isValidAddress(instance)
}
validator.customFormats.secret = function(instance) {
if (instance === undefined) {
return true
@@ -158,8 +173,8 @@ function schemaValidate(schemaName: string, object: any): void {
}
}
export {
schemaValidate,
isValidSecret,
isValidAddress
function isValidAddress(address: string): boolean {
return isValidXAddress(address) || isValidClassicAddress(address)
}
export {schemaValidate, isValidSecret, isValidAddress}

View File

@@ -20,6 +20,14 @@
"type": "string",
"enum": ["ecdsa-secp256k1", "ed25519"],
"description": "The digital signature algorithm to generate an address for. Can be `ecdsa-secp256k1` (default) or `ed25519`."
},
"test": {
"type": "boolean",
"description": "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`, the address should only be used on mainnet, and will start with `X`."
},
"includeClassicAddress": {
"type": "boolean",
"description": "If `true`, return the classic address, in addition to the X-address."
}
},
"additionalProperties": false

View File

@@ -0,0 +1,33 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "generateXAddressParameters",
"type": "object",
"properties": {
"options": {
"type": "object",
"description": "Options to control how the address and secret are generated.",
"properties": {
"entropy": {
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"description": "The entropy to use to generate the seed."
},
"algorithm": {
"type": "string",
"enum": ["ecdsa-secp256k1", "ed25519"],
"description": "The digital signature algorithm to generate an address for. Can be `ecdsa-secp256k1` (default) or `ed25519`."
},
"test": {
"type": "boolean",
"description": "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`, the address should only be used on mainnet, and will start with `X`."
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

View File

@@ -6,7 +6,7 @@
"properties": {
"address": {
"$ref": "address",
"description": "The Ripple address of the account to get the balance sheet of."
"description": "The XRP Ledger address of the account to get the balance sheet of."
},
"options": {
"properties": {

View File

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

View File

@@ -6,7 +6,7 @@
"properties": {
"address": {
"$ref": "address",
"description": "The Ripple address of the account to get open orders for."
"description": "The XRP Ledger address of the account to get open orders for."
},
"options": {
"description": "Options that determine what orders will be returned.",

View File

@@ -12,7 +12,7 @@
"properties": {
"address": {
"$ref": "address",
"description": "The Ripple address of the account where funds will come from."
"description": "The XRP Ledger address of the account where funds will come from."
},
"amount": {
"$ref": "laxAmount",
@@ -49,7 +49,7 @@
"properties": {
"address": {
"$ref": "address",
"description": "The address to send to."
"description": "An address representing the destination of the transaction."
},
"amount": {
"$ref": "laxLaxAmount",

View File

@@ -10,14 +10,14 @@
"properties": {
"minLedgerVersion": {
"$ref": "ledgerVersion",
"description": "The lowest ledger version to search."
"description": "The lowest ledger version to search. This must be an integer greater than 0, or one of the following strings: 'validated', 'closed', 'current'."
},
"maxLedgerVersion": {
"$ref": "ledgerVersion",
"description": "The highest ledger version to search"
"description": "The highest ledger version to search. This must be an integer greater than 0, or one of the following strings: 'validated', 'closed', 'current'."
},
"includeRawTransaction": {
"description": "Include raw transaction data. For advanced users; exercise caution when interpreting this data. "
"description": "Include raw transaction data. For advanced users; exercise caution when interpreting this data."
}
},
"additionalProperties": false

View File

@@ -22,7 +22,7 @@
},
"minLedgerVersion": {
"$ref": "ledgerVersion",
"description": "Return only transactions in this ledger verion or higher."
"description": "Return only transactions in this ledger version or higher."
},
"maxLedgerVersion": {
"$ref": "ledgerVersion",

View File

@@ -10,7 +10,7 @@
"secret": {
"type": "string",
"format": "secret",
"description": "The secret of the account that is initiating the transaction. (This field is exclusive with keypair)."
"description": "The secret of the account that is initiating the transaction. (This field cannot be used with keypair)."
},
"keypair": {
"type": "object",
@@ -24,7 +24,7 @@
"description": "The uppercase hexadecimal representation of the secp256k1 or Ed25519 public key."
}
},
"description": "The private and public key of the account that is initiating the transaction. (This field is exclusive with secret).",
"description": "The private and public key of the account that is initiating the transaction. (This field cannot be used with secret).",
"required": ["privateKey", "publicKey"],
"additionalProperties": false
},

View File

@@ -1,9 +1,12 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "address",
"description": "A Ripple account address",
"description": "An account address on the XRP Ledger",
"type": "string",
"format": "address",
"link": "address",
"pattern": "^r[1-9A-HJ-NP-Za-km-z]{25,34}$"
"oneOf": [
{"$ref": "xAddress"},
{"$ref": "classicAddress"}
]
}

View File

@@ -13,7 +13,7 @@
"$ref": "currency"
},
"counterparty": {
"description": "The Ripple address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\" or \"drops\")",
"description": "The XRP Ledger address of the account that owes or is owed the funds (omitted if `currency` is \"XRP\" or \"drops\")",
"$ref": "address"
}
},

View File

@@ -14,7 +14,7 @@
"$ref": "currency"
},
"counterparty": {
"description": "The Ripple address of the account that owes or is owed the funds.",
"description": "The XRP Ledger address of the account that owes or is owed the funds.",
"$ref": "address"
}
},

View File

@@ -0,0 +1,9 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "classicAddress",
"description": "A classic address (Account ID) for the XRP Ledger",
"type": "string",
"format": "classicAddress",
"link": "classic-address",
"pattern": "^r[1-9A-HJ-NP-Za-km-z]{24,34}$"
}

View File

@@ -6,7 +6,7 @@
"properties": {
"address": {
"$ref": "address",
"description": "The address to receive at."
"description": "An address representing the destination of the transaction."
},
"tag": {"$ref": "tag"}
},

View File

@@ -5,7 +5,7 @@
"properties": {
"address": {
"$ref": "address",
"description": "The address to receive at."
"description": "An address representing the destination of the transaction."
},
"amount": {
"$ref": "laxAmount",

View File

@@ -10,7 +10,7 @@
"$ref": "sequence"
},
"fee": {
"description": "An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information.",
"description": "An exact fee to pay for the transaction, before multiplying for multi-signed transactions. See [Transaction Fees](#transaction-fees) for more information.",
"$ref": "value"
},
"maxFee": {
@@ -18,7 +18,7 @@
"$ref": "value"
},
"maxLedgerVersion": {
"description": "The highest ledger version that the transaction can be included in. If this option and `maxLedgerVersionOffset` are both omitted, the `maxLedgerVersion` option will default to 3 greater than the current validated ledger version (equivalent to `maxLedgerVersionOffset=3`). Use `null` to not set a maximum ledger version.",
"description": "The highest ledger version that the transaction can be included in. If this option and `maxLedgerVersionOffset` are both omitted, the `maxLedgerVersion` option will default to 3 greater than the current validated ledger version (equivalent to `maxLedgerVersionOffset=3`). Use `null` to not set a maximum ledger version. If not null, this must be an integer greater than 0, or one of the following strings: 'validated', 'closed', 'current'.",
"oneOf": [
{"$ref": "ledgerVersion"},
{"type": "null"}

View File

@@ -9,7 +9,7 @@
},
"maxAmount": {
"$ref": "laxAmount",
"description": "The maximum amount to send. (This field is exclusive with source.amount)"
"description": "The maximum amount to send. (This field cannot be used with source.amount)"
},
"tag": {"$ref": "tag"}
},

View File

@@ -5,11 +5,11 @@
"properties": {
"address": {
"$ref": "address",
"description": "The address to send to."
"description": "An address representing the destination of the transaction."
},
"minAmount": {
"$ref": "laxAmount",
"description": "The minimum amount to be delivered. (This field is exclusive with destination.amount)"
"description": "The minimum amount to be delivered. (This field cannot be used with destination.amount)"
},
"tag": {"$ref": "tag"}
},

View File

@@ -13,7 +13,7 @@
},
"disableMasterKey": {
"type": "boolean",
"description": "Disallows use of the master key to sign transactions for this account."
"description": "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": {
"type": "boolean",
@@ -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 accounts most recent transaction."
@@ -94,15 +101,19 @@
"maxItems": 8
}
},
"required": ["threshold", "weights"],
"required": ["threshold"],
"additionalProperties": false
},
"transferRate": {
"description": " The fee to charge when users transfer this accounts 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.",
"description": "The fee to charge when users transfer this accounts 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.",
"oneOf": [
{"type": "null"},
{"type": "number", "minimum": 1, "maximum": 4.294967295}
]
},
"tickSize": {
"description": "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.",
"enum": [0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
}
},
"additionalProperties": false

View File

@@ -9,7 +9,7 @@
},
"amount": {
"$ref": "laxAmount",
"description": "An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field is exclusive with source.maxAmount)"
"description": "An exact amount to send. If the counterparty is not specified, amounts with any counterparty may be used. (This field cannot be used with source.maxAmount)"
},
"tag": {"$ref": "tag"}
},

View File

@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "tag",
"description": "An arbitrary unsigned 32-bit integer that identifies a reason for payment or a non-Ripple account.",
"description": "An arbitrary 32-bit unsigned integer. It typically maps to an off-ledger account; for example, a hosted wallet or exchange account.",
"type": "integer",
"$ref": "uint32"
}

View File

@@ -18,6 +18,8 @@
"paymentChannelClaim",
"checkCreate",
"checkCancel",
"checkCash"
"checkCash",
"depositPreauth",
"accountDelete"
]
}

View File

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

View File

@@ -0,0 +1,9 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "xAddress",
"description": "An XRP Ledger address in X-address format",
"type": "string",
"format": "xAddress",
"link": "x-address",
"pattern": "^[XT][1-9A-HJ-NP-Za-km-z]{46}$"
}

View File

@@ -3,16 +3,24 @@
"title": "generateAddress",
"type": "object",
"properties": {
"xAddress": {
"$ref": "xAddress",
"description": "A randomly generated XRP Ledger address in X-address format."
},
"classicAddress": {
"$ref": "classicAddress",
"description": "A randomly generated XRP Ledger Account ID (classic address)."
},
"address": {
"$ref": "address",
"description": "A randomly generated Ripple account address."
"$ref": "classicAddress",
"description": "Deprecated: Use `classicAddress` instead."
},
"secret": {
"type": "string",
"format": "secret",
"description": "The secret corresponding to the `address`."
"description": "The secret corresponding to the address."
}
},
"required": ["address", "secret"],
"required": ["xAddress", "classicAddress", "address", "secret"],
"additionalProperties": false
}

View File

@@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "generateXAddress",
"type": "object",
"properties": {
"xAddress": {
"$ref": "xAddress",
"description": "A randomly generated XRP Ledger address in X-address format."
},
"secret": {
"type": "string",
"format": "secret",
"description": "The secret corresponding to the address."
}
},
"required": ["xAddress", "secret"],
"additionalProperties": false
}

View File

@@ -31,7 +31,7 @@
},
"threads": {
"type": "number",
"description": "*(Admin only)* The number of threads in the servers main job pool, performing various Ripple Network operations."
"description": "*(Admin only)* The number of threads in the servers main job pool, performing various operations."
}
},
"required": ["jobTypes", "threads"]
@@ -70,7 +70,7 @@
},
"serverState": {
"type": "string",
"description": "A string indicating to what extent the server is participating in the network. See [Possible Server States](https://ripple.com/build/rippled-apis/#possible-server-states) for more details.",
"description": "A string indicating to what extent the server is participating in the network. See [Possible Server States](https://developers.ripple.com/rippled-server-states.html) for more details.",
"enum": ["disconnected", "connected", "syncing", "tracking", "full", "validating", "proposing"]
},
"validatedLedger": {

View File

@@ -208,6 +208,30 @@
"$ref": "paymentChannelClaim"
}
}
},
{
"properties": {
"type": {
"enum": [
"depositPreauth"
]
},
"specification": {
"$ref": "depositPreauth"
}
}
},
{
"properties": {
"type": {
"enum": [
"accountDelete"
]
},
"specification": {
"$ref": "accountDelete"
}
}
}
]
}

View File

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

View File

@@ -14,7 +14,7 @@
"properties": {
"fee": {
"$ref": "value",
"description": "An exact fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information."
"description": "The fee to pay for the transaction. See [Transaction Fees](#transaction-fees) for more information. For multi-signed transactions, this fee will be multiplied by (N+1), where N is the number of signatures you plan to provide."
},
"sequence": {
"$ref": "sequence",
@@ -25,7 +25,7 @@
{"$ref": "ledgerVersion"},
{"type": "null"}
],
"description": "The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum."
"description": "The highest ledger version that the transaction can be included in. Set to `null` if there is no maximum. If not null, this must be an integer greater than 0, or one of the following strings: 'validated', 'closed', 'current'."
}
},
"additionalProperties": false,

View File

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

View File

@@ -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
}

View 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
}

View File

@@ -1,35 +1,36 @@
import * as _ from 'lodash'
import {convertKeysFromSnakeCaseToCamelCase} from './utils'
import BigNumber from 'bignumber.js'
import {RippleAPI} from '../index'
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}

View File

@@ -58,7 +58,4 @@ const txFlagIndices = {
}
}
export {
txFlags,
txFlagIndices
}
export {txFlags, txFlagIndices}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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'

View 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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -1,11 +1,7 @@
export type Amount = {
value: string,
currency: string,
issuer?: string,
counterparty?: string
export interface Amount extends Issue {
value: string
}
export type RippledAmount = string | Amount
/**
@@ -21,8 +17,8 @@ export interface TakerRequestAmount {
/**
* A currency-counterparty pair, or just currency if it's XRP.
*/
export type Issue = {
currency: string,
issuer?: string,
export interface Issue {
currency: string
issuer?: string
counterparty?: string
}

View File

@@ -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'

Some files were not shown because too many files have changed in this diff Show More