Compare commits

...

317 Commits

Author SHA1 Message Date
Geert Weening
57ecbc58f8 bump version to 0.13.0-rc14 2015-10-07 11:42:08 -07:00
Geert Weening
ea4d1007b8 Merge branch 'release' into develop 2015-10-07 11:17:36 -07:00
Geert Weening
16bc7b986b Bump version to 0.13.0-rc13 2015-10-07 11:14:39 -07:00
Geert Weening
115f95fa96 update release notes 2015-10-07 11:14:01 -07:00
Chris Clark
b77b76ebb5 Merge pull request #586 from darkdarkdragon/develop-log-fix
get back lost argument in debug logger
2015-10-07 10:20:01 -07:00
Ivan Tivonenko
f516298a84 get back lost argument in debug logger 2015-10-07 11:43:17 +03:00
Chris Clark
edb31a0c9c Merge pull request #584 from darkdarkdragon/develop-RLJS-521
Add Remote.closeCurrentPathFind function, so current pathfind can be …
2015-10-06 18:40:25 -07:00
Ivan Tivonenko
e99010f363 Add Remote.closeCurrentPathFind function, so current pathfind can be properly closed,
so new can be created without adding to queue
2015-10-07 04:10:13 +03:00
Chris Clark
fa865f8409 Merge pull request #580 from FrRichard/patch-1
Update REFERENCE.md
2015-10-06 17:43:47 -07:00
FrRichard
40b613b7a2 Update REFERENCE.md
Update REFERENCE.md

Update REFERENCE.md
2015-10-07 02:29:17 +02:00
Chris Clark
a79b010572 Merge pull request #576 from shekenahglory/develop
allow offers request on orderbook subscribe when disconnected
2015-10-06 14:09:25 -07:00
Matthew Fettig
7404795dc6 fix bugs in orderbook subscription 2015-10-06 13:59:21 -07:00
Chris Clark
47a9fb5803 Merge pull request #583 from clark800/fix-merge-error
Fix merge error
2015-10-06 12:54:41 -07:00
Chris Clark
701d4c5722 Fix merge error 2015-10-06 12:47:26 -07:00
Chris Clark
d8d6f945ec Merge pull request #581 from clark800/binary-codec
Decouple UInt from non-serialization code
2015-10-05 16:39:17 -07:00
Geert Weening
a6821bb8ab Fix bower version regex 2015-10-05 15:58:49 -07:00
Geert Weening
ed40eec711 Bump version to 0.13.0-rc12 2015-10-05 15:38:20 -07:00
Chris Clark
2f163c3b6e Decouple UInt from non-serialization code 2015-10-05 15:27:43 -07:00
Geert Weening
43488c55f1 Update release notes 2015-10-05 15:07:31 -07:00
Geert Weening
2f727b553c Merge branch 'develop' into release 2015-10-05 15:04:18 -07:00
Chris Clark
29c37aa6da Merge pull request #579 from wltsmrz/balance-sheet
Balance sheet
2015-10-05 13:41:24 -07:00
wltsmrz
64baef431d Use amount schema 2015-10-05 13:37:55 -07:00
Chris Clark
634fe5683a Merge pull request #577 from darkdarkdragon/develop-reconnect-2
remove Request resubmit logic
2015-10-05 13:28:47 -07:00
Ivan Tivonenko
225ca3f852 BREAKING CHANGE: removed 'timeout' method of Request
added default timeout to Request - will emit 'timeout' event
and RippleError('tejTimeout') to callback
2015-10-05 23:22:32 +03:00
wltsmrz
ff2ac6c3cd Format balancesheet schema 2015-10-05 13:09:04 -07:00
wltsmrz
607777f2a3 Lint 2015-10-05 12:30:41 -07:00
wltsmrz
78eeb40322 Change rippled test fixture name 2015-10-05 12:23:22 -07:00
wltsmrz
772f79ae21 Update schema 2015-10-05 12:16:25 -07:00
wltsmrz
806a4e823f Add getBalanceSheet() to RippleAPI 2015-10-02 17:30:13 -07:00
wltsmrz
323e402e0c Add requestGatewayBalances() to core 2015-10-02 17:30:04 -07:00
Chris Clark
9ebb59580d Merge pull request #575 from clark800/get-paths-source-amount
Support source.amount in getPaths and destination.minAmount in preparePayment
2015-10-02 13:30:04 -07:00
wltsmrz
bafab6eb18 Merge pull request #574 from clark800/fix-ratio-human
Fix bug in Amount.ratio_human
2015-10-01 15:18:20 -07:00
Chris Clark
35acbb62c3 Support source.amount in getPaths and destination.minAmount in preparePayment 2015-10-01 14:55:11 -07:00
Chris Clark
4676ade4ee Fix bug in Amount.ratio_human 2015-10-01 11:58:09 -07:00
wltsmrz
8edc3b1f36 Merge pull request #572 from darkdarkdragon/develop-request-once
throw error if Request.request called more than once
2015-09-30 12:00:06 -07:00
Chris Clark
8acfb1a537 Merge pull request #546 from darkdarkdragon/develop-async
make Remote.getLedgerSequence asynchronous
2015-09-30 11:18:49 -07:00
Ivan Tivonenko
ac78171099 make orderbook use Remote.getLedgerSequenceSync
fix some variables naming in src/api
2015-09-30 07:46:30 +03:00
Ivan Tivonenko
d573c5746b refactor getLedgerVersionHelper 2015-09-30 07:07:46 +03:00
Ivan Tivonenko
51e8f9a87a make Remote.getLedgerSequence asynchronous 2015-09-30 07:05:39 +03:00
Ivan Tivonenko
bfe590d96d copy message from Error instance into RippleError 2015-09-30 06:34:58 +03:00
Ivan Tivonenko
60e2d10775 throw error if Request.request called more than once 2015-09-30 06:29:07 +03:00
Chris Clark
2f432cef62 Merge pull request #571 from clark800/fix-pathfind-queue
Fix pathfind queuing and add unit test
2015-09-29 15:22:38 -07:00
Chris Clark
5217b66396 Fix pathfind queuing and add unit test 2015-09-29 12:54:23 -07:00
Chris Clark
b8bb191d24 Merge pull request #566 from clark800/refactor
Decouple UInt160 from account.js and amount.js
2015-09-28 14:15:50 -07:00
Chris Clark
8070a52dc7 Merge pull request #568 from ripple/revert-max-ledger
Revert "Set default maxLedgerVersion to last closed ledger when reque…
2015-09-28 13:27:57 -07:00
wltsmrz
3205f3cf8c Merge pull request #570 from darkdarkdragon/develop-before-once
make sure that 'before' event emitted from Request only once
2015-09-28 12:06:15 -07:00
Alan Cohen
e0cdd610dd Set default max ledger to -1 when requesting account_tx
-1 means up to the most recent available _validated_ ledger for ledger_index_max

account_tx operates only on valided ledgers
2015-09-28 10:35:33 -07:00
Ivan Tivonenko
ed3b04ed6f make sure that 'before' event emitted from Request only once 2015-09-28 03:00:59 +03:00
Alan Cohen
62a2d2ae39 Revert "Set default maxLedgerVersion to last closed ledger when requesting account_tx"
This reverts commit 90b53002aa.

account_tx operates against validated ledgers only
2015-09-25 20:18:36 -07:00
Geert Weening
e2c853e40d Bump version to 0.13.0-rc11 2015-09-25 17:05:22 -07:00
Geert Weening
b9b5a71869 Update release notes 2015-09-25 17:01:58 -07:00
Geert Weening
87fdbc932f Merge pull request #567 from clark800/fix-crash
Fix crash due to rippled slowDown error
2015-09-25 16:59:42 -07:00
Chris Clark
84838b2e9f Fix crash due to rippled slowDown error 2015-09-25 16:41:37 -07:00
Chris Clark
c2ca37a790 Fix lint errors in meta.js and serializedtypes.js 2015-09-25 12:42:13 -07:00
Chris Clark
c6805b9f0d Decouple UInt160 from amount.js 2015-09-25 12:42:13 -07:00
Chris Clark
b1dbdc03dd Decouple UInt160 from account.js 2015-09-25 12:42:10 -07:00
Chris Clark
88a3f3d43b Merge pull request #565 from clark800/value
Use ripple-lib-value package and update ripple-lib-transactionparser dependency
2015-09-25 12:39:03 -07:00
Chris Clark
5f8dcd71a5 Merge pull request #564 from darkdarkdragon/develop-master-merge-2
Merge branch 'master' into develop
2015-09-24 13:58:11 -07:00
Ivan Tivonenko
45db95da79 put back UInt160 in AutobridgeCalculator
fix lint issues
2015-09-24 23:49:32 +03:00
Chris Clark
c79b12b27f Use ripple-lib-value package and update ripple-lib-transactionparser dependency 2015-09-24 12:32:15 -07:00
Chris Clark
135da6108d Merge pull request #563 from clark800/keypairs
Move to new ripple-keypairs API
2015-09-24 11:53:20 -07:00
Ivan Tivonenko
0d6dda579f Merge branch 'master' into develop 2015-09-24 20:04:18 +03:00
Chris Clark
e641a347db Merge pull request #561 from darkdarkdragon/master-performance-2
more OrderBook performance optimizations
2015-09-23 17:14:44 -07:00
Ivan Tivonenko
3e17d91edf more OrderBook performance optimizations
OrderBook: emit 'model' event only after last transaction in closed ledger
run AutobridgeCalculator only once in a ledger
2015-09-24 02:50:48 +03:00
Chris Clark
715c648d52 Move to new ripple-keypairs API 2015-09-23 14:30:56 -07:00
Geert Weening
d0ebed9822 bump version to 0.12.8 2015-09-23 11:51:42 -07:00
Geert Weening
a3775f18ba update release notes 2015-09-23 11:51:29 -07:00
wltsmrz
7b5d6e9fc5 Merge pull request #562 from wltsmrz/add-reconnect-test
Add test for Server automatic reconnection
2015-09-22 21:52:11 -07:00
wltsmrz
368ac0b9e0 Merge pull request #560 from wltsmrz/fix-connect-when-already-connected
Always call Remote.connect() callback
2015-09-22 21:51:30 -07:00
wltsmrz
0448696bd8 Merge pull request #552 from wltsmrz/update-multisigning
Autofill LastLedgerSequence for multisigned transactions
2015-09-22 21:50:53 -07:00
wltsmrz
deb75ed0d7 Add test for Server automatic reconnection 2015-09-22 19:48:25 -07:00
Geert Weening
fcc9bacb4e bump version to 0.13.0-rc10 2015-09-22 18:33:48 -07:00
wltsmrz
9a5e8fd2ba Merge pull request #558 from clark800/wss
Add pattern for servers option
2015-09-22 18:25:17 -07:00
wltsmrz
1c023c4377 Always call Remote.connect() callback
Fixes non-resolving Promise in RippleAPI.connect()
2015-09-22 18:22:28 -07:00
Chris Clark
c213b98329 Add pattern for servers option 2015-09-21 17:34:39 -07:00
Alan Cohen
27d2e6e519 Merge pull request #557 from clark800/ledger-close
Add ledgerClosed event
2015-09-21 15:33:44 -07:00
Chris Clark
7ee368965c Add ledgerClosed event 2015-09-21 14:38:51 -07:00
Alan Cohen
d8b5b825b3 Update verison to 0.13.0-rc9 2015-09-21 10:48:03 -07:00
wltsmrz
de67570230 Autofill LastLedgerSequence for multisigned transactions 2015-09-21 10:26:00 -07:00
Chris Clark
60c604fbe6 Merge pull request #536 from sentientwaffle/dj/suspay
suspended payments
2015-09-18 10:58:10 -07:00
sentientwaffle
2f6d25ed01 lint 2015-09-18 10:52:00 -07:00
sentientwaffle
b134081293 Add SuspendedPayment{Create,Finish,Cancel}
* Add SusPay core tests
* Rename SusPay -> SuspendedPayment (code review)
* Rename cancelAfter -> allowCancelAfter
* Rename suspendedPayment{Finish,Execution}
2015-09-18 10:51:34 -07:00
Chris Clark
a0528d7f9c Merge pull request #553 from darkdarkdragon/develop-master-merge
Merge OrderBook optimizations from master to develop
2015-09-18 10:41:22 -07:00
Alan Cohen
348335ddf0 Merge pull request #556 from clark800/tel-fix
Remove "tel" errors from submit's immediate failure category
2015-09-17 17:20:42 -07:00
Ivan Tivonenko
01752e5486 fix eslint errors 2015-09-18 03:15:09 +03:00
Chris Clark
3e758e1b86 Remove "tel" errors from submit's immediate failure category 2015-09-17 17:06:12 -07:00
Chris Clark
fb0b30a9a7 Merge pull request #555 from lumberj/add-data-to-error
RippleAPI: Add data property to error object
2015-09-17 16:29:12 -07:00
Alan Cohen
0c9aea454e RippleAPI: Add data property to error object 2015-09-17 16:05:43 -07:00
Geert Weening
f282585c3f Bump version to 0.12.7
bump dependencies and regenerate shrinkwrap
2015-09-17 10:30:23 -07:00
Geert Weening
ae5ff31c96 Update release notes 2015-09-17 10:20:52 -07:00
Ivan Tivonenko
20fa8bc953 optimize AutobridgeCalculator and Amount for speed 2015-09-17 19:06:47 +03:00
Alan Cohen
778f59b4fd Merge pull request #535 from clark800/submit-error
Return promise error if submit result is an immediate failure
2015-09-16 17:53:35 -07:00
Chris Clark
49623cb4dd Merge pull request #550 from lumberj/max-ledger-sequence
Set default maxLedgerVersion to last closed ledger when requesting ac…
2015-09-16 17:11:11 -07:00
Alan Cohen
90b53002aa Set default maxLedgerVersion to last closed ledger when requesting account_tx 2015-09-16 16:45:25 -07:00
Alan Cohen
93c12af305 Merge pull request #548 from lumberj/check-disjoint
Add PendingLedgerVersionError
2015-09-16 16:29:46 -07:00
Alan Cohen
60f2419b5c Add PendingLedgerVersionError
MissingLedgerHistoryError - no minLedgerVersion or maxLedgerVersion
There is a ledger gap, but a range should be provided to narrow down the range
of the gap.

MissingLedgerHistoryError
When requesting a tx, if maxLedgerVersion and minLedgerVersion provided, this
means there is a ledger gap in the provided range.

PendingLedgerVersionError:
If maxLedgerVersion provided, check if ledger is ahead of the server's last
validated ledger.
2015-09-16 15:57:55 -07:00
Chris Clark
80494ad813 Return promise error if submit result is an immediate failure 2015-09-16 15:56:24 -07:00
Alan Cohen
b43c4a7ad4 Merge pull request #549 from lumberj/validated-tx
Do not return non-validated transaction from RippleAPI#getTransaction
2015-09-16 12:29:23 -07:00
Alan Cohen
3c608de5bb Do not return non-validated transaction from RippleAPI#getTransaction 2015-09-16 12:19:20 -07:00
Chris Clark
fe5bc1d215 Merge pull request #538 from darkdarkdragon/develop-negative-error
shows event that leads to "Offer total cannot be negative" error
2015-09-16 10:26:19 -07:00
Ivan Tivonenko
580bf9a755 shows event that leads to "Offer total cannot be negative" error 2015-09-16 09:57:51 +03:00
Ivan Tivonenko
c7df5df163 make tests pass 2015-09-15 09:14:12 +03:00
Ivan Tivonenko
a08c52af55 Merge branch 'master' into develop-master-merge 2015-09-15 06:29:26 +03:00
Chris Clark
e11db0f0f3 Merge pull request #547 from vhpoet/develop
Remote: Add LowFreeze, HighFreeze flags
2015-09-14 16:59:20 -07:00
Vahe Hovhannisyan
c6e0582729 Remote: Add LowFreeze, HighFreeze flags 2015-09-14 16:57:13 -07:00
wltsmrz
6e98629f9b Merge pull request #543 from darkdarkdragon/develop-reconnect
resend request in case server was disconnected after request was sent
2015-09-13 02:14:22 -07:00
sublimator
2243760442 Merge pull request #541 from wltsmrz/add-tecOVERSIZE
Add tecOVERSIZE transaction result
2015-09-13 16:11:26 +07:00
wltsmrz
91dd6877aa Add tecOVERSIZE transaction result 2015-09-13 02:07:53 -07:00
sublimator
e73bcd8fc1 Merge pull request #545 from wltsmrz/add-multisign
Add multisign helpers
2015-09-13 15:10:19 +07:00
wltsmrz
7e886b3260 Add multisign helpers 2015-09-13 00:59:27 -07:00
Ivan Tivonenko
5c9451d3ed allow Request.request(callback) 2015-09-12 22:18:52 +03:00
wltsmrz
c6c2dcc6c0 Merge pull request #533 from clark800/webpack-net-fix
Fix browser build
2015-09-11 13:15:58 -07:00
wltsmrz
0bdd37090e Merge pull request #537 from darkdarkdragon/master-performance
Optimize performance (for 0.12 master branch)
2015-09-10 17:04:16 -07:00
Ivan Tivonenko
c745faaaf0 optimize baseconverter , OrderBook and AutobridgeCalculator for speed 2015-09-11 02:34:48 +03:00
Alan Cohen
9ad03ca873 Bump version to 0.13.0-rc8 2015-09-09 13:22:18 -07:00
wltsmrz
138914384e Merge pull request #531 from clark800/fix-pathfind-queue
Fix queueing of pathfind requests
2015-09-09 13:09:34 -07:00
Ivan Tivonenko
77068667e4 move reconnect logic from Request.callback to Request.request 2015-09-09 21:16:10 +03:00
Ivan Tivonenko
c57cef4a21 resend request in case server was disconnected after request was sent 2015-09-09 02:22:02 +03:00
Alan Cohen
50acc4c708 Merge pull request #542 from lumberj/fix-destination_currencies
Fix: Check for destination_currencies property
2015-09-08 16:04:54 -07:00
Alan Cohen
b5f8ba4817 Fix: Check for destination_currencies property
Example stack:

TypeError: Cannot read property 'join' of undefined
    at formatResponse
    (ripple-lib/dist/npm/api/ledger/pathfind.js:75:187)
2015-09-08 16:02:23 -07:00
Alan Cohen
a53249ccd7 Bump version to 0.13.-rc7 2015-09-03 14:04:07 -07:00
Ivan Tivonenko
0c62fa2112 remove Firefox warning about prototype overwrite 2015-09-01 01:34:59 +03:00
Ivan Tivonenko
806547dd15 fix Amount compare bug
return 0 if values not comparable
2015-09-01 01:29:37 +03:00
Chris Clark
fb1669b2b3 Merge pull request #534 from clark800/prepare
Return instructions in prepare responses
2015-08-28 15:31:59 -07:00
Chris Clark
0cda15f2b5 Update is-my-json-valid depedency to fix webpack issue 2015-08-28 14:18:02 -07:00
Chris Clark
b88e9370c6 Return instructions in prepare responses 2015-08-28 14:11:02 -07:00
Chris Clark
e343f3beb8 Remove usage of fs module because it does not work in browser 2015-08-28 11:53:45 -07:00
Chris Clark
a13bfae714 Merge pull request #528 from mDuo13/min_value_abs
remove redundant abs from MIN_IOU_VALUE
2015-08-27 14:27:33 -07:00
mDuo13
877c6bbb2a amount min/max - more tests 2015-08-27 14:06:47 -07:00
Chris Clark
30d5134394 Fix require failure in browser code due to proxy library 2015-08-27 11:57:15 -07:00
Chris Clark
fae5c74487 Merge pull request #530 from clark800/remove-methods
Remove computeLedgerHash and isValidAddress from API
2015-08-26 17:57:15 -07:00
Chris Clark
255332ea2e Fix queueing of pathfind requests 2015-08-26 17:38:11 -07:00
Chris Clark
15c0e6db19 Remove computeLedgerHash and isValidAddress from API 2015-08-26 17:19:09 -07:00
mDuo13
2b600a1e4e more amount minimum abs test fixes 2015-08-26 12:26:47 -07:00
mDuo13
297fb2483d fix test for amount min 2015-08-25 17:38:32 -07:00
mDuo13
5049822415 remove redundant abs from MIN_IOU_VALUE 2015-08-25 17:14:33 -07:00
Chris Clark
e3787e0f4f Merge pull request #527 from clark800/fix-getpaths
Use maxAmount in getPaths results so they can be passed to preparePayment
2015-08-25 15:18:21 -07:00
Chris Clark
683199044b Use maxAmount in getPaths results so they can be passed to preparePayment 2015-08-25 15:14:06 -07:00
sublimator
4f3c3e9f66 Merge pull request #524 from wltsmrz/deprecate-positional-api
Deprecate positional request constructor API
2015-08-25 20:52:59 +07:00
wltsmrz
fc0240c06b Deprecate positional request constructor API 2015-08-25 06:42:47 -07:00
sublimator
6bfa284bac Merge pull request #526 from sublimator/update-legacy-support
Update legacy-support & JSDoc comments
2015-08-25 20:18:06 +07:00
Nicholas Dudfield
dfee9bc578 Update legacy-support & JSDoc comments 2015-08-25 20:14:14 +07:00
Chris Clark
0838a0e865 Merge pull request #525 from clark800/test-compiled
Fix testing of compiled library
2015-08-24 17:57:50 -07:00
Chris Clark
5f61d80e2d Fix bugs in compiled library 2015-08-24 17:38:30 -07:00
Chris Clark
c4fa4c237c Compile test cases to run tests without using Babel 2015-08-24 16:58:50 -07:00
Geert Weening
44d00d5ef4 Bump version to 0.13.0-rc6 2015-08-24 14:24:48 -07:00
Geert Weening
d4d3efcb65 Update releas notes 2015-08-24 14:24:40 -07:00
Geert Weening
f23e105240 Merge branch 'develop' into release 2015-08-24 13:47:00 -07:00
Chris Clark
5a396a7060 Merge pull request #517 from darkdarkdragon/develop-RLJS-463
Add schema for RippleAPI constructor options
2015-08-24 11:39:21 -07:00
Ivan Tivonenko
513632299f Add schema for RippleAPI constructor options 2015-08-24 21:29:50 +03:00
Chris Clark
0d40558f1e Merge pull request #522 from clark800/srcActNotFound-pathfind
Fix: Emit error events and return error on pathfind
2015-08-21 14:26:19 -07:00
Alan Cohen
1ccbaf6776 Fix: Emit error events and return error on pathfind 2015-08-21 14:24:13 -07:00
sublimator
ba6c703163 Merge pull request #518 from darkdarkdragon/develop-RLJS-467
Allow to specify server url without explicit port number
2015-08-21 20:41:25 +07:00
sublimator
3b9eb02bbb Merge pull request #520 from sublimator/ledger-select
Update ledgerSelect to throw if ledger arg is unrecognized
2015-08-21 17:34:35 +07:00
Nicholas Dudfield
bca7382015 Update ledgerSelect to throw if ledger arg is unrecognized 2015-08-21 15:31:14 +07:00
wltsmrz
67672bd389 Merge pull request #519 from sublimator/hackz
Move positional args wrappers into legacy-support module
2015-08-21 14:19:50 +07:00
Nicholas Dudfield
232017d9a2 Move positional args wrappers into legacy-support module 2015-08-21 14:06:32 +07:00
Ivan Tivonenko
23653f67f0 Allow to specify server url without explicit port number 2015-08-21 06:39:48 +03:00
Chris Clark
e3b688d1dd Merge pull request #516 from darkdarkdragon/develop-server-info-schema-fix
fix get-server-info.json schema
2015-08-20 17:40:03 -07:00
Ivan Tivonenko
a94b21ca3c fix get-server-info.json schema 2015-08-21 03:36:04 +03:00
Geert Weening
9c9be3e6e4 Bump version to 0.13.0-rc5 2015-08-20 13:46:11 -07:00
Chris Clark
062561686e Update release notes 2015-08-20 11:49:04 -07:00
Geert Weening
761682c206 Merge branch 'develop' into release 2015-08-20 10:18:22 -07:00
Chris Clark
39c48d631c Merge pull request #513 from darkdarkdragon/develop-parse-trustline-fix
fix parseTrustline for case when no QualityIn or QualityOut are set i…
2015-08-19 11:20:32 -07:00
Ivan Tivonenko
a55d26a726 fix parseTrustline for case when no QualityIn or QualityOut are set in transaction 2015-08-19 21:17:50 +03:00
Chris Clark
597ae157b3 Merge pull request #515 from darkdarkdragon/develop-isvalidaddress-fix
in isValidAddress check that address starting with 'r'
2015-08-19 10:56:40 -07:00
wltsmrz
c1c7458914 Merge pull request #514 from sublimator/eslint-1.2.0
Update eslint to 1.2.0
2015-08-19 16:28:14 +07:00
Ivan Tivonenko
0e97f269ab in isValidAddress check that address starting with 'r'
because UInt160 considers valid hex values
2015-08-19 05:26:08 +03:00
Nicholas Dudfield
bbe4cd63a1 Update eslint to 1.2.0 2015-08-19 08:41:35 +07:00
Chris Clark
2515d17a85 Merge pull request #509 from clark800/generate-address
Rename generateWallet to generateAddress
2015-08-18 18:11:22 -07:00
Chris Clark
d8e95a3c3b Rename generateWallet to generateAddress 2015-08-18 17:44:10 -07:00
Chris Clark
98f6bed8c9 Merge pull request #511 from darkdarkdragon/develop-filter-fix
fix transactionFilter
2015-08-18 17:21:17 -07:00
Ivan Tivonenko
bd000c2662 fix transactionFilter 2015-08-19 03:15:10 +03:00
Chris Clark
a46141111a Merge pull request #512 from clark800/validate-address
Add isValidAddress
2015-08-18 14:48:44 -07:00
Chris Clark
f57c89c6e9 Add isValidAddress 2015-08-18 14:46:11 -07:00
Chris Clark
6d4cac948d Merge pull request #504 from clark800/get-ledger
Add getLedger method, remove getLedgerHeader method
2015-08-18 10:01:22 -07:00
Chris Clark
1f54b3a0cf Rename ledger "account" to "state" 2015-08-17 18:41:22 -07:00
Chris Clark
2f8655dc23 Add getLedger method, remove getLedgerHeader method 2015-08-17 18:39:34 -07:00
sublimator
d624923cd8 Merge pull request #510 from clark800/underscore-fixes
Fix snake case method calls
2015-08-18 07:33:56 +07:00
Chris Clark
2180c076dd Fix snake case method calls 2015-08-17 17:28:16 -07:00
Chris Clark
0dbdf0a21a Merge pull request #503 from darkdarkdragon/develop-RLJS-444-01
annotate api functions with types
2015-08-17 14:34:12 -07:00
Ivan Tivonenko
5cb63a258c annotate api functions with types 2015-08-17 20:51:03 +03:00
Chris Clark
39ac6caaef Merge pull request #506 from sublimator/uint-scraggles
Remove UInt#from_bn
2015-08-17 10:04:18 -07:00
Chris Clark
de4ef8b2b4 Merge pull request #505 from sublimator/reserve
[WIP] Fix reserve calculation
2015-08-17 10:01:10 -07:00
Nicholas Dudfield
99cba09a4a Remove UInt#from_bn 2015-08-16 21:31:46 +07:00
Nicholas Dudfield
300967f0f3 [WIP] Fix lint issues 2015-08-15 18:15:36 +07:00
Nicholas Dudfield
52879febb9 [WIP] Fix reserve calculation 2015-08-15 18:11:43 +07:00
Chris Clark
f077a563c4 Merge pull request #498 from clark800/compute-ledger-hash
Add computeLedgerHash method
2015-08-14 14:43:57 -07:00
Chris Clark
92fbc61f47 Add computeLedgerHash method 2015-08-14 14:25:56 -07:00
Chris Clark
5ac1bcc414 Merge pull request #502 from sublimator/hash.js
Remove sjcl-extended/ripple-wallet-generator. Use hash.js & sjcl-codec.
2015-08-14 11:14:33 -07:00
Nicholas Dudfield
5837aa23ea Remove sjcl-extended/ripple-wallet-generator. Use hash.js & sjcl-codec. 2015-08-14 09:31:49 +07:00
Chris Clark
8c431b4ec3 Merge pull request #499 from clark800/validated-ledger
Get validated ledger in getSettings and getAccountInfo
2015-08-13 13:20:55 -07:00
sublimator
25086a7944 Merge pull request #501 from sublimator/bn.js
Replace sjcl.bn with bn.js
2015-08-14 01:38:13 +07:00
Nicholas Dudfield
b0889b4afe Replace sjcl.bn with bn.js 2015-08-14 01:33:59 +07:00
wltsmrz
ed971bc41c Merge pull request #500 from clark800/get-ledger-header
Add getLedgerHeader method
2015-08-13 07:57:45 +07:00
Chris Clark
728595dc96 Add getLedgerHeader method 2015-08-12 17:37:13 -07:00
Chris Clark
7fc6adb776 Get validated ledger in getSettings and getAccountInfo 2015-08-12 15:58:47 -07:00
Chris Clark
002102ce62 Merge pull request #494 from clark800/streaming-pathfinding
Use streaming pathfinding: rippled path_find instead of ripple_path_find
2015-08-12 13:14:13 -07:00
Chris Clark
bf9da80d46 Fix lint errors in remote.js and pathfind.js 2015-08-12 12:34:12 -07:00
Chris Clark
dda9994869 Use streaming pathfinding: rippled path_find instead of ripple_path_find 2015-08-12 12:34:08 -07:00
sublimator
4c76ad159e Merge pull request #495 from sublimator/ripple-keypairs
Use ripple-keypairs and ripple-address-codec
2015-08-12 13:01:56 +07:00
Nicholas Dudfield
f76a8daca8 Update babel, eslint & co 2015-08-12 12:54:33 +07:00
Nicholas Dudfield
3263629ebe Use ripple-keypairs and ripple-address-codec 2015-08-12 12:54:30 +07:00
Chris Clark
fcbe7d3c98 Merge pull request #493 from clark800/max-amount-2
Rename source.amount to source.maxAmount
2015-08-10 14:29:47 -07:00
Chris Clark
a6662ccdff Rename source.amount to source.maxAmount 2015-08-10 14:15:30 -07:00
Chris Clark
854fe85151 Check for duplicate schema titles 2015-08-10 11:35:41 -07:00
Geert Weening
2b2fdf1b11 Bump version to 0.13.0-rc4 2015-08-07 15:32:21 -07:00
Geert Weening
cbe44d6a96 Update release notes 2015-08-07 15:32:21 -07:00
Geert Weening
420346faea Bump version to 0.13.0-rc3 2015-08-07 15:32:20 -07:00
Geert Weening
6220162852 Update release notes 2015-08-07 15:32:20 -07:00
Geert Weening
37198bde66 Bump version to 0.13.0-rc4 2015-08-07 15:31:56 -07:00
Geert Weening
281c056f6c Update release notes 2015-08-07 15:31:24 -07:00
Geert Weening
49a513cd07 Merge branch 'release' into develop 2015-08-07 14:47:26 -07:00
Alan Cohen
7a95aabbf4 Merge pull request #491 from lumberj/empty-paths
Don't set empty paths
2015-08-07 10:35:41 -07:00
Alan Cohen
83874ec096 Don't set empty paths
"The Paths field must not be an empty array, nor an array whose members are all
empty arrays."
https://ripple.com/build/transactions/#paths

Fix test file lint errors
2015-08-07 10:26:45 -07:00
Chris Clark
9270d0a33d Merge pull request #490 from clark800/test-dist
Clean up package.json
2015-08-06 15:30:09 -07:00
Chris Clark
30295efdb4 Clean up package.json 2015-08-06 15:09:49 -07:00
Chris Clark
f1342c1456 Merge pull request #489 from clark800/test-compiled
Test compiled code in dist/npm on CI server
2015-08-06 15:02:56 -07:00
Chris Clark
194b73c293 Test compiled code in dist/npm on CI server 2015-08-06 14:59:48 -07:00
Chris Clark
89e5f79bbb Merge pull request #487 from clark800/orderbook-changes
Switch to direction/quantity/totalPrice for orderbookChanges
2015-08-06 14:53:18 -07:00
Chris Clark
82d7ce7ac2 Switch to direction/quantity/totalPrice for orderbookChanges 2015-08-06 12:27:03 -07:00
Geert Weening
0cc4c704f8 Merge pull request #482 from clark800/deprecate
Deprecate core
2015-08-06 11:35:12 -07:00
Chris Clark
dde762a1d6 Merge pull request #483 from clark800/fix-prepare-trustline
Fix prepareTrustline with no quality setting
2015-08-06 10:40:34 -07:00
Chris Clark
1c86e246c7 Merge pull request #484 from darkdarkdragon/develop-schema-fix
small adjustment.json schema fix
2015-08-05 16:31:27 -07:00
Ivan Tivonenko
2d173c8e69 small adjustment.json schema fix 2015-08-06 02:25:59 +03:00
Chris Clark
600fd34d30 Fix prepareTrustline with no quality setting 2015-08-05 15:42:48 -07:00
Geert Weening
4cb9cf801c Bump version to 0.13.0-rc3 2015-08-04 17:20:25 -07:00
Geert Weening
50fb8789b4 Update release notes 2015-08-04 17:06:57 -07:00
Chris Clark
fb8dc44ec1 Deprecate core 2015-08-04 16:57:39 -07:00
Geert Weening
0781caa8bc Merge pull request #481 from clark800/pathfind-fix
Add test case for createPathFind and convert snake case function calls to camel case
2015-08-04 16:57:18 -07:00
Chris Clark
2cdb23f0dd Fix lint errors in pathfind.js 2015-08-04 15:51:52 -07:00
Chris Clark
8e536c00b9 Add test case for createPathFind and convert snake case function calls to camel case 2015-08-04 15:51:18 -07:00
Geert Weening
8ff154cc2d Merge pull request #480 from clark800/promise-docs
Update RippleAPI documentation for promises
2015-08-04 15:29:08 -07:00
Chris Clark
daaae6e01e Update RippleAPI documentation for promises 2015-08-04 14:53:46 -07:00
Chris Clark
a64a4e697a Merge pull request #478 from clark800/promises
Convert API to promises
2015-08-04 11:32:52 -07:00
wltsmrz
3f51d8cc12 Merge pull request #479 from wltsmrz/fix-validated-ledgers-single-ledger
Fix RangeSet for validated_ledger as single ledger
2015-08-05 00:48:48 +07:00
wltsmrz
9f9e76f8b9 Fix RangeSet for validated_ledger as single ledger 2015-08-04 10:45:29 -07:00
sublimator
5b51db158d Merge pull request #476 from clark800/badge
Replace Travis badge with CircleCI badge
2015-08-04 07:44:59 +07:00
Chris Clark
a4d1509448 Replace Travis badge with CircleCI badge 2015-08-03 17:39:01 -07:00
Chris Clark
bbd51a03b6 Convert API to promises 2015-08-03 17:22:17 -07:00
sublimator
b55b82b2fd Merge pull request #474 from shekenahglory/develop
add 'DeliveredAmount' as optional metadata field
2015-08-01 06:30:36 +07:00
Matthew Fettig
fdb0f101bd add 'DeliveredAmount' as optional metadata field 2015-07-31 16:21:18 -07:00
Chris Clark
0afca5633d Merge pull request #473 from clark800/remove-slippage
Remove slippage parameter
2015-07-31 11:06:32 -07:00
Chris Clark
7c0d9a7172 Remove slippage parameter 2015-07-31 10:43:39 -07:00
sublimator
f6b7e27c67 Merge pull request #472 from clark800/offline
Add unit test for offline prepare and sign
2015-07-31 08:47:29 +07:00
Chris Clark
b8624bc55f Add unit test for offline prepare and sign 2015-07-30 18:19:52 -07:00
sublimator
2eec30756d Merge pull request #471 from clark800/no-xrp-paths
Don't set paths for XRP to XRP payment
2015-07-31 06:46:12 +07:00
sublimator
6b44ce8973 Merge pull request #458 from clark800/fix-pathfind
Fix counterparty logic in pathfind parsing
2015-07-31 06:26:58 +07:00
Chris Clark
ed0b501716 Don't set paths for XRP to XRP payment 2015-07-30 13:43:44 -07:00
Geert Weening
0fd391af72 bump version to 0.13.0.rc2 2015-07-30 12:18:48 -07:00
Chris Clark
fe9c1ada88 Fix counterparty logic in pathfind parsing 2015-07-30 11:55:52 -07:00
Alan Cohen
4c1f4ef58c Merge pull request #470 from clark800/remove-asyncify
Remove simple-asyncify dependency
2015-07-30 11:47:03 -07:00
Chris Clark
10afc770ff Remove simple-asyncify dependency 2015-07-30 11:38:46 -07:00
Alan Cohen
8543e60f86 Merge pull request #469 from lumberj/update-flow
Update Flow to 0.14
2015-07-30 11:09:57 -07:00
Alan Cohen
116d7e0f29 Update Flow to 0.14
Fixes issue with fs.readFileSync return type
See: https://github.com/facebook/flow/issues/416
https://github.com/facebook/flow/compare/v0.13.1...v0.14.0
2015-07-30 10:06:53 -07:00
Chris Clark
68adaec55b Merge pull request #467 from darkdarkdragon/develop-RLJS-440
change snake_case to camelCase in responses from api.submit and api.g…
2015-07-29 17:31:36 -07:00
Ivan Tivonenko
03640efef5 change snake_case to camelCase in responses from api.submit and api.getServerInfo and add schema for it 2015-07-30 03:10:10 +03:00
Alan Cohen
c6f450842e Merge pull request #466 from lumberj/continue-flowing
Typecheck remaining files in src/api
2015-07-29 16:03:15 -07:00
Alan Cohen
e583eb4592 Typecheck remaining files in src/api 2015-07-29 15:59:07 -07:00
Chris Clark
7fffbe0c64 Merge pull request #465 from darkdarkdragon/develop-RLJS-370-12
more unit tests coverage
2015-07-29 11:22:06 -07:00
Ivan Tivonenko
63e3b71eb5 cover api/common/errors.js with tests 2015-07-29 21:15:28 +03:00
Ivan Tivonenko
823ef738fe cover api/common/utils.js with tests 2015-07-29 17:40:59 +03:00
Ivan Tivonenko
0977ef0ec2 cover api/common/validate.js with tests 2015-07-29 17:15:34 +03:00
Ivan Tivonenko
cecf3f3d22 cover api/ledger/parse/utils.js with tests 2015-07-29 16:42:23 +03:00
Ivan Tivonenko
472fbce23a cover api/ledger/parse/trustline.js with tests 2015-07-29 15:46:15 +03:00
sublimator
e44aea1767 Merge pull request #464 from wltsmrz/add-delivermin
Add DeliverMin setter
2015-07-29 14:52:56 +07:00
wltsmrz
d682d90d86 Add DeliverMin setter 2015-07-29 00:25:27 -07:00
Chris Clark
141aa17dfc Merge pull request #463 from darkdarkdragon/develop-RLJS-370-11
cover api/common/schema-validator.js with tests
2015-07-28 17:40:48 -07:00
Ivan Tivonenko
0b09e53479 cover api/common/schema-validator.js with tests 2015-07-29 03:22:17 +03:00
Chris Clark
528d8bf25d Merge pull request #457 from darkdarkdragon/develop-sign-with-regular-key
allow to sign transaction in api.sign using regular key
2015-07-28 15:53:37 -07:00
Ivan Tivonenko
03a2109e24 allow to sign transaction in api.sign using regular key
make Seed.parse_json try different input types instead
of stopping on first failing
2015-07-29 01:49:25 +03:00
Chris Clark
b38b9bced6 Merge pull request #462 from darkdarkdragon/develop-RLJS-370-10
cover api/ledger/parse/settings.js with tests
2015-07-28 14:05:04 -07:00
Ivan Tivonenko
ea063d0c95 cover api/ledger/parse/settings.js with tests 2015-07-28 22:21:25 +03:00
Chris Clark
7f93929014 Merge pull request #461 from lumberj/update-parser
Update ripple-lib-transactionparser to 0.4
2015-07-28 11:23:06 -07:00
Alan Cohen
4cd10ecb87 Update ripple-lib-transactionparser to 0.4 2015-07-28 09:55:01 -07:00
sublimator
6ef30debd2 Merge pull request #459 from wltsmrz/fix-transaction-constructor
Fix transaction construction for SetRegularKey transactions
2015-07-28 14:50:58 +07:00
wltsmrz
4766bace4e Fix transaction construction for SetRegularKey transactions 2015-07-28 00:47:30 -07:00
sublimator
261500a3a4 Merge pull request #460 from wltsmrz/fix-transaction-sequencing
Fix transaction sequencing
2015-07-28 14:37:32 +07:00
wltsmrz
fae22b7023 Fix transaction sequencing 2015-07-27 23:17:05 -07:00
Chris Clark
4568b39997 Merge pull request #450 from clark800/api-names
Rename API parameters
2015-07-27 17:06:14 -07:00
Chris Clark
4a218cacfa Merge pull request #449 from clark800/numbers
Express trustline quality and account transferRate as floats
2015-07-27 17:02:35 -07:00
Chris Clark
34a4dd3077 Express transferRate as a float 2015-07-27 16:59:58 -07:00
Chris Clark
a383bd7e52 Express trustline quality as a float 2015-07-27 16:56:46 -07:00
Chris Clark
e76e693bdb Merge pull request #452 from darkdarkdragon/develop-RLJS-370-9-1
Increase tests coverage even more
2015-07-27 16:35:59 -07:00
Ivan Tivonenko
2c52e4aa69 more unit tests coverage 2015-07-28 02:24:27 +03:00
Ivan Tivonenko
13dee36e93 propagate message from remote error to RippledNetworkError 2015-07-28 02:17:40 +03:00
Ivan Tivonenko
6e180439d1 cover api/ledger/transaction.js with unit tests 2015-07-28 02:17:38 +03:00
Ivan Tivonenko
e8d0c1ae95 make api.getTransaction return NotFound error in case of transaction not found
instead of core.RippleError
2015-07-28 02:16:30 +03:00
Ivan Tivonenko
068bda0c95 cover api/ledger/transactions.js with unit tests 2015-07-28 02:16:28 +03:00
Ivan Tivonenko
ab694381d5 fix some api functions to work with parsed version of transaction 2015-07-28 02:13:54 +03:00
Chris Clark
dc2a6c75cf Merge pull request #456 from clark800/docs
Update api.html doc
2015-07-27 14:57:13 -07:00
Chris Clark
98dbba8f27 Add api.html doc 2015-07-27 14:54:15 -07:00
Chris Clark
9a1b80d77a Merge pull request #451 from clark800/sample
Add sample API usage for getting balances and making a payment
2015-07-27 14:46:59 -07:00
Chris Clark
a655be30d6 Merge pull request #455 from clark800/doc
Add api.html
2015-07-27 14:46:50 -07:00
Chris Clark
e5aabc3072 Add api.html 2015-07-27 14:42:29 -07:00
Chris Clark
2cd32d58ad Merge pull request #454 from clark800/response-schemas
Add response schemas and small fixes
2015-07-27 14:22:55 -07:00
Chris Clark
0c02b92717 Add response schemas and small fixes 2015-07-27 14:20:09 -07:00
Geert Weening
c58a077a2f Merge branch 'release' into develop 2015-07-24 15:39:50 -07:00
Geert Weening
6e7dc9d7d3 Merge branch 'master' into release
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-07-24 15:39:00 -07:00
Geert Weening
572c945274 Bump version to 0.12.6 2015-07-24 15:32:07 -07:00
Geert Weening
c605efab61 Update release notes 2015-07-24 15:31:59 -07:00
wltsmrz
2695f4302a Merge pull request #436 from wltsmrz/fix-orderbook-notification
Fix orderbook notification while disconnected
2015-07-25 06:25:31 +08:00
Chris Clark
a17011243e Fix webpack require failure due to "./" notation 2015-07-24 15:24:40 -07:00
Geert Weening
9a533ab807 Merge branch 'develop' into release 2015-07-24 15:22:35 -07:00
wltsmrz
a037952493 Fix orderbook notification while disconnected 2015-07-24 15:22:21 -07:00
Geert Weening
dc96795a02 Merge pull request #453 from clark800/webpack-fix
Fix webpack require failure due to "./" notation
2015-07-24 15:03:44 -07:00
Chris Clark
8d9746d7b1 Fix webpack require failure due to "./" notation 2015-07-24 14:59:25 -07:00
Chris Clark
00342c4239 Merge pull request #446 from darkdarkdragon/develop-RLJS-370-8
Increase tests coverage
2015-07-23 16:47:42 -07:00
Chris Clark
e48df2c1fd Add sample API usage for getting balances and making a payment 2015-07-23 15:51:15 -07:00
Ivan Tivonenko
6ade0f6554 cover api/ledger/pathfind.js with tests 2015-07-24 01:34:54 +03:00
Ivan Tivonenko
a88157bb92 change pathfind scheme so destination can be specified without counterparty 2015-07-24 01:34:51 +03:00
Ivan Tivonenko
00f318284f cover api/transaction/utils.js with tests 2015-07-24 01:34:49 +03:00
Chris Clark
2e12dc6d53 Merge pull request #445 from darkdarkdragon/develop-RLJS-370-7
fix settings.json schema to allow empty stings to
2015-07-23 15:27:50 -07:00
Chris Clark
34435d4d05 Rename API parameters 2015-07-23 14:24:11 -07:00
Ivan Tivonenko
a99452b773 fix settings.json schema to allow null to
'walletSize', 'transferRate', 'emailHash' and
'walletLocator' fields so they
can be cleared

cover api/transaction/settings.js with tests
2015-07-23 23:29:00 +03:00
Geert Weening
a05cb39ab0 Merge pull request #447 from geertweening/develop
Remove `src/js`
2015-07-23 11:12:21 -07:00
Geert Weening
0c69f7f10e Remove src/js 2015-07-23 11:06:12 -07:00
255 changed files with 11199 additions and 4718 deletions

View File

@@ -26,6 +26,9 @@ function webpackConfig(extension, overrides) {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader?optional=runtime'
}, {
test: /\.json/,
loader: 'json-loader'
}]
}
};

View File

@@ -1,3 +1,35 @@
##0.13.0 (release candidate)
**Breaking Changes**
+ [Removed timeout method of Request and added default timeout](https://github.com/ripple/ripple-lib/commit/634fe5683a9082e57682ff7d5c4fb9483b4af818)
+ Add new RippleAPI interface
- [RippleAPI README and samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples)
- [Method documentation](https://rawgit.com/ripple/ripple-lib/develop/docs/api.html)
**Changes**
+ [Add Remote.closeCurrentPathFind function, so current pathfind can be properly closed](https://github.com/ripple/ripple-lib/commit/e99010f363fc7cbe7fd547d3ca5b32ea083c44e6)
+ [Implement Balance Sheet API](https://github.com/ripple/ripple-lib/pull/579)
+ [Fix bugs in orderbook subscription](https://github.com/ripple/ripple-lib/commit/7404795dc64a85216148de7bc3ca7da7b33f4490)
+ [Fix crash due to rippled slowDown error](https://github.com/ripple/ripple-lib/commit/84838b2e9f6969b593b8462a62a6b8f516ada937)
+ [Fix: Emit error events and return error on pathfind](https://github.com/ripple/ripple-lib/commit/1ccbaf677631a1944eb05d90f7afc5f3690a03dd)
+ [Deprecate core and remove snake case method copying](https://github.com/ripple/ripple-lib/commit/fb8dc44ec1d49bb05cd0cdbe6dd4ab211195868a)
+ [Fix RangeSet for validated_ledger as single ledger](https://github.com/ripple/ripple-lib/commit/9f9e76f8b933201651af59307135f67cfa7d60e8)
+ [Fix bug where the paths would be set with an empty array](https://github.com/ripple/ripple-lib/commit/83874ec0962da311b76f2385623e51c68bc39035)
+ [Fix reserve calculation](https://github.com/ripple/ripple-lib/commit/52879febb92d876f01f2e4d70871baa07af631fb)
##0.12.7 and 0.12.8
+ [Improve performance of orderbook](https://github.com/ripple/ripple-lib/commit/c745faaaf0956ca98448a754b4fe97fb50574fc7)
+ [Remove Firefox warning about prototype overwrite](https://github.com/ripple/ripple-lib/commit/0c62fa21123b220b066871e1c41a3b4fe6f51885)
+ [Fix compare bug in Amount class](https://github.com/ripple/ripple-lib/commit/806547dd154e1b0bf252e8a74ad3ac6aa8a97660)
##0.12.6
+ [Fix webpack require failure due to "./" notation](https://github.com/ripple/ripple-lib/commit/8d9746d7b10be203ee613df523c2522012ff1baf)
##0.12.15
+ [Add offer autobridging](https://github.com/ripple/ripple-lib/commit/c7bbce83719c1e8c6a4fae5ca850e7515db1a4a5)

View File

@@ -2,7 +2,7 @@
A JavaScript API for interacting with Ripple in Node.js and the browser
[![Build Status](https://travis-ci.org/ripple/ripple-lib.svg?branch=develop)](https://travis-ci.org/ripple/ripple-lib) [![Coverage Status](https://coveralls.io/repos/ripple/ripple-lib/badge.png?branch=develop)](https://coveralls.io/r/ripple/ripple-lib?branch=develop)
[![Circle CI](https://circleci.com/gh/ripple/ripple-lib/tree/develop.svg?style=svg)](https://circleci.com/gh/ripple/ripple-lib/tree/develop) [![Coverage Status](https://coveralls.io/repos/ripple/ripple-lib/badge.png?branch=develop)](https://coveralls.io/r/ripple/ripple-lib?branch=develop)
[![NPM](https://nodei.co/npm/ripple-lib.png)](https://www.npmjs.org/package/ripple-lib)

View File

@@ -5,19 +5,32 @@ TOTAL_NODES="$2"
typecheck() {
npm install -g flow-bin
flow --version
npm run typecheck
}
lint() {
echo "eslint $(node_modules/.bin/eslint --version)"
npm list babel-eslint | grep babel-eslint
REPO_URL="https://raw.githubusercontent.com/ripple/javascript-style-guide"
curl "$REPO_URL/es6/eslintrc" > ./eslintrc
echo "plugins: [flowtype]" >> ./eslintrc
node_modules/.bin/eslint --reset -c ./eslintrc $(git --no-pager diff --name-only -M100% --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD | grep "\.js$")
echo "parser: babel-eslint" >> ./eslintrc
node_modules/.bin/eslint -c ./eslintrc $(git --no-pager diff --name-only -M100% --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD | grep "\.js$")
}
unittest() {
# test "src"
npm test --coverage
npm run coveralls
# test compiled version in "dist/npm"
babel -D --optional runtime --ignore "**/node_modules/**" -d test-compiled/ test/
echo "--reporter spec --timeout 5000 --slow 500" > test-compiled/mocha.opts
mkdir -p test-compiled/node_modules
ln -nfs ../../dist/npm/core test-compiled/node_modules/ripple-lib
ln -nfs ../../dist/npm test-compiled/node_modules/ripple-api
mocha --opts test-compiled/mocha.opts test-compiled
rm -rf test-compiled
}
oneNode() {

View File

@@ -14,6 +14,8 @@ __(More examples coming soon!)__
+ [Transaction requests](REFERENCE.md#transaction-requests)
3. [`Transaction` constructors](REFERENCE.md#transaction-constructors)
+ [Transaction events](REFERENCE.md#transaction-events)
4. [Subscriptions](REFERENCE.md#subscriptions)
+ [Orderbook subscription](REFERENCE.md#orderbook-subscription)
###Also see:
@@ -352,3 +354,24 @@ transaction.submit(function(err, res) {
#Amount objects
Coming Soon
#Subscriptions
##Orderbook subscription
Subscribes to an orderbook (including autobridged books). Send the orderbook on subscribe then notifies updates.
Available events: ['transaction', 'model', 'trade', 'offer_added', 'offer_removed', 'offer_changed', 'offer_funds_changed']
```js
parameters = {
currency_pays: <string>,
issuer_pays: <string>,
currency_gets: <string>,
issuer_gets: <string>
}
```
Basic subscription:
```js
var Orderbook = Remote.book(parameters);
Orderbook.on('model', handler);
```

358
docs/api.html Normal file
View File

@@ -0,0 +1,358 @@
<html>
<head>
<style>
a {
text-decoration: none;
}
.method {
margin-bottom: 10px;
}
.details {
font-family: "Courier New", monospace;
white-space: pre;
display: none;
}
</style>
<script type="text/javascript">
function toggle(element) {
var results = element.parentElement.getElementsByClassName('details');
if (results.length > 0) {
var style = results[0].style;
style.display = (style.display === 'block') ? 'none' : 'block';
}
}
</script>
</head>
<body>
<h2><a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/index.js">RippleAPI</a></h2>
<div class="method">
connect()
</div>
<div class="method">
disconnect()
</div>
<div class="method">
isConnected()
</div>
<div class="method">
getServerInfo()
</div>
<div class="method">
getFee()
</div>
<div class="method">
getLedgerVersion()
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-transaction.json">getTransaction</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/hash256.json">identifier</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/transaction-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
identifier: txhash
options: {minLedgerVersion: int, maxLedgerVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-transactions.json">getTransactions</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/transactions-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
options: {
start: txhash,
limit: int,
minLedgerVersion: int,
maxLedgerVersion: int,
earliestFirst: bool,
excludeFailures: bool,
initiated: bool,
counterparty: address,
types: [string],
binary: bool
}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-trustlines.json">getTrustlines</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/trustlines-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
options: {counterparty: address, currency: string, limit: int, ledgerVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-balances.json">getBalances</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/trustlines-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
options: {counterparty: address, currency: string, limit: int, ledgerVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-paths.json">getPaths</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/pathfind.json">pathfind</a>
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
pathfind: {
source: {
address: address,
currencies: [{
currency: string,
counterparty: address
}]
},
destination: adjustment
}
adjustment = {address: address, amount: amount, tag?: int}
amount = {currency: string, counterparty: address, value: floatstr}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-orders.json">getOrders</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/orders-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
options: {limit: int, ledverVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-orderbook.json">getOrderbook</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/orderbook.json">orderbook</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/orders-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
orderbook: {
base: {
currency,
counterparty
},
counter: {
currency,
counterparty
}
}
options: {limit: int, ledverVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-settings.json">getSettings</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/settings-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
options: {ledgerVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/get-account-info.json">getAccountInfo</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/settings-options.json">options</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
options: {ledgerVersion: int}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/tx.json">preparePayment</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/payment.json">payment</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
payment: {
source: adjustment,
destination: adjustment,
paths?: string,
slippage?: strfloat,
memos?: [{
type: string,
format: string,
data: string
}],
invoiceID?: hash256,
allowPartialPayment?: bool,
noDirectRipple?: bool,
limitQuality?: bool
}
adjustment = {address: address, amount: amount, tag?: int}
amount = {currency: string, counterparty: address, value: floatstr}
instructions: {
sequence: int,
fee: floatstr,
maxFee: floatstr,
maxLedgerVersion: int,
maxLedgerVersionOffset: int
}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/tx.json">prepareTrustline</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/trustline.json">trustline</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
trustline: {
currency: string,
counterparty: address,
limit: strfloat,
qualityIn?: float,
qualityOut?: float,
allowRippling?: bool,
authorized?: bool,
frozen?: bool
}
instructions: {
sequence: int,
fee: floatstr,
maxFee: floatstr,
maxLedgerVersion: int,
maxLedgerVersionOffset: int
}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/tx.json">prepareOrder</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/order.json">order</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
order: {
direction: ("buy"|"sell"),
quantity: amount,
totalPrice: amount,
immediateOrCancel?: bool,
fillOrKill?: bool,
passive?: bool
}
amount = {currency: string, counterparty: address, value: floatstr}
instructions: {
sequence: int,
fee: floatstr,
maxFee: floatstr,
maxLedgerVersion: int,
maxLedgerVersionOffset: int
}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/tx.json">prepareOrderCancellation</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/sequence.json">sequence</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
sequence: int
instructions: {
sequence: int,
fee: floatstr,
maxFee: floatstr,
maxLedgerVersion: int,
maxLedgerVersionOffset: int
}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/tx.json">prepareSettings</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/address.json">account</a>,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/settings.json">settings</a>[,
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
)
<a href="#" onclick="javascript:toggle(this)">+</a>
<div class="details">
settings: {
passwordSpent: bool,
requireDestinationTag: bool,
requireAuthorization: bool,
disallowIncomingXRP: bool,
disableMasterKey: bool,
enableTransactionIDTracking: bool,
noFreeze: bool,
globalFreeze: bool,
defaultRipple: bool,
emailHash: hash128,
walletLocator: hash256,
walletSize: int,
messageKey: string,
domain: string,
transferRate: float,
signers: string,
regularKey: address
}
instructions: {
sequence: int,
fee: floatstr,
maxFee: floatstr,
maxLedgerVersion: int,
maxLedgerVersionOffset: int
}
</div>
</div>
<div class="method">
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/sign.json">sign</a>(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/tx.json">txJSON</a>,
secret)
</div>
<div class="method">
submit(
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/blob.json">txBlob</a>
)
</div>
<div class="method">
generateWallet()
</div>
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/errors.js">errors</a>
</body>
</html>

3
docs/samples/README Normal file
View File

@@ -0,0 +1,3 @@
Usage:
babel-node balances.js
babel-node payment.js (requires setting address and secret in source file first)

12
docs/samples/balances.js Normal file
View File

@@ -0,0 +1,12 @@
'use strict';
const RippleAPI = require('../../src').RippleAPI; // require('ripple-lib')
const api = new RippleAPI({servers: ['wss://s1.ripple.com:443']});
const address = 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV';
api.connect().then(() => {
api.getBalances(address).then(balances => {
console.log(JSON.stringify(balances, null, 2));
process.exit();
});
});

41
docs/samples/payment.js Normal file
View File

@@ -0,0 +1,41 @@
'use strict';
const RippleAPI = require('../../src').RippleAPI; // require('ripple-lib')
const address = 'INSERT ADDRESS HERE';
const secret = 'INSERT SECRET HERE';
const api = new RippleAPI({servers: ['wss://s1.ripple.com:443']});
const instructions = {maxLedgerVersionOffset: 5};
const payment = {
source: {
address: address,
amount: {
value: '0.01',
currency: 'XRP'
}
},
destination: {
address: 'rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc',
amount: {
value: '0.01',
currency: 'XRP'
}
}
};
api.connect().then(() => {
console.log('Connected...');
api.preparePayment(address, payment, instructions).then(txJSON => {
console.log('Payment transaction prepared...');
const signedTransaction = api.sign(txJSON, secret).signedTransaction;
console.log('Payment transaction signed...');
api.submit(signedTransaction).then(response => {
console.log(response);
process.exit(0);
}).catch(error => {
console.log(error);
process.exit(1);
});
});
});

138
npm-shrinkwrap.json generated
View File

@@ -1,20 +1,20 @@
{
"name": "ripple-lib",
"version": "0.13.0-rc1",
"version": "0.13.0-rc14",
"npm-shrinkwrap-version": "5.4.0",
"node-version": "v0.12.6",
"node-version": "v0.12.7",
"dependencies": {
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
},
"babel-runtime": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.3.tgz",
"version": "5.8.25",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.25.tgz",
"dependencies": {
"core-js": {
"version": "0.9.18",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-0.9.18.tgz"
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.1.4.tgz"
}
}
},
@@ -22,21 +22,45 @@
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.7.tgz"
},
"bn.js": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-3.1.2.tgz"
},
"es6-promisify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-2.0.0.tgz",
"dependencies": {
"es6-promise": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz"
}
}
},
"extend": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
},
"hash.js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz",
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
},
"https-proxy-agent": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
"dependencies": {
"agent-base": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.0.tgz",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz",
"dependencies": {
"semver": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
}
}
},
@@ -57,8 +81,8 @@
}
},
"is-my-json-valid": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.0.tgz",
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz",
"dependencies": {
"generate-function": {
"version": "2.0.0",
@@ -75,8 +99,8 @@
}
},
"jsonpointer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-1.1.0.tgz"
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
},
"xtend": {
"version": "4.0.0",
@@ -85,40 +109,76 @@
}
},
"lodash": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.0.tgz"
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
},
"lru-cache": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.2.tgz"
},
"ripple-address-codec": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz",
"dependencies": {
"x-address-codec": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.0.tgz",
"dependencies": {
"base-x": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-1.0.1.tgz"
}
}
}
}
},
"ripple-keypairs": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-0.9.0.tgz",
"dependencies": {
"brorand": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.0.5.tgz"
},
"elliptic": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-5.1.0.tgz",
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
},
"ripple-address-codec": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-1.6.0.tgz",
"dependencies": {
"x-address-codec": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.6.0.tgz",
"dependencies": {
"base-x": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-1.0.1.tgz"
}
}
}
}
}
}
},
"ripple-lib-transactionparser": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.3.2.tgz",
"dependencies": {
"bignumber.js": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-1.4.1.tgz"
}
}
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.5.1.tgz"
},
"ripple-wallet-generator": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.3.tgz"
},
"simple-asyncify": {
"ripple-lib-value": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/simple-asyncify/-/simple-asyncify-0.1.0.tgz"
"resolved": "https://registry.npmjs.org/ripple-lib-value/-/ripple-lib-value-0.1.0.tgz"
},
"sjcl-extended": {
"version": "1.0.3",
"resolved": "git://github.com/ripple/sjcl-extended.git#d8cf8b22e7d97193c54e1f65113e3edcf200ca17",
"dependencies": {
"sjcl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.3.tgz"
}
}
"sjcl-codec": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/sjcl-codec/-/sjcl-codec-0.1.0.tgz"
},
"ws": {
"version": "0.7.2",

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.13.0-rc1",
"version": "0.13.0-rc14",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [
@@ -18,33 +18,38 @@
"async": "~0.9.0",
"babel-runtime": "^5.5.4",
"bignumber.js": "^2.0.3",
"bn.js": "^3.1.1",
"es6-promisify": "^2.0.0",
"extend": "~1.2.1",
"hash.js": "^1.0.3",
"https-proxy-agent": "^1.0.0",
"is-my-json-valid": "^2.12.0",
"is-my-json-valid": "^2.12.2",
"lodash": "^3.1.0",
"lru-cache": "~2.5.0",
"ripple-lib-transactionparser": "^0.3.2",
"ripple-wallet-generator": "^1.0.3",
"simple-asyncify": "^0.1.0",
"sjcl-extended": "ripple/sjcl-extended#1.0.3",
"ripple-address-codec": "^2.0.1",
"ripple-keypairs": "^0.9.0",
"ripple-lib-transactionparser": "^0.5.1",
"ripple-lib-value": "0.1.0",
"sjcl-codec": "0.1.0",
"ws": "~0.7.1"
},
"devDependencies": {
"assert-diff": "^1.0.1",
"babel": "^5.5.4",
"babel-core": "^5.5.4",
"babel-eslint": "^3.1.23",
"babel-loader": "^5.0.0",
"babel": "^5.8.21",
"babel-core": "^5.8.22",
"babel-eslint": "^4.0.5",
"babel-loader": "^5.3.2",
"coveralls": "~2.10.0",
"eslint": "^0.24.0",
"eslint": "^1.3.0",
"eslint-plugin-flowtype": "^1.0.0",
"eventemitter2": "^0.4.14",
"flow-bin": "^0.13.1",
"flow-bin": "^0.14",
"gulp": "~3.8.10",
"gulp-bump": "~0.1.13",
"gulp-rename": "~1.2.0",
"gulp-uglify": "~1.1.0",
"istanbul": "~0.3.5",
"json-loader": "^0.5.2",
"mocha": "~2.1.0",
"webpack": "~1.5.3",
"yargs": "~1.3.1"
@@ -53,12 +58,13 @@
"build": "gulp",
"clean": "rm -rf dist/npm && rm -rf build/flow",
"typecheck": "babel --optional runtime --blacklist flow -d build/flow/ src/ && flow check",
"compile": "babel --optional runtime -d dist/npm/ src/ && cp -r src/api/common/schemas/ dist/npm/api/common/schemas/",
"compile-with-source-maps": "babel --optional runtime -s -t -d dist/npm/ src/",
"compile": "babel -D --optional runtime -d dist/npm/ src/",
"watch": "babel -w -D --optional runtime -d dist/npm/ src/",
"compile-with-source-maps": "babel -D --optional runtime -s -t -d dist/npm/ src/",
"prepublish": "npm run clean && npm run compile",
"test": "istanbul test _mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'plugins:\n - flowtype' >> eslintrc; fi; eslint --reset -c eslintrc src/",
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'parser: babel-eslint' >> eslintrc; fi; eslint -c eslintrc src/",
"perf": "./scripts/perf_test.sh"
},
"repository": {

View File

@@ -26,7 +26,7 @@ gulp bower
exit_on_error
cd dist/bower
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc[0-9])?')
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc([0-9])+)?')
echo "version: $version"
git add ripple.js ripple-debug.js ripple-min.js bower.json
exit_on_error
@@ -40,4 +40,4 @@ exit_on_error
git push origin master
git push --tags origin master
cd ..
cd ../..

View File

@@ -26,7 +26,7 @@ gulp bower
exit_on_error
cd dist/bower
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc[0-9])?')
version=$(cat bower.json | grep -Eo '([0-9]\.?)+(-rc([0-9])+)?')
echo "version: $version"
git add ripple.js ripple-debug.js ripple-min.js bower.json
exit_on_error
@@ -40,4 +40,4 @@ exit_on_error
git push origin master
git push --tags origin master
cd ..
cd ../..

View File

@@ -2,12 +2,13 @@
'use strict';
var fs = require('fs');
var Amount = require('../dist/npm').Amount;
var Ledger = require('../dist/npm').Ledger;
var ripple = require('../dist/npm')._DEPRECATED;
var Amount = ripple.Amount;
var Ledger = ripple.Ledger;
function parse_options(from, flags) {
var argv = from.slice(),
opts_ = {argv: argv};
var argv = from.slice();
var opts_ = {argv: argv};
flags.forEach(function(f) {
// Do we have the flag?

View File

@@ -33,7 +33,7 @@ const AccountFields = {
WalletSize: {name: 'walletSize', defaults: 0},
MessageKey: {name: 'messageKey'},
Domain: {name: 'domain', encoding: 'hex'},
TransferRate: {name: 'transferRate', defaults: 0},
TransferRate: {name: 'transferRate', defaults: 0, shift: 9},
Signers: {name: 'signers'}
};

View File

@@ -58,6 +58,13 @@ function MissingLedgerHistoryError(message) {
MissingLedgerHistoryError.prototype = new RippleError();
MissingLedgerHistoryError.prototype.name = 'MissingLedgerHistoryError';
function PendingLedgerVersionError(message) {
this.message = message ||
'maxLedgerVersion is greater than server\'s most recent validated ledger';
}
PendingLedgerVersionError.prototype = new RippleError();
PendingLedgerVersionError.prototype.name = 'PendingLedgerVersionError';
/**
* Request timed out
*/
@@ -77,13 +84,14 @@ ApiError.prototype = new RippleError();
ApiError.prototype.name = 'ApiError';
module.exports = {
ValidationError: ValidationError,
NetworkError: NetworkError,
TransactionError: TransactionError,
RippledNetworkError: RippledNetworkError,
NotFoundError: NotFoundError,
MissingLedgerHistoryError: MissingLedgerHistoryError,
TimeOutError: TimeOutError,
ApiError: ApiError,
RippleError: RippleError
ValidationError,
NetworkError,
TransactionError,
RippledNetworkError,
NotFoundError,
PendingLedgerVersionError,
MissingLedgerHistoryError,
TimeOutError,
ApiError,
RippleError
};

View File

@@ -9,7 +9,12 @@ module.exports = {
dropsToXrp: utils.dropsToXrp,
xrpToDrops: utils.xrpToDrops,
toRippledAmount: utils.toRippledAmount,
wrapCatch: utils.wrapCatch,
generateAddress: utils.generateAddress,
composeAsync: utils.composeAsync,
convertExceptions: utils.convertExceptions
wrapCatch: utils.wrapCatch,
convertErrors: utils.convertErrors,
convertExceptions: utils.convertExceptions,
convertKeysFromSnakeCaseToCamelCase:
utils.convertKeysFromSnakeCaseToCamelCase,
promisify: utils.promisify
};

View File

@@ -1,36 +1,84 @@
// flow is disabled for this file until support for requiring json is added:
// https://github.com/facebook/flow/issues/167
'use strict';
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const validator = require('is-my-json-valid');
const core = require('./utils').core;
const ValidationError = require('./errors').ValidationError;
const {isValidAddress} = require('ripple-address-codec');
let SCHEMAS = {};
function isValidAddress(address) {
return core.UInt160.is_valid(address);
}
function isValidLedgerHash(ledgerHash) {
return core.UInt256.is_valid(ledgerHash);
}
function loadSchema(filepath) {
try {
return JSON.parse(fs.readFileSync(filepath, 'utf8'));
} catch (e) {
throw new Error('Failed to parse schema: ' + filepath);
}
}
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
function loadSchemas(dir) {
const filenames = fs.readdirSync(dir).filter(name => endsWith(name, '.json'));
const schemas = filenames.map(name => loadSchema(path.join(dir, name)));
function loadSchemas() {
// listed explicitly for webpack (instead of scanning schemas directory)
const schemas = [
require('./schemas/address.json'),
require('./schemas/adjustment.json'),
require('./schemas/amount.json'),
require('./schemas/amountbase.json'),
require('./schemas/balance.json'),
require('./schemas/blob.json'),
require('./schemas/currency.json'),
require('./schemas/get-account-info.json'),
require('./schemas/get-balances.json'),
require('./schemas/get-balance-sheet'),
require('./schemas/balance-sheet-options.json'),
require('./schemas/get-ledger.json'),
require('./schemas/get-orderbook.json'),
require('./schemas/get-orders.json'),
require('./schemas/get-paths.json'),
require('./schemas/get-server-info.json'),
require('./schemas/get-settings.json'),
require('./schemas/get-transaction.json'),
require('./schemas/get-transactions.json'),
require('./schemas/get-trustlines.json'),
require('./schemas/hash128.json'),
require('./schemas/hash256.json'),
require('./schemas/instructions.json'),
require('./schemas/issue.json'),
require('./schemas/ledger-options.json'),
require('./schemas/ledgerversion.json'),
require('./schemas/max-adjustment.json'),
require('./schemas/memo.json'),
require('./schemas/order-cancellation-transaction.json'),
require('./schemas/order-cancellation.json'),
require('./schemas/order-change.json'),
require('./schemas/order-transaction.json'),
require('./schemas/order.json'),
require('./schemas/orderbook-orders.json'),
require('./schemas/orderbook.json'),
require('./schemas/orders-options.json'),
require('./schemas/outcome.json'),
require('./schemas/pathfind.json'),
require('./schemas/payment-transaction.json'),
require('./schemas/payment.json'),
require('./schemas/quality.json'),
require('./schemas/remote-options.json'),
require('./schemas/sequence.json'),
require('./schemas/settings-options.json'),
require('./schemas/settings-transaction.json'),
require('./schemas/settings.json'),
require('./schemas/sign.json'),
require('./schemas/signed-value.json'),
require('./schemas/submit.json'),
require('./schemas/suspended-payment-cancellation.json'),
require('./schemas/suspended-payment-execution.json'),
require('./schemas/suspended-payment-creation.json'),
require('./schemas/timestamp.json'),
require('./schemas/transaction-options.json'),
require('./schemas/transactions-options.json'),
require('./schemas/trustline-transaction.json'),
require('./schemas/trustline.json'),
require('./schemas/trustlines-options.json'),
require('./schemas/tx.json'),
require('./schemas/uint32.json'),
require('./schemas/value.json'),
require('./schemas/prepare.json'),
require('./schemas/ledger-closed.json')
];
const titles = _.map(schemas, schema => schema.title);
const duplicates = _.keys(_.pick(_.countBy(titles), count => count > 1));
assert(duplicates.length === 0, 'Duplicate schemas for: ' + duplicates);
return _.indexBy(schemas, 'title');
}
@@ -43,9 +91,8 @@ function formatSchemaErrors(errors) {
return errors.map(formatSchemaError).join(', ');
}
function schemaValidate(schemaName, object) {
const formats = {address: isValidAddress,
ledgerHash: isValidLedgerHash};
function schemaValidate(schemaName: string, object: any): void {
const formats = {address: isValidAddress};
const options = {schemas: SCHEMAS, formats: formats,
verbose: true, greedy: true};
const schema = SCHEMAS[schemaName];
@@ -59,5 +106,8 @@ function schemaValidate(schemaName, object) {
}
}
SCHEMAS = loadSchemas(path.join(__dirname, './schemas'));
module.exports = schemaValidate;
SCHEMAS = loadSchemas();
module.exports = {
schemaValidate: schemaValidate,
SCHEMAS: SCHEMAS
};

View File

@@ -5,10 +5,7 @@
"properties": {
"address": {"$ref": "address"},
"amount": {"$ref": "amount"},
"tag": {
"description": "A string representing an unsigned 32-bit integer most commonly used to refer to a sender's hosted account at a Ripple gateway",
"$ref": "uint32"
}
"tag": {"$ref": "tag"}
},
"required": ["address", "amount"],
"additionalProperties": false

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "balance-sheet-options",
"description": "Options for getBalanceSheet",
"type": "object",
"properties": {
"excludeAddresses": {
"type": "array",
"items": {"$ref": "address"},
"uniqueItems": true
},
"ledgerVersion": {"$ref": "ledgerVersion"}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,44 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "balance",
"description": "Balance amount",
"type": "object",
"properties": {
"value": {
"description": "The balance on the trustline",
"$ref": "signedValue"
},
"currency": {
"description": "The three-character code or hex string used to denote currencies",
"$ref": "currency"
},
"counterparty": {
"description": "The Ripple account address of the currency's issuer or gateway",
"$ref": "address"
}
},
"additionalProperties": false,
"required": ["currency", "value"],
"oneOf": [
{
"properties": {
"currency": {
"not": {
"enum": ["XRP"]
}
}
},
"required": ["counterparty"]
},
{
"properties": {
"currency": {
"enum": ["XRP"]
}
},
"not": {
"required": ["counterparty"]
}
}
]
}

View File

@@ -0,0 +1,9 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "destinationAdjustment",
"type": "object",
"oneOf": [
{"$ref": "adjustment"},
{"$ref": "minAdjustment"}
]
}

View File

@@ -0,0 +1,21 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getAccountInfo",
"type": "object",
"properties": {
"sequence": {"$ref": "sequence"},
"xrpBalance": {"$ref": "value"},
"ownerCount": {"type": "integer", "minimum": 0},
"previousInitiatedTransactionID": {"$ref": "hash256"},
"previousAffectingTransactionID": {"$ref": "hash256"},
"previousAffectingTransactionLedgerVersion": {"$ref": "ledgerVersion"}
},
"required": [
"sequence",
"xrpBalance",
"ownerCount",
"previousAffectingTransactionID",
"previousAffectingTransactionLedgerVersion"
],
"additionalProperties": false
}

View File

@@ -0,0 +1,29 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getBalanceSheet",
"description": "getBalanceSheet response",
"type": "object",
"properties": {
"balances": {
"type": "array",
"items": {"$ref": "amount"}
},
"assets": {
"type": "array",
"items": {"$ref": "amount"}
},
"obligations": {
"type": "array",
"items": {
"type": "object",
"required": ["currency", "value"],
"additionalProperties": false,
"properties": {
"currency": {"$ref": "currency"},
"value": {"$ref": "value"}
}
}
}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getBalances",
"type": "array",
"items": {"$ref": "balance"}
}

View File

@@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getLedger",
"type": "object",
"properties": {
"accepted": {"type": "boolean"},
"closed": {"type": "boolean"},
"stateHash": {"$ref": "hash256"},
"closeTime": {"type": "integer", "minimum": 0},
"closeTimeResolution": {"type": "integer", "minimum": 1},
"closeFlags": {"type": "integer", "minimum": 0},
"ledgerHash": {"$ref": "hash256"},
"ledgerVersion": {"$ref": "ledgerVersion"},
"parentLedgerHash": {"$ref": "hash256"},
"parentCloseTime": {"type": "integer", "minimum": 0},
"totalDrops": {"$ref": "value"},
"transactionHash": {"$ref": "hash256"},
"transactions": {"type": "array", "items": {"type": "object"}},
"rawTransactions": {"type": "string"},
"transactionHashes": {"type": "array", "items": {"$ref": "hash256"}},
"rawState": {"type": "string"},
"stateHashes": {"type": "array", "items": {"$ref": "hash256"}}
},
"required": [
"accepted",
"closed",
"stateHash",
"closeTime",
"closeTimeResolution",
"closeFlags",
"ledgerHash",
"ledgerVersion",
"parentLedgerHash",
"parentCloseTime",
"totalDrops",
"transactionHash"
],
"additionalProperties": false
}

View File

@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getOrderbook",
"type": "object",
"properties": {
"bids": {"$ref": "orderbookOrders"},
"asks": {"$ref": "orderbookOrders"}
},
"required": ["bids", "asks"],
"additionalProperties": false
}

View File

@@ -0,0 +1,23 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getOrders",
"type": "array",
"items": {
"type": "object",
"properties": {
"specification": {"$ref": "order"},
"properties": {
"type": "object",
"properties": {
"maker": {"$ref": "address"},
"sequence": {"$ref": "sequence"},
"makerExchangeRate": {"$ref": "value"}
},
"required": ["maker", "sequence", "makerExchangeRate"],
"addtionalProperties": false
}
},
"required": ["specification", "properties"],
"additionalProperties": false
}
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getPaths",
"type": "array",
"items": {
"type": "object",
"properties": {
"source": {"$ref": "sourceAdjustment"},
"destination": {"$ref": "destinationAdjustment"},
"paths": {"type": "string"}
},
"required": ["source", "destination", "paths"],
"additionalProperties": false
}
}

View File

@@ -0,0 +1,49 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getServerInfo",
"type": "object",
"properties": {
"buildVersion": {"type": "string"},
"completeLedgers": {"type": "string", "pattern": "[0-9,-]+"},
"hostid": {"type": "string"},
"ioLatencyMs": {"type": "number"},
"load": {
"type": "object",
"properties": {
"jobTypes": {
"type": "array",
"items": {"type": "object"}
},
"threads": {"type": "number"}
}
},
"lastClose": {
"type": "object",
"properties": {
"convergeTimeS": {"type": "number"},
"proposers": {"type": "integer", "minimum": 0}
}
},
"loadFactor": {"type": "number"},
"peers": {"type": "integer", "minimum": 0},
"pubkeyNode": {"type": "string"},
"pubkeyValidator": {"type": "string"},
"serverState": {
"type": "string",
"enum": ["disconnected", "connected", "syncing", "tracking", "full", "validating", "proposing"]
},
"validatedLedger": {
"type": "object",
"properties": {
"age": {"type": "integer", "minimum": 0},
"baseFeeXrp": {"type": "number"},
"hash": {"$ref": "hash256"},
"reserveBaseXrp": {"type": "integer", "minimum": 0},
"reserveIncXrp": {"type": "integer", "minimum": 0},
"seq": {"type": "integer", "minimum": 0}
}
},
"validationQuorum": {"type": "number"}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,40 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getSettings",
"type": "object",
"properties": {
"passwordSpent": {"type": "boolean"},
"requireDestinationTag": {"type": "boolean"},
"requireAuthorization": {"type": "boolean"},
"disallowIncomingXRP": {"type": "boolean"},
"disableMasterKey": {"type": "boolean"},
"enableTransactionIDTracking": {"type": "boolean"},
"noFreeze": {"type": "boolean"},
"globalFreeze": {"type": "boolean"},
"defaultRipple": {"type": "boolean"},
"emailHash": {
"oneOf": [
{"type": "null"},
{"$ref": "hash128"}
]
},
"walletLocator": {
"oneOf": [
{"type": "null"},
{"$ref": "hash256"}
]
},
"walletSize": {"type": ["integer", "null"]},
"messageKey": {"type": "string"},
"domain": {"type": "string"},
"transferRate": {
"oneOf": [
{"type": "null"},
{"type": "number", "minimum": 1, "maximum": 4.294967295}
]
},
"signers": {"type": "string"},
"regularKey": {"$ref": "address"}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getTransaction",
"oneOf": [
{"$ref": "paymentTransaction"},
{"$ref": "orderTransaction"},
{"$ref": "orderCancellationTransaction"},
{"$ref": "trustlineTransaction"},
{"$ref": "settingsTransaction"}
]
}

View File

@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getTransactions",
"type": "array",
"items": {"$ref": "getTransaction"}
}

View File

@@ -0,0 +1,29 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "getTrustlines",
"type": "array",
"items": {
"properties": {
"specification": {"$ref": "trustline"},
"counterparty": {
"properties": {
"limit": {"$ref": "value"},
"ripplingDisabled": {"type": "boolean"},
"frozen": {"type": "boolean"},
"authorized": {"type": "boolean"}
},
"required": ["limit"],
"additionalProperties": false
},
"state": {
"properties": {
"balance": {"$ref": "value"}
},
"required": ["balance"],
"additionalProperties": false
}
},
"required": ["specification", "counterparty", "state"],
"additionalProperties": false
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "laxAmount",
"description": "Amount where counterparty is optional",
"type": "object",
"properties": {
"currency": {"$ref": "currency"},
"counterparty": {"$ref": "address"},
"value": {"$ref": "value"}
},
"required": ["currency", "value"],
"additionalProperties": false
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "laxLaxAmount",
"description": "Amount where counterparty and value are optional",
"type": "object",
"properties": {
"currency": {"$ref": "currency"},
"counterparty": {"$ref": "address"},
"value": {"$ref": "value"}
},
"required": ["currency"],
"additionalProperties": false
}

View File

@@ -0,0 +1,21 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "ledgerClosed",
"description": "A ledgerClosed event message",
"type": "object",
"properties": {
"feeBase": {"type": "integer", "minimum": 0},
"feeReference": {"type": "integer", "minimum": 0},
"ledgerHash": {"$ref": "ledgerHash"},
"ledgerVersion": {"$ref": "ledgerVersion"},
"ledgerTimestamp": {"type": "string", "format": "date-time"},
"reserveBase": {"type": "integer", "minimum": 0},
"reserveIncrement": {"type": "integer", "minimum": 0},
"transactionCount": {"type": "integer", "minimum": 0},
"validatedLedgerVersions": {"type": "string"}
},
"addtionalProperties": false,
"required": ["feeBase", "feeReference", "ledgerHash", "ledgerTimestamp",
"reserveBase", "reserveIncrement", "transactionCount",
"ledgerVersion", "validatedLedgerVersions"]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "ledger-options",
"description": "Options for getLedger",
"type": "object",
"properties": {
"ledgerVersion": {"$ref": "ledgerVersion"},
"includeAllData": {"type": "boolean"},
"includeTransactions": {"type": "boolean"},
"includeState": {"type": "boolean"}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,12 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "maxAdjustment",
"type": "object",
"properties": {
"address": {"$ref": "address"},
"maxAmount": {"$ref": "laxAmount"},
"tag": {"$ref": "tag"}
},
"required": ["address", "maxAmount"],
"additionalProperties": false
}

View File

@@ -0,0 +1,12 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "minAdjustment",
"type": "object",
"properties": {
"address": {"$ref": "address"},
"minAmount": {"$ref": "laxAmount"},
"tag": {"$ref": "tag"}
},
"required": ["address", "minAmount"],
"additionalProperties": false
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "orderCancellationTransaction",
"type": "object",
"properties": {
"type": {"enum": ["orderCancellation"]},
"specification": {"$ref": "orderCancellation"},
"outcome": {"$ref": "outcome"},
"id": {"$ref": "hash256"},
"address": {"$ref": "address"},
"sequence": {"$ref": "sequence"}
},
"required": ["type", "id", "address", "sequence", "specification", "outcome"],
"additionalProperties": false
}

View File

@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "cancellation",
"title": "orderCancellation",
"type": "object",
"properties": {
"orderSequence": {"$ref": "sequence"}

View File

@@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "orderChange",
"type": "object",
"properties": {
"direction": {
"type": "string",
"enum": ["buy", "sell"]
},
"quantity": {"$ref": "balance"},
"totalPrice": {"$ref": "balance"},
"makerExchangeRate": {"$ref": "value"},
"sequence": {"$ref": "sequence"},
"status": {"enum": ["created", "open", "closed", "canceled"]}
},
"required": ["direction", "quantity", "totalPrice", "sequence", "status"],
"additionalProperties": false
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "orderTransaction",
"type": "object",
"properties": {
"type": {"enum": ["order"]},
"specification": {"$ref": "order"},
"outcome": {"$ref": "outcome"},
"id": {"$ref": "hash256"},
"address": {"$ref": "address"},
"sequence": {"$ref": "sequence"}
},
"required": ["type", "id", "address", "sequence", "specification", "outcome"],
"additionalProperties": false
}

View File

@@ -0,0 +1,32 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "orderbookOrders",
"type": "array",
"items": {
"type": "object",
"properties": {
"specification": {"$ref": "order"},
"properties": {
"type": "object",
"properties": {
"maker": {"$ref": "address"},
"sequence": {"$ref": "sequence"},
"makerExchangeRate": {"$ref": "value"}
},
"required": ["maker", "sequence", "makerExchangeRate"],
"addtionalProperties": false
},
"state": {
"type": "object",
"properties": {
"fundedAmount": {"$ref": "amount"},
"priceOfFundedAmount": {"$ref": "amount"}
},
"required": ["fundedAmount", "priceOfFundedAmount"],
"additionalProperties": false
}
},
"required": ["specification", "properties"],
"additionalProperties": false
}
}

View File

@@ -0,0 +1,31 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "outcome",
"type": "object",
"properties": {
"result": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"},
"fee": {"$ref": "value"},
"balanceChanges": {
"type": "object",
"description": "Key is the ripple address; value is an array of changes",
"additionalProperties": {
"type": "array",
"items": {"$ref": "balance"}
}
},
"orderbookChanges": {
"type": "object",
"description": "Key is the maker's ripple address; value is an array of changes",
"additionalProperties": {
"type": "array",
"items": {"$ref": "orderChange"}
}
},
"ledgerVersion": {"$ref": "ledgerVersion"},
"indexInLedger": {"type": "integer", "minimum": 0}
},
"required": ["result", "fee", "balanceChanges",
"orderbookChanges", "ledgerVersion", "indexInLedger"],
"additionalProperties": false
}

View File

@@ -7,6 +7,7 @@
"type": "object",
"properties": {
"address": {"$ref": "address"},
"amount": {"$ref": "laxAmount"},
"currencies": {
"type": "array",
"items": {
@@ -19,12 +20,23 @@
"additionalProperties": false
},
"uniqueItems": true
},
"not": {
"required": ["amount", "currencies"]
}
},
"additionalProperties": false,
"required": ["address"]
},
"destination": {"$ref": "adjustment"}
"destination": {
"type": "object",
"properties": {
"address": {"$ref": "address"},
"amount": {"$ref": "laxLaxAmount"}
},
"required": ["address", "amount"],
"additionalProperties": false
}
},
"required": ["source", "destination"],
"additionalProperties": false

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "paymentTransaction",
"type": "object",
"properties": {
"type": {"enum": ["payment"]},
"specification": {"$ref": "payment"},
"outcome": {"$ref": "outcome"},
"id": {"$ref": "hash256"},
"address": {"$ref": "address"},
"sequence": {"$ref": "sequence"}
},
"required": ["type", "id", "address", "sequence", "specification", "outcome"],
"additionalProperties": false
}

View File

@@ -3,13 +3,9 @@
"title": "payment",
"type": "object",
"properties": {
"source": {"$ref": "adjustment"},
"destination": {"$ref": "adjustment"},
"source": {"$ref": "sourceAdjustment"},
"destination": {"$ref": "destinationAdjustment"},
"paths": {"type": "string"},
"slippage": {
"description": "An optional cushion for the source_amount to increase the likelihood that the payment will succeed. The source_account will never be charged more than source_amount.value + source_slippage",
"$ref": "value"
},
"memos": {
"type": "array",
"items": {

View File

@@ -0,0 +1,21 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "prepare",
"description": "Result of prepare function",
"type": "object",
"properties": {
"txJSON": {"type": "string"},
"instructions": {
"type": "object",
"properties": {
"fee": {"$ref": "value"},
"sequence": {"$ref": "sequence"},
"maxLedgerVersion": {"$ref": "ledgerVersion"}
},
"additionalProperties": false,
"required": ["fee", "sequence"]
}
},
"additionalProperties": false,
"required": ["txJSON", "instructions"]
}

View File

@@ -1,8 +1,8 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "quality",
"description": "Ratio for incoming/outgoing transit fees represented in billionths. (For example, a value of 500 million represents a 0.5:1 ratio.) As a special case, 0 is treated as a 1:1 ratio.",
"type": "integer",
"minimum": 0,
"maximum": 1000000000
"description": "Ratio for incoming/outgoing transit fees.",
"type": "number",
"minimum": 0.000000001,
"maximum": 4.294967295
}

View File

@@ -0,0 +1,17 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "remote-options",
"type": "object",
"properties": {
"trace": {"type": "boolean"},
"servers": {
"type": "array",
"items": {
"type": "string",
"format": "uri",
"pattern": "^wss?://"
}
}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "settingsTransaction",
"type": "object",
"properties": {
"type": {"enum": ["settings"]},
"specification": {"$ref": "getSettings"},
"outcome": {"$ref": "outcome"},
"id": {"$ref": "hash256"},
"address": {"$ref": "address"},
"sequence": {"$ref": "sequence"}
},
"required": ["type", "id", "address", "sequence", "specification"],
"additionalProperties": false
}

View File

@@ -1,27 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "settings",
"type": "object",
"properties": {
"passwordSpent": {"type": "boolean"},
"requireDestinationTag": {"type": "boolean"},
"requireAuthorization": {"type": "boolean"},
"disallowIncomingXRP": {"type": "boolean"},
"disableMasterKey": {"type": "boolean"},
"enableTransactionIDTracking": {"type": "boolean"},
"noFreeze": {"type": "boolean"},
"globalFreeze": {"type": "boolean"},
"defaultRipple": {"type": "boolean"},
"emailHash": {"$ref": "hash128"},
"walletLocator": {"$ref": "hash256"},
"walletSize": {"type": "integer"},
"messageKey": {"type": "string"},
"domain": {"type": "string"},
"transferRate": {"type": "integer"},
"signers": {"type": "string"},
"regularKey": {"$ref": "address"}
},
"minProperties": 1,
"maxProperties": 1,
"additionalProperties": false
"allOf": [
{
"$ref": "getSettings"
},
{
"minProperties": 1,
"maxProperties": 1
}
]
}

View File

@@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "sign",
"type": "object",
"properties": {
"signedTransaction": {
"type": "string",
"pattern": "^[A-F0-9]+$"
},
"id": {"$ref": "hash256"}
},
"required": ["signedTransaction", "id"],
"additionalProperties": false
}

View File

@@ -0,0 +1,7 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "signedValue",
"description": "A string representation of a floating point number",
"type": "string",
"pattern": "^[-]?[0-9]*[.]?[0-9]+([eE][-+]?[0-9]+)?$"
}

View File

@@ -0,0 +1,9 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "sourceAdjustment",
"type": "object",
"oneOf": [
{"$ref": "adjustment"},
{"$ref": "maxAdjustment"}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "submit",
"type": "object",
"properties": {
"success": {"type": "boolean"},
"engineResult": {"type": "string"},
"engineResultCode": {"type": "integer"},
"engineResultMessage": {"type": "string"},
"txBlob": {"type": "string"},
"txJson": {"type": "object"}
},
"required": ["success", "engineResult", "engineResultCode"],
"additionalProperties": false
}

View File

@@ -0,0 +1,17 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "suspended-payment-cancellation",
"type": "object",
"properties": {
"memos": {
"type": "array",
"items": {
"$ref": "memo"
}
},
"owner": {"$ref": "address"},
"paymentSequence": {"$ref": "uint32"}
},
"required": ["owner", "paymentSequence"],
"additionalProperties": false
}

View File

@@ -0,0 +1,28 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "suspended-payment-creation",
"type": "object",
"properties": {
"source": {"$ref": "maxAdjustment"},
"destination": {"$ref": "adjustment"},
"memos": {
"type": "array",
"items": {
"$ref": "memo"
}
},
"digest": {"$ref": "hash256"},
"allowCancelAfter": {
"type": "integer",
"minimum": 0,
"description": "milliseconds since unix epoch"
},
"allowExecuteAfter": {
"type": "integer",
"minimum": 0,
"description": "milliseconds since unix epoch"
}
},
"required": ["source", "destination"],
"additionalProperties": false
}

View File

@@ -0,0 +1,20 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "suspended-payment-execution",
"type": "object",
"properties": {
"memos": {
"type": "array",
"items": {
"$ref": "memo"
}
},
"owner": {"$ref": "address"},
"paymentSequence": {"$ref": "uint32"},
"method": {"type": "integer", "minimum": 0, "maximum": 255},
"digest": {"$ref": "hash256"},
"proof": {"type": "string"}
},
"required": ["owner", "paymentSequence"],
"additionalProperties": false
}

View File

@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "tag",
"description": "A string representing an unsigned 32-bit integer most commonly used to refer to a sender's hosted account at a Ripple gateway",
"$ref": "uint32"
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "trustlineTransaction",
"type": "object",
"properties": {
"type": {"enum": ["trustline"]},
"specification": {"$ref": "trustline"},
"outcome": {"$ref": "outcome"},
"id": {"$ref": "hash256"},
"address": {"$ref": "address"},
"sequence": {"$ref": "sequence"}
},
"required": ["type", "id", "address", "sequence", "specification", "outcome"],
"additionalProperties": false
}

View File

@@ -8,7 +8,7 @@
"limit": {"$ref": "value"},
"qualityIn": {"$ref": "quality"},
"qualityOut": {"$ref": "quality"},
"allowRippling": {"type": "boolean"},
"ripplingDisabled": {"type": "boolean"},
"authorized": {"type": "boolean"},
"frozen": {"type": "boolean"}
},

View File

@@ -1,17 +1,23 @@
/* @flow */
'use strict';
const _ = require('lodash');
const BigNumber = require('bignumber.js');
const core = require('../../core');
const errors = require('./errors');
const es6promisify = require('es6-promisify');
const keypairs = require('ripple-keypairs');
function dropsToXrp(drops) {
type Amount = {currency: string, issuer: string, value: string}
function dropsToXrp(drops: string): string {
return (new BigNumber(drops)).dividedBy(1000000.0).toString();
}
function xrpToDrops(xrp) {
function xrpToDrops(xrp: string): string {
return (new BigNumber(xrp)).times(1000000.0).floor().toString();
}
function toRippledAmount(amount) {
function toRippledAmount(amount: Amount): string|Amount {
if (amount.currency === 'XRP') {
return xrpToDrops(amount.value);
}
@@ -22,7 +28,16 @@ function toRippledAmount(amount) {
};
}
function wrapCatch(asyncFunction: () => void): () => void {
function generateAddress(options?: Object): Object {
const secret = keypairs.generateSeed(options);
const keypair = keypairs.deriveKeypair(secret);
const address = keypairs.deriveAddress(keypair.publicKey);
return {secret, address};
}
type AsyncFunction = (...x: any) => void
function wrapCatch(asyncFunction: AsyncFunction): AsyncFunction {
return function() {
try {
asyncFunction.apply(this, arguments);
@@ -33,10 +48,13 @@ function wrapCatch(asyncFunction: () => void): () => void {
};
}
function composeAsync(wrapper, callback) {
type Callback = (err: any, data: any) => void
type Wrapper = (data: any) => any
function composeAsync(wrapper: Wrapper, callback: Callback): Callback {
return function(error, data) {
if (error) {
callback(error);
callback(error, data);
return;
}
let result;
@@ -50,7 +68,23 @@ function composeAsync(wrapper, callback) {
};
}
function convertExceptions(f) {
function convertErrors(callback: Callback): () => void {
return function(error, data) {
if (error && !(error instanceof errors.RippleError)) {
const message = _.get(error, ['remote', 'error_message'], error.message);
const error_ = new errors.RippleError(message);
error_.data = data;
callback(error_, data);
} else if (error) {
error.data = data;
callback(error, data);
} else {
callback(error, data);
}
};
}
function convertExceptions<T>(f: () => T): () => T {
return function() {
try {
return f.apply(this, arguments);
@@ -60,12 +94,36 @@ function convertExceptions(f) {
};
}
const FINDSNAKE = /([a-zA-Z]_[a-zA-Z])/g;
function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
if (typeof obj === 'object') {
let newKey;
return _.reduce(obj, (result, value, key) => {
newKey = key;
if (FINDSNAKE.test(key)) {
newKey = key.replace(FINDSNAKE, r => r[0] + r[2].toUpperCase());
}
result[newKey] = convertKeysFromSnakeCaseToCamelCase(value);
return result;
}, {});
}
return obj;
}
function promisify(asyncFunction: AsyncFunction): Function {
return es6promisify(wrapCatch(asyncFunction));
}
module.exports = {
core,
dropsToXrp,
xrpToDrops,
toRippledAmount,
wrapCatch,
generateAddress,
composeAsync,
convertExceptions
wrapCatch,
convertExceptions,
convertErrors,
convertKeysFromSnakeCaseToCamelCase,
promisify
};

View File

@@ -1,26 +1,43 @@
/* @flow */
'use strict';
const _ = require('lodash');
const core = require('./utils').core;
const deriveKeypair = require('ripple-keypairs').deriveKeypair;
const ValidationError = require('./errors').ValidationError;
const schemaValidate = require('./schema-validator');
const schemaValidate = require('./schema-validator').schemaValidate;
function error(text) {
return new ValidationError(text);
}
function validateAddressAndSecret(obj) {
function isValidSecret(secret) {
try {
deriveKeypair(secret);
return true;
} catch (err) {
return false;
}
}
function validateAddressAndSecret(obj: {address: string, secret: string}
): void {
const address = obj.address;
const secret = obj.secret;
schemaValidate('address', address);
if (!secret) {
throw error('Parameter missing: secret');
}
try {
if (!core.Seed.from_json(secret).get_key(address)) {
throw error('secret does not match address');
}
} catch (exception) {
throw error('secret does not match address');
if (!isValidSecret(secret)) {
throw error('Invalid parameter: secret');
}
}
function validateSecret(secret: string): void {
if (!secret) {
throw error('Parameter missing: secret');
}
if (typeof secret !== 'string' || secret[0] !== 's'
|| !isValidSecret(secret)) {
throw error('Invalid parameter: secret');
}
}
@@ -41,12 +58,20 @@ function validateOptions(schema, options) {
module.exports = {
address: _.partial(schemaValidate, 'address'),
addressAndSecret: validateAddressAndSecret,
secret: validateSecret,
currency: _.partial(schemaValidate, 'currency'),
identifier: _.partial(schemaValidate, 'hash256'),
ledgerVersion: _.partial(schemaValidate, 'ledgerVersion'),
sequence: _.partial(schemaValidate, 'sequence'),
order: _.partial(schemaValidate, 'order'),
orderbook: _.partial(schemaValidate, 'orderbook'),
payment: _.partial(schemaValidate, 'payment'),
suspendedPaymentCreation:
_.partial(schemaValidate, 'suspended-payment-creation'),
suspendedPaymentExecution:
_.partial(schemaValidate, 'suspended-payment-execution'),
suspendedPaymentCancellation:
_.partial(schemaValidate, 'suspended-payment-cancellation'),
pathfind: _.partial(schemaValidate, 'pathfind'),
settings: _.partial(schemaValidate, 'settings'),
trustline: _.partial(schemaValidate, 'trustline'),
@@ -57,9 +82,12 @@ module.exports = {
getAccountInfoOptions: _.partial(validateOptions, 'settings-options'),
getTrustlinesOptions: _.partial(validateOptions, 'trustlines-options'),
getBalancesOptions: _.partial(validateOptions, 'trustlines-options'),
getBalanceSheetOptions: _.partial(validateOptions, 'balance-sheet-options'),
getOrdersOptions: _.partial(validateOptions, 'orders-options'),
getOrderbookOptions: _.partial(validateOptions, 'orders-options'),
getTransactionOptions: _.partial(validateOptions, 'transaction-options'),
getLedgerOptions: _.partial(validateOptions, 'ledger-options'),
options: _.partial(validateOptions, 'options'),
remoteOptions: _.partial(schemaValidate, 'remote-options'),
instructions: _.partial(schemaValidate, 'instructions')
};

View File

@@ -2,7 +2,9 @@
'use strict';
const _ = require('lodash');
const core = require('./common').core;
const util = require('util');
const EventEmitter = require('events').EventEmitter;
const common = require('./common');
const server = require('./server/server');
const connect = server.connect;
const disconnect = server.disconnect;
@@ -14,6 +16,7 @@ const getTransaction = require('./ledger/transaction');
const getTransactions = require('./ledger/transactions');
const getTrustlines = require('./ledger/trustlines');
const getBalances = require('./ledger/balances');
const getBalanceSheet = require('./ledger/balance-sheet');
const getPaths = require('./ledger/pathfind');
const getOrders = require('./ledger/orders');
const getOrderbook = require('./ledger/orderbook');
@@ -23,19 +26,36 @@ const preparePayment = require('./transaction/payment');
const prepareTrustline = require('./transaction/trustline');
const prepareOrder = require('./transaction/order');
const prepareOrderCancellation = require('./transaction/ordercancellation');
const prepareSuspendedPaymentCreation =
require('./transaction/suspended-payment-creation');
const prepareSuspendedPaymentExecution =
require('./transaction/suspended-payment-execution');
const prepareSuspendedPaymentCancellation =
require('./transaction/suspended-payment-cancellation');
const prepareSettings = require('./transaction/settings');
const sign = require('./transaction/sign');
const submit = require('./transaction/submit');
const errors = require('./common').errors;
const convertExceptions = require('./common').convertExceptions;
const generateWallet = convertExceptions(core.Wallet.generate);
const generateAddress = convertExceptions(common.generateAddress);
const computeLedgerHash = require('./offline/ledgerhash');
const getLedger = require('./ledger/ledger');
function RippleAPI(options: {}) {
common.validate.remoteOptions(options);
if (EventEmitter instanceof Function) { // always true, needed for flow
EventEmitter.call(this);
}
const _options = _.assign({}, options, {automatic_resubmission: false});
this.remote = new core.Remote(_options);
this.remote = new common.core.Remote(_options);
this.remote.on('ledger_closed', message => {
this.emit('ledgerClosed', server.formatLedgerClose(message));
});
}
RippleAPI.prototype = {
util.inherits(RippleAPI, EventEmitter);
_.assign(RippleAPI.prototype, {
connect,
disconnect,
isConnected,
@@ -47,22 +67,35 @@ RippleAPI.prototype = {
getTransactions,
getTrustlines,
getBalances,
getBalanceSheet,
getPaths,
getOrders,
getOrderbook,
getSettings,
getAccountInfo,
getLedger,
preparePayment,
prepareTrustline,
prepareOrder,
prepareOrderCancellation,
prepareSuspendedPaymentCreation,
prepareSuspendedPaymentExecution,
prepareSuspendedPaymentCancellation,
prepareSettings,
sign,
submit,
generateWallet,
generateAddress,
errors
});
// these are exposed only for use by unit tests; they are not part of the API
RippleAPI._PRIVATE = {
common,
computeLedgerHash,
ledgerUtils: require('./ledger/utils'),
schemaValidator: require('./common/schema-validator')
};
module.exports = RippleAPI;

View File

@@ -5,8 +5,45 @@ const utils = require('./utils');
const removeUndefined = require('./parse/utils').removeUndefined;
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
function formatAccountInfo(response) {
type AccountData = {
Sequence: number,
Account: string,
Balance: string,
Flags: number,
LedgerEntryType: string,
OwnerCount: number,
PreviousTxnID: string,
AccountTxnID?: string,
PreviousTxnLgrSeq: number,
index: string
}
type AccountDataResponse = {
account_data: AccountData,
ledger_current_index?: number,
ledger_hash?: string,
ledger_index: number,
validated: boolean
}
type AccountInfoOptions = {
ledgerVersion?: number
}
type AccountInfoCallback = (err: any, data: AccountInfoResponse) => void
type AccountInfoResponse = {
sequence: number,
xrpBalance: string,
ownerCount: number,
previousInitiatedTransactionID: string,
previousAffectingTransactionID: string,
previousAffectingTransactionLedgerVersion: number
}
function formatAccountInfo(response: AccountDataResponse) {
const data = response.account_data;
return removeUndefined({
sequence: data.Sequence,
@@ -18,17 +55,24 @@ function formatAccountInfo(response) {
});
}
function getAccountInfo(account, options, callback) {
function getAccountInfoAsync(account: string, options: AccountInfoOptions,
callback: AccountInfoCallback
) {
validate.address(account);
validate.getAccountInfoOptions(options);
const request = {
account: account,
ledger: options.ledgerVersion
ledger: options.ledgerVersion || 'validated'
};
this.remote.requestAccountInfo(request,
composeAsync(formatAccountInfo, callback));
composeAsync(formatAccountInfo, convertErrors(callback)));
}
module.exports = utils.wrapCatch(getAccountInfo);
function getAccountInfo(account: string, options: AccountInfoOptions = {}
): Promise<AccountInfoResponse> {
return utils.promisify(getAccountInfoAsync).call(this, account, options);
}
module.exports = getAccountInfo;

View File

@@ -0,0 +1,68 @@
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
function formatBalanceSheet(balanceSheet) {
const result = {};
if (!_.isUndefined(balanceSheet.balances)) {
result.balances = [];
_.forEach(balanceSheet.balances, (balances, counterparty) => {
_.forEach(balances, (balance) => {
result.balances.push(Object.assign({counterparty}, balance));
});
});
}
if (!_.isUndefined(balanceSheet.assets)) {
result.assets = [];
_.forEach(balanceSheet.assets, (assets, counterparty) => {
_.forEach(assets, (balance) => {
result.assets.push(Object.assign({counterparty}, balance));
});
});
}
if (!_.isUndefined(balanceSheet.obligations)) {
result.obligations = _.map(balanceSheet.obligations, (value, currency) =>
({currency, value}));
}
return result;
}
function getBalanceSheetAsync(address, options, callback) {
validate.address(address);
validate.getBalanceSheetOptions(options);
const requestOptions = Object.assign({}, {
account: address,
strict: true,
hotwallet: options.excludeAddresses,
ledger: options.ledgerVersion
});
const requestCallback = composeAsync(
formatBalanceSheet, convertErrors(callback));
this.remote.getLedgerSequence((err, ledgerVersion) => {
if (err) {
callback(err);
return;
}
if (_.isUndefined(requestOptions.ledger)) {
requestOptions.ledger = ledgerVersion;
}
this.remote.requestGatewayBalances(requestOptions, requestCallback);
});
}
function getBalanceSheet(address: string, options = {}) {
return utils.promisify(getBalanceSheetAsync).call(this, address, options);
}
module.exports = getBalanceSheet;

View File

@@ -6,6 +6,10 @@ const utils = require('./utils');
const getTrustlines = require('./trustlines');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
import type {Remote} from '../../core/remote';
import type {GetLedgerSequenceCallback} from '../../core/remote';
function getTrustlineBalanceAmount(trustline) {
return {
@@ -24,16 +28,37 @@ function formatBalances(balances) {
balances.trustlines.map(getTrustlineBalanceAmount));
}
function getBalances(account, options, callback) {
function getTrustlinesAsync(account, options, callback) {
getTrustlines.call(this, account, options)
.then(data => callback(null, data))
.catch(callback);
}
function getLedgerVersionHelper(remote: Remote, optionValue?: number,
callback: GetLedgerSequenceCallback
) {
if (optionValue !== undefined && optionValue !== null) {
callback(null, optionValue);
} else {
remote.getLedgerSequence(callback);
}
}
function getBalancesAsync(account, options, callback) {
validate.address(account);
validate.getBalancesOptions(options);
const ledgerVersion = options.ledgerVersion
|| this.remote.getLedgerSequence();
async.parallel({
xrp: _.partial(utils.getXRPBalance, this.remote, account, ledgerVersion),
trustlines: _.partial(getTrustlines.bind(this), account, options)
}, composeAsync(formatBalances, callback));
xrp: async.seq(
_.partial(getLedgerVersionHelper, this.remote, options.ledgerVersion),
_.partial(utils.getXRPBalance, this.remote, account)
),
trustlines: _.partial(getTrustlinesAsync.bind(this), account, options)
}, composeAsync(formatBalances, convertErrors(callback)));
}
module.exports = utils.wrapCatch(getBalances);
function getBalances(account: string, options = {}) {
return utils.promisify(getBalancesAsync).call(this, account, options);
}
module.exports = getBalances;

28
src/api/ledger/ledger.js Normal file
View File

@@ -0,0 +1,28 @@
/* @flow */
'use strict';
const utils = require('./utils');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseLedger = require('./parse/ledger');
function getLedgerAsync(options, callback) {
validate.getLedgerOptions(options);
const request = {
ledger: options.ledgerVersion || 'validated',
expand: options.includeAllData,
transactions: options.includeTransactions,
accounts: options.includeState
};
this.remote.requestLedger(request,
composeAsync(response => parseLedger(response.ledger),
convertErrors(callback)));
}
function getLedger(options = {}) {
return utils.promisify(getLedgerAsync).call(this, options);
}
module.exports = getLedger;

View File

@@ -3,21 +3,23 @@
const _ = require('lodash');
const async = require('async');
const utils = require('./utils');
const parseOrderbookOrder = require('./parse/orderbook-order');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseOrderbookOrder = require('./parse/orderbook-order');
// account is to specify a "perspective", which affects which unfunded offers
// are returned
function getBookOffers(remote, account, ledgerVersion, limit,
takerGets, takerPays, callback) {
takerGets, takerPays, callback
) {
remote.requestBookOffers(utils.renameCounterpartyToIssuerInOrder({
taker_gets: takerGets,
taker_pays: takerPays,
ledger: ledgerVersion || 'validated',
limit: limit,
taker: account
}), composeAsync(data => data.offers, callback));
}), composeAsync(data => data.offers, convertErrors(callback)));
}
function isSameIssue(a, b) {
@@ -62,7 +64,7 @@ function formatBidsAndAsks(orderbook, offers) {
return {bids, asks};
}
function getOrderbook(account, orderbook, options, callback) {
function getOrderbookAsync(account, orderbook, options, callback) {
validate.address(account);
validate.orderbook(orderbook);
validate.getOrderbookOptions(options);
@@ -76,4 +78,9 @@ function getOrderbook(account, orderbook, options, callback) {
callback));
}
module.exports = utils.wrapCatch(getOrderbook);
function getOrderbook(account: string, orderbook: Object, options = {}) {
return utils.promisify(getOrderbookAsync).call(this,
account, orderbook, options);
}
module.exports = getOrderbook;

View File

@@ -1,13 +1,16 @@
/* @flow */
'use strict';
const _ = require('lodash');
const async = require('async');
const utils = require('./utils');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseAccountOrder = require('./parse/account-order');
function requestAccountOffers(remote, address, ledgerVersion, options,
marker, limit, callback) {
function requestAccountOffers(remote, address, ledgerVersion, marker, limit,
callback
) {
remote.requestAccountOffers({
account: address,
marker: marker,
@@ -17,20 +20,24 @@ function requestAccountOffers(remote, address, ledgerVersion, options,
composeAsync((data) => ({
marker: data.marker,
results: data.offers.map(_.partial(parseAccountOrder, address))
}), callback));
}), convertErrors(callback)));
}
function getOrders(account, options, callback) {
function getOrdersAsync(account, options, callback) {
validate.address(account);
validate.getOrdersOptions(options);
const ledgerVersion = options.ledgerVersion
|| this.remote.getLedgerSequence();
const getter = _.partial(requestAccountOffers, this.remote, account,
ledgerVersion, options);
options.ledgerVersion);
utils.getRecursive(getter, options.limit,
composeAsync((orders) => _.sortBy(orders,
(order) => order.properties.sequence), callback));
}
module.exports = utils.wrapCatch(getOrders);
function getOrders(account: string, options = {}) {
return utils.promisify(async.seq(
utils.getLedgerOptionsWithLedgerVersion,
getOrdersAsync)).call(this, account, options);
}
module.exports = getOrders;

View File

@@ -1,11 +1,15 @@
/* @flow */
'use strict';
const BigNumber = require('bignumber.js');
const AccountFields = require('./utils').constants.AccountFields;
function parseField(info, value) {
if (info.encoding === 'hex' && !info.length) {
return new Buffer(value, 'hex').toString('ascii');
}
if (info.shift) {
return (new BigNumber(value)).shift(-info.shift).toNumber();
}
return value;
}

View File

@@ -0,0 +1,50 @@
/* @flow */
'use strict';
const _ = require('lodash');
const removeUndefined = require('./utils').removeUndefined;
const parseTransaction = require('./transaction');
function parseTransactions(transactions) {
if (_.isEmpty(transactions)) {
return {};
}
if (_.isString(transactions[0])) {
return {transactionHashes: transactions};
}
return {
transactions: _.map(transactions, parseTransaction),
rawTransactions: JSON.stringify(transactions)
};
}
function parseState(state) {
if (_.isEmpty(state)) {
return {};
}
if (_.isString(state[0])) {
return {stateHashes: state};
}
return {rawState: JSON.stringify(state)};
}
function parseLedger(ledger: Object): Object {
return removeUndefined(_.assign({
accepted: ledger.accepted,
closed: ledger.closed,
stateHash: ledger.account_hash,
closeTime: ledger.close_time,
closeTimeResolution: ledger.close_time_resolution,
closeFlags: ledger.close_flags,
ledgerHash: ledger.hash || ledger.ledger_hash,
ledgerVersion: parseInt(ledger.ledger_index || ledger.seqNum, 10),
parentLedgerHash: ledger.parent_hash,
parentCloseTime: ledger.parent_close_time,
totalDrops: ledger.total_coins || ledger.totalCoins,
transactionHash: ledger.transaction_hash
},
parseTransactions(ledger.transactions),
parseState(ledger.accountState)
));
}
module.exports = parseLedger;

View File

@@ -8,21 +8,42 @@ function parsePaths(paths) {
_.omit(step, ['type', 'type_hex'])));
}
function parsePathfind(sourceAddress: string,
destinationAmount: Object, pathfindResult: Object): Object {
return pathfindResult.alternatives.map(function(alternative) {
return {
source: {
address: sourceAddress,
amount: parseAmount(alternative.source_amount)
},
destination: {
address: pathfindResult.destination_account,
amount: destinationAmount
},
paths: JSON.stringify(parsePaths(alternative.paths_computed))
};
});
function removeAnyCounterpartyEncoding(address: string, amount: Object) {
return amount.counterparty === address ?
_.omit(amount, 'counterparty') : amount;
}
function createAdjustment(address: string, adjustmentWithoutAddress: Object) {
const amountKey = _.keys(adjustmentWithoutAddress)[0];
const amount = adjustmentWithoutAddress[amountKey];
return _.set({address: address}, amountKey,
removeAnyCounterpartyEncoding(address, amount));
}
function parseAlternative(sourceAddress: string, destinationAddress: string,
destinationAmount: Object, alternative: Object
) {
// we use "maxAmount"/"minAmount" here so that the result can be passed
// directly to preparePayment
const amounts = (alternative.destination_amount !== undefined) ?
{source: {amount: parseAmount(alternative.source_amount)},
destination: {minAmount: parseAmount(alternative.destination_amount)}} :
{source: {maxAmount: parseAmount(alternative.source_amount)},
destination: {amount: parseAmount(destinationAmount)}};
return {
source: createAdjustment(sourceAddress, amounts.source),
destination: createAdjustment(destinationAddress, amounts.destination),
paths: JSON.stringify(parsePaths(alternative.paths_computed))
};
}
function parsePathfind(pathfindResult: Object): Object {
const sourceAddress = pathfindResult.source_account;
const destinationAddress = pathfindResult.destination_account;
const destinationAmount = pathfindResult.destination_amount;
return pathfindResult.alternatives.map(_.partial(parseAlternative,
sourceAddress, destinationAddress, destinationAmount));
}
module.exports = parsePathfind;

View File

@@ -1,5 +1,6 @@
/* @flow */
'use strict';
const _ = require('lodash');
const assert = require('assert');
const utils = require('./utils');
const parseAmount = require('./amount');
@@ -17,17 +18,9 @@ function isQualityLimited(tx) {
return (tx.Flags & Transaction.flags.Payment.LimitQuality) !== 0;
}
function parsePaymentMemos(tx) {
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
return undefined;
}
return tx.Memos.map((m) => {
return utils.removeUndefined({
type: m.Memo.parsed_memo_type,
format: m.Memo.parsed_memo_format,
data: m.Memo.parsed_memo_data
});
});
function removeGenericCounterparty(amount, address) {
return amount.counterparty === address ?
_.omit(amount, 'counterparty') : amount;
}
function parsePayment(tx: Object): Object {
@@ -35,20 +28,21 @@ function parsePayment(tx: Object): Object {
const source = {
address: tx.Account,
amount: parseAmount(tx.SendMax || tx.Amount),
maxAmount: removeGenericCounterparty(
parseAmount(tx.SendMax || tx.Amount), tx.Account),
tag: tx.SourceTag
};
const destination = {
address: tx.Destination,
amount: parseAmount(tx.Amount),
amount: removeGenericCounterparty(parseAmount(tx.Amount), tx.Destination),
tag: tx.DestinationTag
};
return utils.removeUndefined({
source: utils.removeUndefined(source),
destination: utils.removeUndefined(destination),
memos: parsePaymentMemos(tx),
memos: utils.parseMemos(tx),
invoiceID: tx.InvoiceID,
paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined,
allowPartialPayment: isPartialPayment(tx) || undefined,

View File

@@ -0,0 +1,16 @@
/* @flow */
'use strict';
const assert = require('assert');
const utils = require('./utils');
function parseSuspendedPaymentCancellation(tx: Object): Object {
assert(tx.TransactionType === 'SuspendedPaymentCancel');
return utils.removeUndefined({
memos: utils.parseMemos(tx),
owner: tx.Owner,
paymentSequence: tx.OfferSequence
});
}
module.exports = parseSuspendedPaymentCancellation;

View File

@@ -0,0 +1,39 @@
/* @flow */
'use strict';
const _ = require('lodash');
const assert = require('assert');
const utils = require('./utils');
const parseAmount = require('./amount');
function removeGenericCounterparty(amount, address) {
return amount.counterparty === address ?
_.omit(amount, 'counterparty') : amount;
}
function parseSuspendedPaymentCreation(tx: Object): Object {
assert(tx.TransactionType === 'SuspendedPaymentCreate');
const source = {
address: tx.Account,
maxAmount: removeGenericCounterparty(
parseAmount(tx.SendMax || tx.Amount), tx.Account),
tag: tx.SourceTag
};
const destination = {
address: tx.Destination,
amount: removeGenericCounterparty(parseAmount(tx.Amount), tx.Destination),
tag: tx.DestinationTag
};
return utils.removeUndefined({
source: utils.removeUndefined(source),
destination: utils.removeUndefined(destination),
memos: utils.parseMemos(tx),
digest: tx.Digest,
allowCancelAfter: tx.CancelAfter,
allowExecuteAfter: tx.FinishAfter
});
}
module.exports = parseSuspendedPaymentCreation;

View File

@@ -0,0 +1,25 @@
/* @flow */
'use strict';
const assert = require('assert');
const sjclcodec = require('sjcl-codec');
const utils = require('./utils');
function convertHexToString(hexString) {
const bits = sjclcodec.hex.toBits(hexString);
return sjclcodec.utf8String.fromBits(bits);
}
function parseSuspendedPaymentExecution(tx: Object): Object {
assert(tx.TransactionType === 'SuspendedPaymentFinish');
return utils.removeUndefined({
memos: utils.parseMemos(tx),
owner: tx.Owner,
paymentSequence: tx.OfferSequence,
method: tx.Method,
digest: tx.Digest,
proof: tx.Proof ? convertHexToString(tx.Proof) : undefined
});
}
module.exports = parseSuspendedPaymentExecution;

View File

@@ -7,6 +7,10 @@ const parseTrustline = require('./trustline');
const parseOrder = require('./order');
const parseOrderCancellation = require('./cancellation');
const parseSettings = require('./settings');
const parseSuspendedPaymentCreation = require('./suspended-payment-creation');
const parseSuspendedPaymentExecution = require('./suspended-payment-execution');
const parseSuspendedPaymentCancellation =
require('./suspended-payment-cancellation');
function parseTransactionType(type) {
const mapping = {
@@ -15,7 +19,10 @@ function parseTransactionType(type) {
OfferCreate: 'order',
OfferCancel: 'orderCancellation',
AccountSet: 'settings',
SetRegularKey: 'settings'
SetRegularKey: 'settings',
SuspendedPaymentCreate: 'suspendedPaymentCreation',
SuspendedPaymentFinish: 'suspendedPaymentExecution',
SuspendedPaymentCancel: 'suspendedPaymentCancellation'
};
return mapping[type] || null;
}
@@ -27,7 +34,10 @@ function parseTransaction(tx: Object): Object {
'trustline': parseTrustline,
'order': parseOrder,
'orderCancellation': parseOrderCancellation,
'settings': parseSettings
'settings': parseSettings,
'suspendedPaymentCreation': parseSuspendedPaymentCreation,
'suspendedPaymentExecution': parseSuspendedPaymentExecution,
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation
};
const parser = mapping[type];
assert(parser !== undefined, 'Unrecognized transaction type');

View File

@@ -3,6 +3,7 @@
const assert = require('assert');
const utils = require('./utils');
const flags = utils.core.Transaction.flags.TrustSet;
const BigNumber = require('bignumber.js');
function parseFlag(flagsValue, trueValue, falseValue) {
if (flagsValue & trueValue) {
@@ -14,6 +15,13 @@ function parseFlag(flagsValue, trueValue, falseValue) {
return undefined;
}
function parseQuality(quality?: number) {
if (typeof quality === 'number') {
return (new BigNumber(quality)).shift(-9).toNumber();
}
return undefined;
}
function parseTrustline(tx: Object): Object {
assert(tx.TransactionType === 'TrustSet');
@@ -21,8 +29,8 @@ function parseTrustline(tx: Object): Object {
limit: tx.LimitAmount.value,
currency: tx.LimitAmount.currency,
counterparty: tx.LimitAmount.issuer,
qualityIn: tx.QualityIn,
qualityOut: tx.QualityOut,
qualityIn: parseQuality(tx.QualityIn),
qualityOut: parseQuality(tx.QualityOut),
ripplingDisabled: parseFlag(
tx.Flags, flags.SetNoRipple, flags.ClearNoRipple),
frozen: parseFlag(tx.Flags, flags.SetFreeze, flags.ClearFreeze),

View File

@@ -6,8 +6,9 @@ const toTimestamp = require('../../../core/utils').toTimestamp;
const utils = require('../utils');
const BigNumber = require('bignumber.js');
function adjustQualityForXRP(quality: string, takerGetsCurrency: string,
takerPaysCurrency: string) {
function adjustQualityForXRP(
quality: string, takerGetsCurrency: string, takerPaysCurrency: string
) {
// quality = takerPays.value/takerGets.value
// using drops (1e-6 XRP) for XRP values
const numeratorShift = (takerPaysCurrency === 'XRP' ? -6 : 0);
@@ -51,7 +52,7 @@ function parseOutcome(tx: Object): ?Object {
}
const balanceChanges = transactionParser.parseBalanceChanges(tx.meta);
const orderbookChanges = transactionParser.parseOrderBookChanges(tx.meta);
const orderbookChanges = transactionParser.parseOrderbookChanges(tx.meta);
removeEmptyCounterpartyInBalanceChanges(balanceChanges);
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges);
@@ -66,8 +67,22 @@ function parseOutcome(tx: Object): ?Object {
};
}
function parseMemos(tx: Object): ?Array<Object> {
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
return undefined;
}
return tx.Memos.map((m) => {
return removeUndefined({
type: m.Memo.parsed_memo_type,
format: m.Memo.parsed_memo_format,
data: m.Memo.parsed_memo_data
});
});
}
module.exports = {
parseOutcome,
parseMemos,
removeUndefined,
adjustQualityForXRP,
dropsToXrp: utils.common.dropsToXrp,

View File

@@ -4,14 +4,18 @@ const _ = require('lodash');
const async = require('async');
const BigNumber = require('bignumber.js');
const utils = require('./utils');
const validate = utils.common.validate;
const parsePathfind = require('./parse/pathfind');
const validate = utils.common.validate;
const NotFoundError = utils.common.errors.NotFoundError;
const ValidationError = utils.common.errors.ValidationError;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const toRippledAmount = utils.common.toRippledAmount;
type PathFindParams = {
src_currencies?: Array<string>, src_account: string, dst_amount: string,
dst_account?: string
src_currencies?: Array<string>, src_account: string,
dst_amount: string | Object, dst_account?: string,
src_amount?: string | Object
}
function addParams(params: PathFindParams, result: {}) {
@@ -28,10 +32,11 @@ type PathFind = {
}
function requestPathFind(remote, pathfind: PathFind, callback) {
const destinationAmount = _.assign({value: -1}, pathfind.destination.amount);
const params: PathFindParams = {
src_account: pathfind.source.address,
dst_account: pathfind.destination.address,
dst_amount: utils.common.toRippledAmount(pathfind.destination.amount)
dst_amount: toRippledAmount(destinationAmount)
};
if (typeof params.dst_amount === 'object' && !params.dst_amount.issuer) {
// Convert blank issuer to sender's address
@@ -43,11 +48,21 @@ function requestPathFind(remote, pathfind: PathFind, callback) {
}
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
params.src_currencies = pathfind.source.currencies.map(amount =>
_.omit(utils.common.toRippledAmount(amount), 'value'));
_.omit(toRippledAmount(amount), 'value'));
}
if (pathfind.source.amount) {
if (pathfind.destination.amount.value !== undefined) {
throw new ValidationError('Cannot specify both source.amount'
+ ' and destination.amount.value in getPaths');
}
params.src_amount = toRippledAmount(pathfind.source.amount);
if (params.src_amount.currency && !params.src_amount.issuer) {
params.src_amount.issuer = pathfind.source.address;
}
}
remote.requestRipplePathFind(params,
composeAsync(_.partial(addParams, params), callback));
remote.createPathFind(params,
composeAsync(_.partial(addParams, params), convertErrors(callback)));
}
function addDirectXrpPath(paths, xrpBalance) {
@@ -80,10 +95,10 @@ function conditionallyAddDirectXRPPath(remote, address, paths, callback) {
function formatResponse(pathfind, paths) {
if (paths.alternatives && paths.alternatives.length > 0) {
const address = pathfind.source.address;
return parsePathfind(address, pathfind.destination.amount, paths);
return parsePathfind(paths);
}
if (!_.includes(paths.destination_currencies,
if (paths.destination_currencies !== undefined &&
!_.includes(paths.destination_currencies,
pathfind.destination.amount.currency)) {
throw new NotFoundError('No paths found. ' +
'The destination_account does not accept ' +
@@ -103,7 +118,7 @@ function formatResponse(pathfind, paths) {
}
}
function getPaths(pathfind, callback) {
function getPathsAsync(pathfind, callback) {
validate.pathfind(pathfind);
const address = pathfind.source.address;
@@ -113,4 +128,8 @@ function getPaths(pathfind, callback) {
], composeAsync(_.partial(formatResponse, pathfind), callback));
}
module.exports = utils.wrapCatch(getPaths);
function getPaths(pathfind: Object) {
return utils.promisify(getPathsAsync).call(this, pathfind);
}
module.exports = getPaths;

View File

@@ -6,6 +6,7 @@ const validate = utils.common.validate;
const parseFields = require('./parse/fields');
const composeAsync = utils.common.composeAsync;
const AccountFlags = utils.common.constants.AccountFlags;
const convertErrors = utils.common.convertErrors;
function parseFlags(value) {
const settings = {};
@@ -24,17 +25,21 @@ function formatSettings(response) {
return _.assign({}, parsedFlags, parsedFields);
}
function getSettings(account, options, callback) {
function getSettingsAsync(account, options, callback) {
validate.address(account);
validate.getSettingsOptions(options);
const request = {
account: account,
ledger: options.ledgerVersion
ledger: options.ledgerVersion || 'validated'
};
this.remote.requestAccountInfo(request,
composeAsync(formatSettings, callback));
composeAsync(formatSettings, convertErrors(callback)));
}
module.exports = utils.wrapCatch(getSettings);
function getSettings(account: string, options = {}) {
return utils.promisify(getSettingsAsync).call(this, account, options);
}
module.exports = getSettings;

View File

@@ -0,0 +1,147 @@
/* @flow */
'use strict';
type Outcome = {
result: string,
timestamp?: string,
fee: string,
balanceChanges: Object,
orderbookChanges: Object,
ledgerVersion: number,
indexInLedger: number
}
type Adjustment = {
address: string,
amount: {
currency: string,
counterparty?: string,
value: string
},
tag?: number
}
type Trustline = {
currency: string,
counterparty: string,
limit: string,
qualityIn?: number,
qualityOut?: number,
ripplingDisabled?: boolean,
authorized?: boolean,
frozen?: boolean
}
type Settings = {
passwordSpent?: boolean,
requireDestinationTag?: boolean,
requireAuthorization?: boolean,
disallowIncomingXRP?: boolean,
disableMasterKey?: boolean,
enableTransactionIDTracking?: boolean,
noFreeze?: boolean,
globalFreeze?: boolean,
defaultRipple?: boolean,
emailHash?: string,
walletLocator?: string,
walletSize?: number,
messageKey?: string,
domain?: string,
transferRate?: number,
signers?: string,
regularKey?: string
}
type OrderCancellation = {
orderSequence: number
}
type Memo = {
type?: string,
format?: string,
data?: string
}
type Amount = {
value: string,
currency: string,
counterparty?: string
}
type Payment = {
source: Adjustment,
destination: Adjustment,
paths?: string,
memos?: Array<Memo>,
invoiceID?: string,
allowPartialPayment?: boolean,
noDirectRipple?: boolean,
limitQuality?: boolean
}
type PaymentTransaction = {
type: string,
specification: Payment,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type Order = {
direction: string,
quantity: Amount,
totalPrice: Amount,
immediateOrCancel?: boolean,
fillOrKill?: boolean,
passive?: boolean
}
type OrderTransaction = {
type: string,
specification: Order,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type OrderCancellationTransaction = {
type: string,
specification: OrderCancellation,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type TrustlineTransaction = {
type: string,
specification: Trustline,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
type SettingsTransaction = {
type: string,
specification: Settings,
outcome: Outcome,
id: string,
address: string,
sequence: number
}
export type TransactionOptions = {
minLedgerVersion?: number,
maxLedgerVersion?: number
}
export type GetTransactionResponse = PaymentTransaction | OrderTransaction |
OrderCancellationTransaction | TrustlineTransaction | SettingsTransaction
export type GetTransactionResponseCallback =
(err?: ?Error, data?: GetTransactionResponse) => void
export type CallbackType = (err?: ?Error, data?: Object) => void

View File

@@ -6,8 +6,18 @@ const utils = require('./utils');
const parseTransaction = require('./parse/transaction');
const validate = utils.common.validate;
const errors = utils.common.errors;
const convertErrors = utils.common.convertErrors;
const RippleError = require('../../core/rippleerror').RippleError;
function attachTransactionDate(remote, tx, callback) {
import type {Remote} from '../../core/remote';
import type {CallbackType, GetTransactionResponse,
GetTransactionResponseCallback, TransactionOptions}
from './transaction-types';
function attachTransactionDate(remote: Remote, tx: Object,
callback: CallbackType
) {
if (tx.date) {
callback(null, tx);
return;
@@ -28,40 +38,76 @@ function attachTransactionDate(remote, tx, callback) {
});
}
function isTransactionInRange(tx, options) {
function isTransactionInRange(tx: Object, options: TransactionOptions) {
return (!options.minLedgerVersion
|| tx.ledger_index >= options.minLedgerVersion)
&& (!options.maxLedgerVersion
|| tx.ledger_index <= options.maxLedgerVersion);
}
function getTransaction(identifier, options, callback) {
function getTransactionAsync(identifier: string, options: TransactionOptions,
callback: GetTransactionResponseCallback
) {
validate.identifier(identifier);
validate.getTransactionOptions(options);
const remote = this.remote;
const maxLedgerVersion = Math.min(options.maxLedgerVersion,
remote.getLedgerSequence());
function callbackWrapper(error, tx) {
function callbackWrapper(error_?: Error, tx?: Object,
maxLedgerVersion?: number
) {
let error = error_;
if (!error && tx && tx.validated !== true) {
return callback(new errors.NotFoundError('Transaction not found'));
}
if (error instanceof RippleError && error.remote &&
error.remote.error === 'txnNotFound') {
error = new errors.NotFoundError('Transaction not found');
}
// Missing complete ledger range
if (error instanceof errors.NotFoundError
&& !utils.hasCompleteLedgerRange(remote,
options.minLedgerVersion, maxLedgerVersion)) {
callback(new errors.MissingLedgerHistoryError('Transaction not found,'
+ ' but the server\'s ledger history is incomplete'));
} else if (!error && !isTransactionInRange(tx, options)) {
&& !utils.hasCompleteLedgerRange(remote, options.minLedgerVersion,
maxLedgerVersion)) {
if (utils.isPendingLedgerVersion(remote, maxLedgerVersion)) {
callback(new errors.PendingLedgerVersionError());
} else {
callback(new errors.MissingLedgerHistoryError());
}
// Transaction is found, but not in specified range
} else if (!error && tx && !isTransactionInRange(tx, options)) {
callback(new errors.NotFoundError('Transaction not found'));
// Transaction is not found
} else if (error) {
callback(error);
convertErrors(callback)(error);
} else if (!tx) {
callback(new errors.ApiError('Internal error'));
} else {
callback(error, parseTransaction(tx));
}
}
function maxLedgerGetter(error_?: Error, tx?: Object) {
this.getLedgerVersion().then((version) => {
const maxLedgerVersion = options.maxLedgerVersion || version;
callbackWrapper(error_, tx, maxLedgerVersion);
}, callbackWrapper);
}
async.waterfall([
_.partial(remote.requestTx.bind(remote), {hash: identifier, binary: false}),
_.partial(remote.requestTx.bind(remote),
{hash: identifier, binary: false}),
_.partial(attachTransactionDate, remote)
], callbackWrapper);
], maxLedgerGetter.bind(this));
}
module.exports = utils.wrapCatch(getTransaction);
function getTransaction(identifier: string,
options: TransactionOptions = {}
): Promise<GetTransactionResponse> {
return utils.promisify(getTransactionAsync).call(this, identifier, options);
}
module.exports = getTransaction;

View File

@@ -1,4 +1,5 @@
/* @flow */
/* eslint-disable max-params */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
@@ -6,6 +7,7 @@ const parseTransaction = require('./parse/transaction');
const getTransaction = require('./transaction');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
function parseAccountTxTransaction(tx) {
// rippled uses a different response format for 'account_tx' than 'tx'
@@ -14,6 +16,21 @@ function parseAccountTxTransaction(tx) {
return parseTransaction(tx.tx);
}
function counterpartyFilter(filters, tx) {
if (!filters.counterparty) {
return true;
}
if (tx.address === filters.counterparty || (
tx.specification && (
(tx.specification.destination &&
tx.specification.destination.address === filters.counterparty) ||
(tx.specification.counterparty === filters.counterparty)
))) {
return true;
}
return false;
}
function transactionFilter(address, filters, tx) {
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
return false;
@@ -27,8 +44,7 @@ function transactionFilter(address, filters, tx) {
if (filters.initiated === false && tx.address === address) {
return false;
}
if (filters.counterparty && tx.address !== filters.counterparty
&& tx.Destination !== filters.counterparty) {
if (filters.counterparty && !counterpartyFilter(filters, tx)) {
return false;
}
return true;
@@ -40,10 +56,23 @@ function orderFilter(options, tx) {
utils.compareTransactions(tx, options.startTx) < 0);
}
function formatPartialResponse(address, options, data) {
return {
marker: data.marker,
results: data.transactions
.filter((tx) => tx.validated)
.map(parseAccountTxTransaction)
.filter(_.partial(transactionFilter, address, options))
.filter(_.partial(orderFilter, options))
};
}
function getAccountTx(remote, address, options, marker, limit, callback) {
const params = {
account: address,
// -1 is equivalent to earliest available validated ledger
ledger_index_min: options.minLedgerVersion || -1,
// -1 is equivalent to most recent available validated ledger
ledger_index_max: options.maxLedgerVersion || -1,
forward: options.earliestFirst,
binary: options.binary,
@@ -51,16 +80,9 @@ function getAccountTx(remote, address, options, marker, limit, callback) {
marker: marker
};
remote.requestAccountTx(params, (error, data) => {
return error ? callback(error) : callback(null, {
marker: data.marker,
results: data.transactions
.filter((tx) => tx.validated)
.map(parseAccountTxTransaction)
.filter(_.partial(transactionFilter, address, options))
.filter(_.partial(orderFilter, options))
});
});
remote.requestAccountTx(params,
composeAsync(_.partial(formatPartialResponse, address, options),
convertErrors(callback)));
}
function checkForLedgerGaps(remote, options, transactions) {
@@ -97,27 +119,27 @@ function getTransactionsInternal(remote, address, options, callback) {
utils.getRecursive(getter, options.limit, composeAsync(format, callback));
}
function getTransactions(address, options, callback) {
validate.address(address);
function getTransactionsAsync(account, options, callback) {
validate.address(account);
validate.getTransactionsOptions(options);
const defaults = {maxLedgerVersion: this.remote.getLedgerSequence()};
const defaults = {maxLedgerVersion: -1};
if (options.start) {
getTransaction.bind(this)(options.start, {}, (error, tx) => {
if (error) {
callback(error);
return;
}
getTransaction.call(this, options.start).then(tx => {
const ledgerVersion = tx.outcome.ledgerVersion;
const bound = options.earliestFirst ?
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion};
const newOptions = _.assign(defaults, options, {startTx: tx}, bound);
getTransactionsInternal(this.remote, address, newOptions, callback);
});
getTransactionsInternal(this.remote, account, newOptions, callback);
}).catch(callback);
} else {
const newOptions = _.assign(defaults, options);
getTransactionsInternal(this.remote, address, newOptions, callback);
getTransactionsInternal(this.remote, account, newOptions, callback);
}
}
module.exports = utils.wrapCatch(getTransactions);
function getTransactions(account: string, options = {}) {
return utils.promisify(getTransactionsAsync).call(this, account, options);
}
module.exports = getTransactions;

View File

@@ -1,16 +1,28 @@
/* @flow */
'use strict';
const _ = require('lodash');
const async = require('async');
const utils = require('./utils');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const convertErrors = utils.common.convertErrors;
const parseAccountTrustline = require('./parse/account-trustline');
function currencyFilter(currency, trustline) {
return currency === null || trustline.specification.currency === currency;
}
function formatResponse(options, data) {
return {
marker: data.marker,
results: data.lines.map(parseAccountTrustline)
.filter(_.partial(currencyFilter, options.currency || null))
};
}
function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
callback) {
callback
) {
const requestOptions = {
account: address,
ledger: ledgerVersion,
@@ -19,27 +31,27 @@ function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
peer: options.counterparty
};
remote.requestAccountLines(requestOptions, (error, data) => {
return error ? callback(error) :
callback(null, {
marker: data.marker,
results: data.lines.map(parseAccountTrustline)
.filter(_.partial(currencyFilter, options.currency || null))
});
});
remote.requestAccountLines(requestOptions,
composeAsync(_.partial(formatResponse, options),
convertErrors(callback)));
}
function getTrustlines(account: string, options: {currency: string,
function getTrustlinesAsync(account: string, options: {currency: string,
counterparty: string, limit: number, ledgerVersion: number},
callback: () => void): void {
callback: () => void
): void {
validate.address(account);
validate.getTrustlinesOptions(options);
const ledgerVersion = options.ledgerVersion
|| this.remote.getLedgerSequence();
const getter = _.partial(getAccountLines, this.remote, account,
ledgerVersion, options);
options.ledgerVersion, options);
utils.getRecursive(getter, options.limit, callback);
}
module.exports = utils.wrapCatch(getTrustlines);
function getTrustlines(account: string, options = {}) {
return utils.promisify(async.seq(
utils.getLedgerOptionsWithLedgerVersion,
getTrustlinesAsync)).call(this, account, options);
}
module.exports = getTrustlines;

View File

@@ -1,23 +1,33 @@
/* @flow */
'use strict';
const _ = require('lodash');
const assert = require('assert');
const common = require('../common');
const dropsToXrp = common.dropsToXrp;
const composeAsync = common.composeAsync;
import type {Remote} from '../../core/remote';
function clamp(value, min, max) {
type Callback = (err: any, data: any) => void
function clamp(value: number, min: number, max: number): number {
assert(min <= max, 'Illegal clamp bounds');
return Math.min(Math.max(value, min), max);
}
function getXRPBalance(remote, address, ledgerVersion, callback) {
function getXRPBalance(remote: Remote, address: string, ledgerVersion?: number,
callback: Callback
): void {
remote.requestAccountInfo({account: address, ledger: ledgerVersion},
composeAsync((data) => dropsToXrp(data.account_data.Balance), callback));
}
type Getter = (marker: ?string, limit: number, callback: Callback) => void
// If the marker is omitted from a response, you have reached the end
// getter(marker, limit, callback), callback(error, {marker, results})
function getRecursiveRecur(getter, marker, limit, callback) {
function getRecursiveRecur(getter: Getter, marker?: string, limit: number,
callback: Callback
): void {
getter(marker, limit, (error, data) => {
if (error) {
return callback(error);
@@ -34,11 +44,13 @@ function getRecursiveRecur(getter, marker, limit, callback) {
});
}
function getRecursive(getter, limit, callback) {
function getRecursive(getter: Getter, limit?: number, callback: Callback) {
getRecursiveRecur(getter, undefined, limit || Infinity, callback);
}
function renameCounterpartyToIssuer(amount) {
type Amount = {counterparty?: string, issuer?: string, value: string}
function renameCounterpartyToIssuer(amount?: Amount): ?{issuer?: string} {
if (amount === undefined) {
return undefined;
}
@@ -48,7 +60,9 @@ function renameCounterpartyToIssuer(amount) {
return _.omit(withIssuer, 'counterparty');
}
function renameCounterpartyToIssuerInOrder(order) {
type Order = {taker_gets: Amount, taker_pays: Amount}
function renameCounterpartyToIssuerInOrder(order: Order) {
const taker_gets = renameCounterpartyToIssuer(order.taker_gets);
const taker_pays = renameCounterpartyToIssuer(order.taker_pays);
const changes = {taker_gets: taker_gets, taker_pays: taker_pays};
@@ -70,28 +84,58 @@ function signum(num) {
* @returns {Number} [-1, 0, 1]
*/
function compareTransactions(first, second) {
if (first.ledgerVersion === second.ledgerVersion) {
return signum(Number(first.indexInLedger) - Number(second.indexInLedger));
type Outcome = {outcome: {ledgerVersion: number, indexInLedger: number}};
function compareTransactions(first: Outcome, second: Outcome): number {
if (!first.outcome || !second.outcome) {
return 0;
}
return Number(first.ledgerVersion) < Number(second.ledgerVersion) ? -1 : 1;
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger);
}
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1;
}
function hasCompleteLedgerRange(remote, minLedgerVersion, maxLedgerVersion) {
function hasCompleteLedgerRange(remote: Remote, minLedgerVersion?: number,
maxLedgerVersion?: number
): boolean {
const firstLedgerVersion = 32570; // earlier versions have been lost
return remote.getServer().hasLedgerRange(
minLedgerVersion || firstLedgerVersion,
maxLedgerVersion || remote.getLedgerSequence());
maxLedgerVersion || remote.getLedgerSequenceSync());
}
function isPendingLedgerVersion(remote: Remote, maxLedgerVersion: ?number
): boolean {
const currentLedger = remote.getLedgerSequenceSync();
return currentLedger < (maxLedgerVersion || 0);
}
function getLedgerOptionsWithLedgerVersion(account: string, options: Object,
callback: (err?: ?Error, account?: string, options: Object) => void
) {
if (Boolean(options) && options.ledgerVersion !== undefined &&
options.ledgerVersion !== null
) {
callback(null, account, options);
} else {
this.getLedgerVersion().then((version) => {
callback(null, account, _.assign({}, options, {ledgerVersion: version}));
}, callback);
}
}
module.exports = {
getXRPBalance,
getLedgerOptionsWithLedgerVersion,
compareTransactions,
renameCounterpartyToIssuer,
renameCounterpartyToIssuerInOrder,
getRecursive,
hasCompleteLedgerRange,
wrapCatch: common.wrapCatch,
isPendingLedgerVersion,
promisify: common.promisify,
clamp: clamp,
common: common
};

View File

@@ -0,0 +1,74 @@
/* @flow */
'use strict';
const _ = require('lodash');
const common = require('../common');
function convertLedgerHeader(header) {
return {
accepted: header.accepted,
closed: header.closed,
account_hash: header.stateHash,
close_time: header.closeTime,
close_time_resolution: header.closeTimeResolution,
close_flags: header.closeFlags,
hash: header.ledgerHash,
ledger_hash: header.ledgerHash,
ledger_index: header.ledgerVersion.toString(),
seqNum: header.ledgerVersion.toString(),
parent_hash: header.parentLedgerHash,
parent_close_time: header.parentCloseTime,
total_coins: header.totalDrops,
totalCoins: header.totalDrops,
transaction_hash: header.transactionHash
};
}
function hashLedgerHeader(ledgerHeader) {
const header = convertLedgerHeader(ledgerHeader);
return common.core.Ledger.calculateLedgerHash(header);
}
function computeTransactionHash(ledger) {
if (ledger.rawTransactions === undefined) {
return ledger.transactionHash;
}
const transactions = JSON.parse(ledger.rawTransactions);
const txs = _.map(transactions, tx => {
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {});
const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'),
tx.meta ? {metaData: tx.meta} : {});
return renameMeta;
});
const ledgerObject = common.core.Ledger.from_json({transactions: txs});
const transactionHash = ledgerObject.calc_tx_hash().to_hex();
if (ledger.transactionHash !== undefined
&& ledger.transactionHash !== transactionHash) {
throw new common.errors.ValidationError('transactionHash in header'
+ ' does not match computed hash of transactions');
}
return transactionHash;
}
function computeStateHash(ledger) {
if (ledger.rawState === undefined) {
return ledger.stateHash;
}
const state = JSON.parse(ledger.rawState);
const ledgerObject = common.core.Ledger.from_json({accountState: state});
const stateHash = ledgerObject.calc_account_hash().to_hex();
if (ledger.stateHash !== undefined && ledger.stateHash !== stateHash) {
throw new common.errors.ValidationError('stateHash in header'
+ ' does not match computed hash of state');
}
return stateHash;
}
function computeLedgerHash(ledger: Object): string {
const hashes = {
transactionHash: computeTransactionHash(ledger),
stateHash: computeStateHash(ledger)
};
return hashLedgerHeader(_.assign({}, ledger, hashes));
}
module.exports = computeLedgerHash;

View File

@@ -2,20 +2,43 @@
'use strict';
const _ = require('lodash');
const common = require('../common');
import type {Remote} from '../../core/remote';
// If a ledger is not received in this time, consider the connection offline
const CONNECTION_TIMEOUT = 1000 * 30;
function connect(callback: (err: any, data: any) => void): void {
this.remote.connect(callback);
type GetServerInfoResponse = {
buildVersion: string,
completeLedgers: string,
hostid: string,
ioLatencyMs: number,
load?: {
jobTypes: Array<Object>,
threads: number
},
lastClose: {
convergeTimeS: number,
proposers: number
},
loadFactor: number,
peers: number,
pubkeyNode: string,
pubkeyValidator?: string,
serverState: string,
validatedLedger: {
age: number,
baseFeeXrp: number,
hash: string,
reserveBaseXrp: number,
reserveIncXrp: number,
seq: number
},
validationQuorum: number
}
function disconnect(callback: (err: any, data: any) => void): void {
this.remote.disconnect(callback);
}
function isUpToDate(remote): boolean {
function isUpToDate(remote: Remote): boolean {
const server = remote.getServer();
return Boolean(server) && (remote._stand_alone
|| (Date.now() - server._lastLedgerClose) <= CONNECTION_TIMEOUT);
@@ -25,22 +48,72 @@ function isConnected(): boolean {
return Boolean(this.remote._ledger_current_index) && isUpToDate(this.remote);
}
function getServerInfo(callback: (err: any, data: any) => void): void {
function getServerInfoAsync(
callback: (err: any, data?: GetServerInfoResponse) => void
): void {
this.remote.requestServerInfo((error, response) => {
if (error) {
callback(new common.errors.RippledNetworkError(error.message));
const message = _.get(error, ['remote', 'error_message'], error.message);
callback(new common.errors.RippledNetworkError(message));
} else {
callback(null, response.info);
callback(null,
common.convertKeysFromSnakeCaseToCamelCase(response.info));
}
});
}
function getFee(): number {
return common.dropsToXrp(this.remote.createTransaction()._computeFee());
function getFee(): ?number {
if (!this.remote.getConnectedServers().length) {
throw new common.errors.RippledNetworkError('No servers available.');
}
const fee = this.remote.createTransaction()._computeFee();
return fee === undefined ? undefined : common.dropsToXrp(fee);
}
function getLedgerVersion(): number {
return this.remote.getLedgerSequence();
function getLedgerVersion(): Promise<number> {
return common.promisify(this.remote.getLedgerSequence).call(this.remote);
}
function connect(): Promise<void> {
return common.promisify(callback => {
try {
this.remote.connect(() => callback(null));
} catch(error) {
callback(new common.errors.RippledNetworkError(error.message));
}
})();
}
function disconnect(): Promise<void> {
return common.promisify(callback => {
try {
this.remote.disconnect(() => callback(null));
} catch(error) {
callback(new common.errors.RippledNetworkError(error.message));
}
})();
}
function getServerInfo(): Promise<GetServerInfoResponse> {
return common.promisify(getServerInfoAsync).call(this);
}
function rippleTimeToISO8601(rippleTime: string): string {
return new Date(common.core.utils.toTimestamp(rippleTime)).toISOString();
}
function formatLedgerClose(ledgerClose: Object): Object {
return {
feeBase: ledgerClose.fee_base,
feeReference: ledgerClose.fee_ref,
ledgerHash: ledgerClose.ledger_hash,
ledgerVersion: ledgerClose.ledger_index,
ledgerTimestamp: rippleTimeToISO8601(ledgerClose.ledger_time),
reserveBase: ledgerClose.reserve_base,
reserveIncrement: ledgerClose.reserve_inc,
transactionCount: ledgerClose.txn_count,
validatedLedgerVersions: ledgerClose.validated_ledgers
};
}
module.exports = {
@@ -49,5 +122,6 @@ module.exports = {
isConnected,
getServerInfo,
getFee,
getLedgerVersion
getLedgerVersion,
formatLedgerClose
};

View File

@@ -30,9 +30,14 @@ function createOrderTransaction(account, order) {
return transaction;
}
function prepareOrder(account, order, instructions, callback) {
function prepareOrderAsync(account, order, instructions, callback) {
const transaction = createOrderTransaction(account, order);
utils.createTxJSON(transaction, this.remote, instructions, callback);
utils.prepareTransaction(transaction, this.remote, instructions, callback);
}
module.exports = utils.wrapCatch(prepareOrder);
function prepareOrder(account: string, order: Object, instructions = {}) {
return utils.promisify(prepareOrderAsync.bind(this))(
account, order, instructions);
}
module.exports = prepareOrder;

View File

@@ -13,9 +13,18 @@ function createOrderCancellationTransaction(account, sequence) {
return transaction;
}
function prepareOrderCancellation(account, sequence, instructions, callback) {
function prepareOrderCancellationAsync(account, sequence, instructions,
callback
) {
const transaction = createOrderCancellationTransaction(account, sequence);
utils.createTxJSON(transaction, this.remote, instructions, callback);
utils.prepareTransaction(transaction, this.remote, instructions, callback);
}
module.exports = utils.wrapCatch(prepareOrderCancellation);
function prepareOrderCancellation(account: string, sequence: number,
instructions = {}
) {
return utils.promisify(prepareOrderCancellationAsync.bind(this))(
account, sequence, instructions);
}
module.exports = prepareOrderCancellation;

View File

@@ -1,21 +1,16 @@
/* @flow */
'use strict';
const _ = require('lodash');
const BigNumber = require('bignumber.js');
const utils = require('./utils');
const validate = utils.common.validate;
const toRippledAmount = utils.common.toRippledAmount;
const Transaction = utils.common.core.Transaction;
const ValidationError = utils.common.errors.ValidationError;
function isSendMaxAllowed(payment) {
const srcAmt = payment.source.amount;
const dstAmt = payment.destination.amount;
// Don't set SendMax for XRP->XRP payment
// temREDUNDANT_SEND_MAX removed in:
// https://github.com/ripple/rippled/commit/
// c522ffa6db2648f1d8a987843e7feabf1a0b7de8/
return srcAmt && !(srcAmt.currency === 'XRP' && dstAmt.currency === 'XRP');
function isXRPToXRPPayment(payment) {
const sourceCurrency = _.get(payment, 'source.maxAmount.currency');
const destinationCurrency = _.get(payment, 'destination.amount.currency');
return sourceCurrency === 'XRP' && destinationCurrency === 'XRP';
}
function isIOUWithoutCounterparty(amount) {
@@ -29,24 +24,49 @@ function applyAnyCounterpartyEncoding(payment) {
// https://ripple.com/build/transactions/
// #special-issuer-values-for-sendmax-and-amount
// https://ripple.com/build/ripple-rest/#counterparties-in-payments
if (isIOUWithoutCounterparty(payment.source.amount)) {
payment.source.amount.counterparty = payment.source.address;
}
if (isIOUWithoutCounterparty(payment.destination.amount)) {
payment.destination.amount.counterparty = payment.destination.address;
}
_.forEach([payment.source, payment.destination], (adjustment) => {
_.forEach(['amount', 'minAmount', 'maxAmount'], (key) => {
if (isIOUWithoutCounterparty(adjustment[key])) {
adjustment[key].counterparty = adjustment.address;
}
});
});
}
function createPaymentTransaction(account, payment) {
function createMaximalAmount(amount) {
const maxXRPValue = '100000000000';
const maxIOUValue = '9999999999999999e80';
const maxValue = amount.currency === 'XRP' ? maxXRPValue : maxIOUValue;
return _.assign(amount, {value: maxValue});
}
function createPaymentTransaction(account, paymentArgument) {
const payment = _.cloneDeep(paymentArgument);
applyAnyCounterpartyEncoding(payment);
validate.address(account);
validate.payment(payment);
if ((payment.source.maxAmount && payment.destination.minAmount) ||
(payment.source.amount && payment.destination.amount)) {
throw new ValidationError('payment must specify either (source.maxAmount '
+ 'and destination.amount) or (source.amount and destination.minAmount)');
}
// when using destination.minAmount, rippled still requires that we set
// a destination amount in addition to DeliverMin. the destination amount
// is interpreted as the maximum amount to send. we want to be sure to
// send the whole source amount, so we set the destination amount to the
// maximum possible amount. otherwise it's possible that the destination
// cap could be hit before the source cap.
const amount = payment.destination.minAmount && !isXRPToXRPPayment(payment) ?
createMaximalAmount(payment.destination.minAmount) :
(payment.destination.amount || payment.destination.minAmount);
const transaction = new Transaction();
transaction.payment({
from: payment.source.address,
to: payment.destination.address,
amount: toRippledAmount(payment.destination.amount)
amount: toRippledAmount(amount)
});
if (payment.invoiceID) {
@@ -58,36 +78,51 @@ function createPaymentTransaction(account, payment) {
if (payment.destination.tag) {
transaction.destinationTag(payment.destination.tag);
}
if (payment.paths) {
transaction.paths(JSON.parse(payment.paths));
}
if (payment.memos) {
_.forEach(payment.memos, memo =>
transaction.addMemo(memo.type, memo.format, memo.data)
);
}
if (payment.allowPartialPayment) {
transaction.setFlags(['PartialPayment']);
}
if (payment.noDirectRipple) {
transaction.setFlags(['NoRippleDirect']);
}
if (payment.limitQuality) {
transaction.setFlags(['LimitQuality']);
}
if (isSendMaxAllowed(payment)) {
const maxValue = new BigNumber(payment.source.amount.value)
.plus(payment.source.slippage || 0).toString();
const maxAmount = _.assign({}, payment.source.amount, {value: maxValue});
transaction.sendMax(toRippledAmount(maxAmount));
if (!isXRPToXRPPayment(payment)) {
// Don't set SendMax for XRP->XRP payment
// temREDUNDANT_SEND_MAX removed in:
// https://github.com/ripple/rippled/commit/
// c522ffa6db2648f1d8a987843e7feabf1a0b7de8/
if (payment.allowPartialPayment || payment.destination.minAmount) {
transaction.setFlags(['PartialPayment']);
}
transaction.setSendMax(toRippledAmount(
payment.source.maxAmount || payment.source.amount));
if (payment.destination.minAmount) {
transaction.setDeliverMin(toRippledAmount(payment.destination.minAmount));
}
if (payment.paths) {
transaction.paths(JSON.parse(payment.paths));
}
} else if (payment.allowPartialPayment) {
throw new ValidationError('XRP to XRP payments cannot be partial payments');
}
return transaction;
}
function preparePayment(account, payment, instructions, callback) {
function preparePaymentAsync(account, payment, instructions, callback) {
const transaction = createPaymentTransaction(account, payment);
utils.createTxJSON(transaction, this.remote, instructions, callback);
utils.prepareTransaction(transaction, this.remote, instructions, callback);
}
module.exports = utils.wrapCatch(preparePayment);
function preparePayment(account: string, payment: Object, instructions = {}) {
return utils.promisify(preparePaymentAsync.bind(this))(
account, payment, instructions);
}
module.exports = preparePayment;

View File

@@ -1,7 +1,7 @@
/* @flow */
'use strict';
const _ = require('lodash');
const assert = require('assert');
const BigNumber = require('bignumber.js');
const utils = require('./utils');
const validate = utils.common.validate;
const AccountFlagIndices = utils.common.constants.AccountFlagIndices;
@@ -9,7 +9,7 @@ const AccountFields = utils.common.constants.AccountFields;
const Transaction = utils.common.core.Transaction;
// Emptry string passed to setting will clear it
const CLEAR_SETTING = '';
const CLEAR_SETTING = null;
function setTransactionFlags(transaction, values) {
const keys = Object.keys(values);
@@ -64,7 +64,7 @@ function setTransactionFields(transaction, input) {
*/
function convertTransferRate(transferRate) {
return _.isNumber(transferRate) ? transferRate * 1e9 : transferRate;
return (new BigNumber(transferRate)).shift(9).toNumber();
}
function createSettingsTransaction(account, settings) {
@@ -90,9 +90,14 @@ function createSettingsTransaction(account, settings) {
return transaction;
}
function prepareSettings(account, settings, instructions, callback) {
function prepareSettingsAsync(account, settings, instructions, callback) {
const transaction = createSettingsTransaction(account, settings);
utils.createTxJSON(transaction, this.remote, instructions, callback);
utils.prepareTransaction(transaction, this.remote, instructions, callback);
}
module.exports = utils.wrapCatch(prepareSettings);
function prepareSettings(account: string, settings: Object, instructions = {}) {
return utils.promisify(prepareSettingsAsync.bind(this))(
account, settings, instructions);
}
module.exports = prepareSettings;

View File

@@ -1,6 +1,7 @@
/* @flow */
'use strict';
const utils = require('./utils');
const keypairs = require('ripple-keypairs');
const core = utils.common.core;
const validate = utils.common.validate;
@@ -15,16 +16,6 @@ const validate = utils.common.validate;
* some arbitrary string. For example "TXN".
*/
const HASH_TX_ID = 0x54584E00; // 'TXN'
const HASH_TX_SIGN = 0x53545800; // 'STX'
const HASH_TX_SIGN_TESTNET = 0x73747800; // 'stx'
function getKeyPair(address, secret) {
return core.Seed.from_json(secret).get_key(address);
}
function getPublicKeyHex(keypair) {
return keypair.to_hex_pub();
}
function serialize(txJSON) {
return core.SerializedObject.from_json(txJSON);
@@ -34,31 +25,26 @@ function hashSerialization(serialized, prefix) {
return serialized.hash(prefix || HASH_TX_ID).to_hex();
}
function hashJSON(txJSON, prefix) {
return hashSerialization(serialize(txJSON), prefix);
function signingData(txJSON) {
return core.Transaction.from_json(txJSON).signingData().buffer;
}
function signingHash(txJSON, isTestNet=false) {
return hashJSON(txJSON, isTestNet ? HASH_TX_SIGN_TESTNET : HASH_TX_SIGN);
function computeSignature(txJSON, privateKey) {
return keypairs.sign(signingData(txJSON), privateKey);
}
function computeSignature(txJSON, keypair) {
const signature = keypair.sign(signingHash(txJSON));
return core.sjcl.codec.hex.fromBits(signature).toUpperCase();
}
function sign(txJSON: string, secret: string
): {signedTransaction: string; id: string} {
const tx = JSON.parse(txJSON);
validate.txJSON(tx);
validate.secret(secret);
function sign(txJSON: {Account: string; SigningPubKey: string,
TxnSignature: string}, secret: string):
{signedTransaction: string; id: string} {
validate.txJSON(txJSON);
validate.addressAndSecret({address: txJSON.Account, secret: secret});
const keypair = getKeyPair(txJSON.Account, secret);
if (txJSON.SigningPubKey === undefined) {
txJSON.SigningPubKey = getPublicKeyHex(keypair);
const keypair = keypairs.deriveKeypair(secret);
if (tx.SigningPubKey === undefined) {
tx.SigningPubKey = keypair.publicKey;
}
txJSON.TxnSignature = computeSignature(txJSON, keypair);
const serialized = serialize(txJSON);
tx.TxnSignature = computeSignature(tx, keypair.privateKey);
const serialized = serialize(tx);
return {
signedTransaction: serialized.to_hex(),
id: hashSerialization(serialized, HASH_TX_ID)

View File

@@ -1,15 +1,44 @@
/* @flow */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const validate = utils.common.validate;
const Request = utils.common.core.Request;
const convertErrors = utils.common.convertErrors;
function submit(tx_blob: string,
callback: (err: any, data: any) => void): void {
validate.blob(tx_blob);
function isImmediateRejection(engineResult) {
// note: "tel" errors mean the local server refused to process the
// transaction *at that time*, but it could potentially buffer the
// transaction and then process it at a later time, for example
// if the required fee changes (this does not occur at the time of
// this writing, but it could change in the future)
// all other error classes can potentially result in transcation validation
return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej');
}
function convertSubmitErrors(callback) {
return function(error, data) {
if (!error && isImmediateRejection(data.engineResult)) {
callback(new utils.common.errors.RippleError('Submit failed'), data);
} else {
callback(error, data);
}
};
}
function submitAsync(txBlob: string, callback: (err: any, data: any) => void
): void {
validate.blob(txBlob);
const request = new Request(this.remote, 'submit');
request.message.tx_blob = tx_blob;
request.request(null, callback);
request.message.tx_blob = txBlob;
request.request(null,
utils.common.composeAsync(
data => utils.common.convertKeysFromSnakeCaseToCamelCase(data),
convertSubmitErrors(convertErrors(callback))));
}
function submit(txBlob: string) {
return utils.promisify(submitAsync.bind(this))(txBlob);
}
module.exports = submit;

View File

@@ -0,0 +1,40 @@
/* @flow */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const validate = utils.common.validate;
const Transaction = utils.common.core.Transaction;
function createSuspendedPaymentCancellationTransaction(account, payment) {
validate.address(account);
validate.suspendedPaymentCancellation(payment);
const transaction = new Transaction();
transaction.suspendedPaymentCancel({
account: account,
owner: payment.owner,
paymentSequence: payment.paymentSequence
});
if (payment.memos) {
_.forEach(payment.memos, memo =>
transaction.addMemo(memo.type, memo.format, memo.data)
);
}
return transaction;
}
function prepareSuspendedPaymentCancellationAsync(account, payment,
instructions, callback) {
const transaction =
createSuspendedPaymentCancellationTransaction(account, payment);
utils.prepareTransaction(transaction, this.remote, instructions, callback);
}
function prepareSuspendedPaymentCancellation(account: string, payment: Object,
instructions = {}) {
return utils.promisify(prepareSuspendedPaymentCancellationAsync)
.call(this, account, payment, instructions);
}
module.exports = prepareSuspendedPaymentCancellation;

View File

@@ -0,0 +1,57 @@
/* @flow */
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const validate = utils.common.validate;
const toRippledAmount = utils.common.toRippledAmount;
const Transaction = utils.common.core.Transaction;
function createSuspendedPaymentCreationTransaction(account, payment) {
validate.address(account);
validate.suspendedPaymentCreation(payment);
const transaction = new Transaction();
transaction.suspendedPaymentCreate({
account: account,
destination: payment.destination.address,
amount: toRippledAmount(payment.destination.amount)
});
if (payment.digest) {
transaction.setDigest(payment.digest);
}
if (payment.allowCancelAfter) {
transaction.setAllowCancelAfter(payment.allowCancelAfter);
}
if (payment.allowExecuteAfter) {
transaction.setAllowExecuteAfter(payment.allowExecuteAfter);
}
if (payment.source.tag) {
transaction.sourceTag(payment.source.tag);
}
if (payment.destination.tag) {
transaction.destinationTag(payment.destination.tag);
}
if (payment.memos) {
_.forEach(payment.memos, memo =>
transaction.addMemo(memo.type, memo.format, memo.data)
);
}
return transaction;
}
function prepareSuspendedPaymentCreationAsync(account, payment, instructions,
callback) {
const transaction =
createSuspendedPaymentCreationTransaction(account, payment);
utils.prepareTransaction(transaction, this.remote, instructions, callback);
}
function prepareSuspendedPaymentCreation(account: string, payment: Object,
instructions = {}) {
return utils.promisify(prepareSuspendedPaymentCreationAsync)
.call(this, account, payment, instructions);
}
module.exports = prepareSuspendedPaymentCreation;

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