mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-17 19:05:47 +00:00
Compare commits
233 Commits
0.13.0-rc2
...
0.13.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed40eec711 | ||
|
|
43488c55f1 | ||
|
|
2f727b553c | ||
|
|
29c37aa6da | ||
|
|
64baef431d | ||
|
|
634fe5683a | ||
|
|
225ca3f852 | ||
|
|
ff2ac6c3cd | ||
|
|
607777f2a3 | ||
|
|
78eeb40322 | ||
|
|
772f79ae21 | ||
|
|
806a4e823f | ||
|
|
323e402e0c | ||
|
|
9ebb59580d | ||
|
|
bafab6eb18 | ||
|
|
35acbb62c3 | ||
|
|
4676ade4ee | ||
|
|
8edc3b1f36 | ||
|
|
8acfb1a537 | ||
|
|
ac78171099 | ||
|
|
d573c5746b | ||
|
|
51e8f9a87a | ||
|
|
bfe590d96d | ||
|
|
60e2d10775 | ||
|
|
2f432cef62 | ||
|
|
5217b66396 | ||
|
|
b8bb191d24 | ||
|
|
8070a52dc7 | ||
|
|
3205f3cf8c | ||
|
|
e0cdd610dd | ||
|
|
ed3b04ed6f | ||
|
|
62a2d2ae39 | ||
|
|
e2c853e40d | ||
|
|
b9b5a71869 | ||
|
|
87fdbc932f | ||
|
|
84838b2e9f | ||
|
|
c2ca37a790 | ||
|
|
c6805b9f0d | ||
|
|
b1dbdc03dd | ||
|
|
88a3f3d43b | ||
|
|
5f8dcd71a5 | ||
|
|
45db95da79 | ||
|
|
c79b12b27f | ||
|
|
135da6108d | ||
|
|
0d6dda579f | ||
|
|
e641a347db | ||
|
|
3e17d91edf | ||
|
|
715c648d52 | ||
|
|
d0ebed9822 | ||
|
|
a3775f18ba | ||
|
|
7b5d6e9fc5 | ||
|
|
368ac0b9e0 | ||
|
|
0448696bd8 | ||
|
|
deb75ed0d7 | ||
|
|
fcc9bacb4e | ||
|
|
9a5e8fd2ba | ||
|
|
1c023c4377 | ||
|
|
c213b98329 | ||
|
|
27d2e6e519 | ||
|
|
7ee368965c | ||
|
|
d8b5b825b3 | ||
|
|
de67570230 | ||
|
|
60c604fbe6 | ||
|
|
2f6d25ed01 | ||
|
|
b134081293 | ||
|
|
a0528d7f9c | ||
|
|
348335ddf0 | ||
|
|
01752e5486 | ||
|
|
3e758e1b86 | ||
|
|
fb0b30a9a7 | ||
|
|
0c9aea454e | ||
|
|
f282585c3f | ||
|
|
ae5ff31c96 | ||
|
|
20fa8bc953 | ||
|
|
778f59b4fd | ||
|
|
49623cb4dd | ||
|
|
90b53002aa | ||
|
|
93c12af305 | ||
|
|
60f2419b5c | ||
|
|
80494ad813 | ||
|
|
b43c4a7ad4 | ||
|
|
3c608de5bb | ||
|
|
fe5bc1d215 | ||
|
|
580bf9a755 | ||
|
|
c7df5df163 | ||
|
|
a08c52af55 | ||
|
|
e11db0f0f3 | ||
|
|
c6e0582729 | ||
|
|
6e98629f9b | ||
|
|
2243760442 | ||
|
|
91dd6877aa | ||
|
|
e73bcd8fc1 | ||
|
|
7e886b3260 | ||
|
|
5c9451d3ed | ||
|
|
c6c2dcc6c0 | ||
|
|
0bdd37090e | ||
|
|
c745faaaf0 | ||
|
|
9ad03ca873 | ||
|
|
138914384e | ||
|
|
77068667e4 | ||
|
|
c57cef4a21 | ||
|
|
50acc4c708 | ||
|
|
b5f8ba4817 | ||
|
|
a53249ccd7 | ||
|
|
0c62fa2112 | ||
|
|
806547dd15 | ||
|
|
fb1669b2b3 | ||
|
|
0cda15f2b5 | ||
|
|
b88e9370c6 | ||
|
|
e343f3beb8 | ||
|
|
a13bfae714 | ||
|
|
877c6bbb2a | ||
|
|
30d5134394 | ||
|
|
fae5c74487 | ||
|
|
255332ea2e | ||
|
|
15c0e6db19 | ||
|
|
2b600a1e4e | ||
|
|
297fb2483d | ||
|
|
5049822415 | ||
|
|
e3787e0f4f | ||
|
|
683199044b | ||
|
|
4f3c3e9f66 | ||
|
|
fc0240c06b | ||
|
|
6bfa284bac | ||
|
|
dfee9bc578 | ||
|
|
0838a0e865 | ||
|
|
5f61d80e2d | ||
|
|
c4fa4c237c | ||
|
|
44d00d5ef4 | ||
|
|
d4d3efcb65 | ||
|
|
f23e105240 | ||
|
|
5a396a7060 | ||
|
|
513632299f | ||
|
|
0d40558f1e | ||
|
|
1ccbaf6776 | ||
|
|
ba6c703163 | ||
|
|
3b9eb02bbb | ||
|
|
bca7382015 | ||
|
|
67672bd389 | ||
|
|
232017d9a2 | ||
|
|
23653f67f0 | ||
|
|
e3b688d1dd | ||
|
|
a94b21ca3c | ||
|
|
9c9be3e6e4 | ||
|
|
062561686e | ||
|
|
761682c206 | ||
|
|
39c48d631c | ||
|
|
a55d26a726 | ||
|
|
597ae157b3 | ||
|
|
c1c7458914 | ||
|
|
0e97f269ab | ||
|
|
bbe4cd63a1 | ||
|
|
2515d17a85 | ||
|
|
d8e95a3c3b | ||
|
|
98f6bed8c9 | ||
|
|
bd000c2662 | ||
|
|
a46141111a | ||
|
|
f57c89c6e9 | ||
|
|
6d4cac948d | ||
|
|
1f54b3a0cf | ||
|
|
2f8655dc23 | ||
|
|
d624923cd8 | ||
|
|
2180c076dd | ||
|
|
0dbdf0a21a | ||
|
|
5cb63a258c | ||
|
|
39ac6caaef | ||
|
|
de4ef8b2b4 | ||
|
|
99cba09a4a | ||
|
|
300967f0f3 | ||
|
|
52879febb9 | ||
|
|
f077a563c4 | ||
|
|
92fbc61f47 | ||
|
|
5ac1bcc414 | ||
|
|
5837aa23ea | ||
|
|
8c431b4ec3 | ||
|
|
25086a7944 | ||
|
|
b0889b4afe | ||
|
|
ed971bc41c | ||
|
|
728595dc96 | ||
|
|
7fc6adb776 | ||
|
|
002102ce62 | ||
|
|
bf9da80d46 | ||
|
|
dda9994869 | ||
|
|
4c76ad159e | ||
|
|
f76a8daca8 | ||
|
|
3263629ebe | ||
|
|
fcbe7d3c98 | ||
|
|
a6662ccdff | ||
|
|
854fe85151 | ||
|
|
2b2fdf1b11 | ||
|
|
cbe44d6a96 | ||
|
|
420346faea | ||
|
|
6220162852 | ||
|
|
37198bde66 | ||
|
|
281c056f6c | ||
|
|
49a513cd07 | ||
|
|
7a95aabbf4 | ||
|
|
83874ec096 | ||
|
|
9270d0a33d | ||
|
|
30295efdb4 | ||
|
|
f1342c1456 | ||
|
|
194b73c293 | ||
|
|
89e5f79bbb | ||
|
|
82d7ce7ac2 | ||
|
|
0cc4c704f8 | ||
|
|
dde762a1d6 | ||
|
|
1c86e246c7 | ||
|
|
2d173c8e69 | ||
|
|
600fd34d30 | ||
|
|
4cb9cf801c | ||
|
|
50fb8789b4 | ||
|
|
fb8dc44ec1 | ||
|
|
0781caa8bc | ||
|
|
2cdb23f0dd | ||
|
|
8e536c00b9 | ||
|
|
8ff154cc2d | ||
|
|
daaae6e01e | ||
|
|
a64a4e697a | ||
|
|
3f51d8cc12 | ||
|
|
9f9e76f8b9 | ||
|
|
5b51db158d | ||
|
|
a4d1509448 | ||
|
|
bbd51a03b6 | ||
|
|
b55b82b2fd | ||
|
|
fdb0f101bd | ||
|
|
0afca5633d | ||
|
|
7c0d9a7172 | ||
|
|
f6b7e27c67 | ||
|
|
b8624bc55f | ||
|
|
2eec30756d | ||
|
|
6b44ce8973 | ||
|
|
ed0b501716 | ||
|
|
fe9c1ada88 |
@@ -26,6 +26,9 @@ function webpackConfig(extension, overrides) {
|
|||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader?optional=runtime'
|
loader: 'babel-loader?optional=runtime'
|
||||||
|
}, {
|
||||||
|
test: /\.json/,
|
||||||
|
loader: 'json-loader'
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
26
HISTORY.md
26
HISTORY.md
@@ -1,3 +1,29 @@
|
|||||||
|
##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**
|
||||||
|
+ [Implement Balance Sheet API](https://github.com/ripple/ripple-lib/pull/579)
|
||||||
|
+ [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
|
##0.12.6
|
||||||
|
|
||||||
+ [Fix webpack require failure due to "./" notation](https://github.com/ripple/ripple-lib/commit/8d9746d7b10be203ee613df523c2522012ff1baf)
|
+ [Fix webpack require failure due to "./" notation](https://github.com/ripple/ripple-lib/commit/8d9746d7b10be203ee613df523c2522012ff1baf)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A JavaScript API for interacting with Ripple in Node.js and the browser
|
A JavaScript API for interacting with Ripple in Node.js and the browser
|
||||||
|
|
||||||
[](https://travis-ci.org/ripple/ripple-lib) [](https://coveralls.io/r/ripple/ripple-lib?branch=develop)
|
[](https://circleci.com/gh/ripple/ripple-lib/tree/develop) [](https://coveralls.io/r/ripple/ripple-lib?branch=develop)
|
||||||
|
|
||||||
[](https://www.npmjs.org/package/ripple-lib)
|
[](https://www.npmjs.org/package/ripple-lib)
|
||||||
|
|
||||||
|
|||||||
17
bin/ci.sh
17
bin/ci.sh
@@ -5,19 +5,32 @@ TOTAL_NODES="$2"
|
|||||||
|
|
||||||
typecheck() {
|
typecheck() {
|
||||||
npm install -g flow-bin
|
npm install -g flow-bin
|
||||||
|
flow --version
|
||||||
npm run typecheck
|
npm run typecheck
|
||||||
}
|
}
|
||||||
|
|
||||||
lint() {
|
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"
|
REPO_URL="https://raw.githubusercontent.com/ripple/javascript-style-guide"
|
||||||
curl "$REPO_URL/es6/eslintrc" > ./eslintrc
|
curl "$REPO_URL/es6/eslintrc" > ./eslintrc
|
||||||
echo "plugins: [flowtype]" >> ./eslintrc
|
echo "parser: babel-eslint" >> ./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$")
|
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() {
|
unittest() {
|
||||||
|
# test "src"
|
||||||
npm test --coverage
|
npm test --coverage
|
||||||
npm run coveralls
|
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() {
|
oneNode() {
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ function toggle(element) {
|
|||||||
<h2><a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/index.js">RippleAPI</a></h2>
|
<h2><a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/index.js">RippleAPI</a></h2>
|
||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
connect(callback)
|
connect()
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
disconnect(callback)
|
disconnect()
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
@@ -40,7 +40,7 @@ isConnected()
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
getServerInfo(callback)
|
getServerInfo()
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
@@ -53,9 +53,9 @@ getLedgerVersion()
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/transaction-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
identifier: txhash
|
identifier: txhash
|
||||||
@@ -65,9 +65,9 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/transactions-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
options: {
|
options: {
|
||||||
@@ -87,9 +87,9 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/trustlines-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
options: {counterparty: address, currency: string, limit: int, ledgerVersion: int}
|
options: {counterparty: address, currency: string, limit: int, ledgerVersion: int}
|
||||||
@@ -98,9 +98,9 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/trustlines-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
options: {counterparty: address, currency: string, limit: int, ledgerVersion: int}
|
options: {counterparty: address, currency: string, limit: int, ledgerVersion: int}
|
||||||
@@ -109,8 +109,8 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/pathfind.json">pathfind</a>
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
pathfind: {
|
pathfind: {
|
||||||
@@ -131,9 +131,9 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/orders-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
options: {limit: int, ledverVersion: int}
|
options: {limit: int, ledverVersion: int}
|
||||||
@@ -143,9 +143,9 @@ callback)
|
|||||||
<div class="method">
|
<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/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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/orders-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
orderbook: {
|
orderbook: {
|
||||||
@@ -164,9 +164,9 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/settings-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
options: {ledgerVersion: int}
|
options: {ledgerVersion: int}
|
||||||
@@ -175,9 +175,9 @@ callback)
|
|||||||
|
|
||||||
<div class="method">
|
<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/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/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="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/settings-options.json">options</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
options: {ledgerVersion: int}
|
options: {ledgerVersion: int}
|
||||||
@@ -187,9 +187,9 @@ callback)
|
|||||||
<div class="method">
|
<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/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/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/payment.json">payment</a>[,
|
||||||
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>,
|
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
payment: {
|
payment: {
|
||||||
@@ -224,9 +224,9 @@ callback)
|
|||||||
<div class="method">
|
<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/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/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/trustline.json">trustline</a>[,
|
||||||
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>,
|
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
trustline: {
|
trustline: {
|
||||||
@@ -253,9 +253,9 @@ callback)
|
|||||||
<div class="method">
|
<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/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/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/order.json">order</a>[,
|
||||||
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>,
|
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
order: {
|
order: {
|
||||||
@@ -282,9 +282,9 @@ callback)
|
|||||||
<div class="method">
|
<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/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/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/sequence.json">sequence</a>[,
|
||||||
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>,
|
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
sequence: int
|
sequence: int
|
||||||
@@ -302,9 +302,9 @@ callback)
|
|||||||
<div class="method">
|
<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/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/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/settings.json">settings</a>[,
|
||||||
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>,
|
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/instructions.json">instructions</a>]
|
||||||
callback)
|
)
|
||||||
<a href="#" onclick="javascript:toggle(this)">+</a>
|
<a href="#" onclick="javascript:toggle(this)">+</a>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
settings: {
|
settings: {
|
||||||
@@ -345,8 +345,8 @@ secret)
|
|||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
submit(
|
submit(
|
||||||
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/blob.json">txBlob</a>,
|
<a href="https://github.com/ripple/ripple-lib/blob/develop/src/api/common/schemas/blob.json">txBlob</a>
|
||||||
callback)
|
)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="method">
|
<div class="method">
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ const RippleAPI = require('../../src').RippleAPI; // require('ripple-lib')
|
|||||||
const api = new RippleAPI({servers: ['wss://s1.ripple.com:443']});
|
const api = new RippleAPI({servers: ['wss://s1.ripple.com:443']});
|
||||||
const address = 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV';
|
const address = 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV';
|
||||||
|
|
||||||
api.connect(() => {
|
api.connect().then(() => {
|
||||||
api.getBalances(address, {}, (error, balances) => {
|
api.getBalances(address).then(balances => {
|
||||||
console.log(JSON.stringify(balances, null, 2));
|
console.log(JSON.stringify(balances, null, 2));
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const RippleAPI = require('../../src').RippleAPI; // require('ripple-lib')
|
const RippleAPI = require('../../src').RippleAPI; // require('ripple-lib')
|
||||||
|
|
||||||
const address = 'ENTER ADDRESS HERE';
|
const address = 'INSERT ADDRESS HERE';
|
||||||
const secret = 'ENTER SECRET HERE';
|
const secret = 'INSERT SECRET HERE';
|
||||||
|
|
||||||
const api = new RippleAPI({servers: ['wss://s1.ripple.com:443']});
|
const api = new RippleAPI({servers: ['wss://s1.ripple.com:443']});
|
||||||
const instructions = {maxLedgerVersionOffset: 5};
|
const instructions = {maxLedgerVersionOffset: 5};
|
||||||
@@ -24,15 +24,18 @@ const payment = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
api.connect(() => {
|
api.connect().then(() => {
|
||||||
console.log('Connected...');
|
console.log('Connected...');
|
||||||
api.preparePayment(address, payment, instructions, (error, txJSON) => {
|
api.preparePayment(address, payment, instructions).then(txJSON => {
|
||||||
console.log('Payment transaction prepared...');
|
console.log('Payment transaction prepared...');
|
||||||
const signedTransaction = api.sign(txJSON, secret).signedTransaction;
|
const signedTransaction = api.sign(txJSON, secret).signedTransaction;
|
||||||
console.log('Payment transaction signed...');
|
console.log('Payment transaction signed...');
|
||||||
api.submit(signedTransaction, (submitError, response) => {
|
api.submit(signedTransaction).then(response => {
|
||||||
console.log(submitError ? submitError : response);
|
console.log(response);
|
||||||
process.exit(submitError ? 1 : 0);
|
process.exit(0);
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
process.exit(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
135
npm-shrinkwrap.json
generated
135
npm-shrinkwrap.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripple-lib",
|
"name": "ripple-lib",
|
||||||
"version": "0.13.0-rc2",
|
"version": "0.13.0-rc12",
|
||||||
"npm-shrinkwrap-version": "5.4.0",
|
"npm-shrinkwrap-version": "5.4.0",
|
||||||
"node-version": "v0.12.7",
|
"node-version": "v0.12.7",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9,12 +9,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
|
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
|
||||||
},
|
},
|
||||||
"babel-runtime": {
|
"babel-runtime": {
|
||||||
"version": "5.8.19",
|
"version": "5.8.25",
|
||||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.19.tgz",
|
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.25.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "0.9.18",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-0.9.18.tgz"
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.1.4.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -22,21 +22,45 @@
|
|||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.7.tgz"
|
"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": {
|
"extend": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
"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": {
|
"https-proxy-agent": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agent-base": {
|
"agent-base": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "4.3.6",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -57,8 +81,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-my-json-valid": {
|
"is-my-json-valid": {
|
||||||
"version": "2.12.1",
|
"version": "2.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"generate-function": {
|
"generate-function": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -75,8 +99,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jsonpointer": {
|
"jsonpointer": {
|
||||||
"version": "1.1.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-1.1.0.tgz"
|
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
|
||||||
},
|
},
|
||||||
"xtend": {
|
"xtend": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
@@ -85,37 +109,76 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "3.10.0",
|
"version": "3.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.0.tgz"
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
|
||||||
},
|
},
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "2.5.2",
|
"version": "2.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.2.tgz"
|
"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": {
|
"ripple-lib-transactionparser": {
|
||||||
"version": "0.4.0",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/ripple-lib-transactionparser/-/ripple-lib-transactionparser-0.5.1.tgz"
|
||||||
"dependencies": {
|
|
||||||
"bignumber.js": {
|
|
||||||
"version": "1.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-1.4.1.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"ripple-wallet-generator": {
|
"ripple-lib-value": {
|
||||||
"version": "1.0.3",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.3.tgz"
|
"resolved": "https://registry.npmjs.org/ripple-lib-value/-/ripple-lib-value-0.1.0.tgz"
|
||||||
},
|
},
|
||||||
"sjcl-extended": {
|
"sjcl-codec": {
|
||||||
"version": "1.0.3",
|
"version": "0.1.0",
|
||||||
"from": "sjcl-extended@git://github.com/ripple/sjcl-extended.git#d8cf8b22e7d97193c54e1f65113e3edcf200ca17",
|
"resolved": "https://registry.npmjs.org/sjcl-codec/-/sjcl-codec-0.1.0.tgz"
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
|
|||||||
33
package.json
33
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripple-lib",
|
"name": "ripple-lib",
|
||||||
"version": "0.13.0-rc2",
|
"version": "0.13.0-rc12",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -18,24 +18,29 @@
|
|||||||
"async": "~0.9.0",
|
"async": "~0.9.0",
|
||||||
"babel-runtime": "^5.5.4",
|
"babel-runtime": "^5.5.4",
|
||||||
"bignumber.js": "^2.0.3",
|
"bignumber.js": "^2.0.3",
|
||||||
|
"bn.js": "^3.1.1",
|
||||||
|
"es6-promisify": "^2.0.0",
|
||||||
"extend": "~1.2.1",
|
"extend": "~1.2.1",
|
||||||
|
"hash.js": "^1.0.3",
|
||||||
"https-proxy-agent": "^1.0.0",
|
"https-proxy-agent": "^1.0.0",
|
||||||
"is-my-json-valid": "^2.12.0",
|
"is-my-json-valid": "^2.12.2",
|
||||||
"lodash": "^3.1.0",
|
"lodash": "^3.1.0",
|
||||||
"lru-cache": "~2.5.0",
|
"lru-cache": "~2.5.0",
|
||||||
"ripple-lib-transactionparser": "^0.4",
|
"ripple-address-codec": "^2.0.1",
|
||||||
"ripple-wallet-generator": "^1.0.3",
|
"ripple-keypairs": "^0.9.0",
|
||||||
"sjcl-extended": "ripple/sjcl-extended#1.0.3",
|
"ripple-lib-transactionparser": "^0.5.1",
|
||||||
|
"ripple-lib-value": "0.1.0",
|
||||||
|
"sjcl-codec": "0.1.0",
|
||||||
"ws": "~0.7.1"
|
"ws": "~0.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"assert-diff": "^1.0.1",
|
"assert-diff": "^1.0.1",
|
||||||
"babel": "^5.5.4",
|
"babel": "^5.8.21",
|
||||||
"babel-core": "^5.5.4",
|
"babel-core": "^5.8.22",
|
||||||
"babel-eslint": "^3.1.23",
|
"babel-eslint": "^4.0.5",
|
||||||
"babel-loader": "^5.0.0",
|
"babel-loader": "^5.3.2",
|
||||||
"coveralls": "~2.10.0",
|
"coveralls": "~2.10.0",
|
||||||
"eslint": "^0.24.0",
|
"eslint": "^1.3.0",
|
||||||
"eslint-plugin-flowtype": "^1.0.0",
|
"eslint-plugin-flowtype": "^1.0.0",
|
||||||
"eventemitter2": "^0.4.14",
|
"eventemitter2": "^0.4.14",
|
||||||
"flow-bin": "^0.14",
|
"flow-bin": "^0.14",
|
||||||
@@ -44,6 +49,7 @@
|
|||||||
"gulp-rename": "~1.2.0",
|
"gulp-rename": "~1.2.0",
|
||||||
"gulp-uglify": "~1.1.0",
|
"gulp-uglify": "~1.1.0",
|
||||||
"istanbul": "~0.3.5",
|
"istanbul": "~0.3.5",
|
||||||
|
"json-loader": "^0.5.2",
|
||||||
"mocha": "~2.1.0",
|
"mocha": "~2.1.0",
|
||||||
"webpack": "~1.5.3",
|
"webpack": "~1.5.3",
|
||||||
"yargs": "~1.3.1"
|
"yargs": "~1.3.1"
|
||||||
@@ -52,12 +58,13 @@
|
|||||||
"build": "gulp",
|
"build": "gulp",
|
||||||
"clean": "rm -rf dist/npm && rm -rf build/flow",
|
"clean": "rm -rf dist/npm && rm -rf build/flow",
|
||||||
"typecheck": "babel --optional runtime --blacklist flow -d build/flow/ src/ && flow check",
|
"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": "babel -D --optional runtime -d dist/npm/ src/",
|
||||||
"compile-with-source-maps": "babel --optional runtime -s -t -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",
|
"prepublish": "npm run clean && npm run compile",
|
||||||
"test": "istanbul test _mocha",
|
"test": "istanbul test _mocha",
|
||||||
"coveralls": "cat ./coverage/lcov.info | coveralls",
|
"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"
|
"perf": "./scripts/perf_test.sh"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var Amount = require('../dist/npm').Amount;
|
var ripple = require('../dist/npm')._DEPRECATED;
|
||||||
var Ledger = require('../dist/npm').Ledger;
|
var Amount = ripple.Amount;
|
||||||
|
var Ledger = ripple.Ledger;
|
||||||
|
|
||||||
function parse_options(from, flags) {
|
function parse_options(from, flags) {
|
||||||
var argv = from.slice(),
|
var argv = from.slice();
|
||||||
opts_ = {argv: argv};
|
var opts_ = {argv: argv};
|
||||||
|
|
||||||
flags.forEach(function(f) {
|
flags.forEach(function(f) {
|
||||||
// Do we have the flag?
|
// Do we have the flag?
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ function MissingLedgerHistoryError(message) {
|
|||||||
MissingLedgerHistoryError.prototype = new RippleError();
|
MissingLedgerHistoryError.prototype = new RippleError();
|
||||||
MissingLedgerHistoryError.prototype.name = 'MissingLedgerHistoryError';
|
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
|
* Request timed out
|
||||||
*/
|
*/
|
||||||
@@ -77,13 +84,14 @@ ApiError.prototype = new RippleError();
|
|||||||
ApiError.prototype.name = 'ApiError';
|
ApiError.prototype.name = 'ApiError';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ValidationError: ValidationError,
|
ValidationError,
|
||||||
NetworkError: NetworkError,
|
NetworkError,
|
||||||
TransactionError: TransactionError,
|
TransactionError,
|
||||||
RippledNetworkError: RippledNetworkError,
|
RippledNetworkError,
|
||||||
NotFoundError: NotFoundError,
|
NotFoundError,
|
||||||
MissingLedgerHistoryError: MissingLedgerHistoryError,
|
PendingLedgerVersionError,
|
||||||
TimeOutError: TimeOutError,
|
MissingLedgerHistoryError,
|
||||||
ApiError: ApiError,
|
TimeOutError,
|
||||||
RippleError: RippleError
|
ApiError,
|
||||||
|
RippleError
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ module.exports = {
|
|||||||
dropsToXrp: utils.dropsToXrp,
|
dropsToXrp: utils.dropsToXrp,
|
||||||
xrpToDrops: utils.xrpToDrops,
|
xrpToDrops: utils.xrpToDrops,
|
||||||
toRippledAmount: utils.toRippledAmount,
|
toRippledAmount: utils.toRippledAmount,
|
||||||
wrapCatch: utils.wrapCatch,
|
generateAddress: utils.generateAddress,
|
||||||
composeAsync: utils.composeAsync,
|
composeAsync: utils.composeAsync,
|
||||||
|
wrapCatch: utils.wrapCatch,
|
||||||
|
convertErrors: utils.convertErrors,
|
||||||
convertExceptions: utils.convertExceptions,
|
convertExceptions: utils.convertExceptions,
|
||||||
convertKeysFromSnakeCaseToCamelCase: utils.convertKeysFromSnakeCaseToCamelCase
|
convertKeysFromSnakeCaseToCamelCase:
|
||||||
|
utils.convertKeysFromSnakeCaseToCamelCase,
|
||||||
|
promisify: utils.promisify
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,38 +1,94 @@
|
|||||||
/* @flow */
|
// flow is disabled for this file until support for requiring json is added:
|
||||||
|
// https://github.com/facebook/flow/issues/167
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const fs = require('fs');
|
const assert = require('assert');
|
||||||
const path = require('path');
|
|
||||||
const validator = require('is-my-json-valid');
|
const validator = require('is-my-json-valid');
|
||||||
const core = require('./utils').core;
|
const core = require('./utils').core;
|
||||||
const ValidationError = require('./errors').ValidationError;
|
const ValidationError = require('./errors').ValidationError;
|
||||||
|
|
||||||
let SCHEMAS = {};
|
let SCHEMAS = {};
|
||||||
|
|
||||||
function isValidAddress(address) {
|
function isValidAddress(address: string): boolean {
|
||||||
return core.UInt160.is_valid(address);
|
return typeof address === 'string' && address.length > 0 &&
|
||||||
|
address[0] === 'r' &&
|
||||||
|
core.UInt160.is_valid(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidLedgerHash(ledgerHash) {
|
function isValidLedgerHash(ledgerHash) {
|
||||||
return core.UInt256.is_valid(ledgerHash);
|
return core.UInt256.is_valid(ledgerHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSchema(filepath: string): {} {
|
function loadSchemas() {
|
||||||
try {
|
// listed explicitly for webpack (instead of scanning schemas directory)
|
||||||
return JSON.parse(fs.readFileSync(filepath, 'utf8'));
|
const schemas = [
|
||||||
} catch (e) {
|
require('./schemas/address.json'),
|
||||||
throw new Error('Failed to parse schema: ' + filepath);
|
require('./schemas/adjustment.json'),
|
||||||
}
|
require('./schemas/amount.json'),
|
||||||
}
|
require('./schemas/amountbase.json'),
|
||||||
|
require('./schemas/balance.json'),
|
||||||
function endsWith(str, suffix) {
|
require('./schemas/blob.json'),
|
||||||
return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
require('./schemas/currency.json'),
|
||||||
}
|
require('./schemas/get-account-info.json'),
|
||||||
|
require('./schemas/get-balances.json'),
|
||||||
function loadSchemas(dir) {
|
require('./schemas/get-balance-sheet'),
|
||||||
const filenames = fs.readdirSync(dir).filter(name => endsWith(name, '.json'));
|
require('./schemas/balance-sheet-options.json'),
|
||||||
const schemas = filenames.map(name => loadSchema(path.join(dir, name)));
|
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');
|
return _.indexBy(schemas, 'title');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,9 +117,8 @@ function schemaValidate(schemaName: string, object: any): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SCHEMAS = loadSchemas(path.join(__dirname, './schemas'));
|
SCHEMAS = loadSchemas();
|
||||||
module.exports = {
|
module.exports = {
|
||||||
schemaValidate: schemaValidate,
|
schemaValidate: schemaValidate,
|
||||||
loadSchema: loadSchema,
|
|
||||||
SCHEMAS: SCHEMAS
|
SCHEMAS: SCHEMAS
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"address": {"$ref": "address"},
|
"address": {"$ref": "address"},
|
||||||
"amount": {"$ref": "amount"},
|
"amount": {"$ref": "amount"},
|
||||||
"tag": {
|
"tag": {"$ref": "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"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"required": ["address", "amount"],
|
"required": ["address", "amount"],
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
|||||||
15
src/api/common/schemas/balance-sheet-options.json
Normal file
15
src/api/common/schemas/balance-sheet-options.json
Normal 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
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"value": {
|
"value": {
|
||||||
"description": "The balance on the trustline",
|
"description": "The balance on the trustline",
|
||||||
"$ref": "signed-value"
|
"$ref": "signedValue"
|
||||||
},
|
},
|
||||||
"currency": {
|
"currency": {
|
||||||
"description": "The three-character code or hex string used to denote currencies",
|
"description": "The three-character code or hex string used to denote currencies",
|
||||||
|
|||||||
9
src/api/common/schemas/destinationAdjustment.json
Normal file
9
src/api/common/schemas/destinationAdjustment.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "destinationAdjustment",
|
||||||
|
"type": "object",
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref": "adjustment"},
|
||||||
|
{"$ref": "minAdjustment"}
|
||||||
|
]
|
||||||
|
}
|
||||||
29
src/api/common/schemas/get-balance-sheet.json
Normal file
29
src/api/common/schemas/get-balance-sheet.json
Normal 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
|
||||||
|
}
|
||||||
39
src/api/common/schemas/get-ledger.json
Normal file
39
src/api/common/schemas/get-ledger.json
Normal 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
|
||||||
|
}
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"source": {"$ref": "adjustment"},
|
"source": {"$ref": "sourceAdjustment"},
|
||||||
"destination": {"$ref": "adjustment"},
|
"destination": {"$ref": "destinationAdjustment"},
|
||||||
"paths": {"type": "string"}
|
"paths": {"type": "string"}
|
||||||
},
|
},
|
||||||
"required": ["source", "destination", "paths"],
|
"required": ["source", "destination", "paths"],
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"load": {
|
"load": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"job_types": {
|
"jobTypes": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {"type": "object"}
|
"items": {"type": "object"}
|
||||||
},
|
},
|
||||||
|
|||||||
13
src/api/common/schemas/lax-amount.json
Normal file
13
src/api/common/schemas/lax-amount.json
Normal 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
|
||||||
|
}
|
||||||
13
src/api/common/schemas/lax-lax-amount.json
Normal file
13
src/api/common/schemas/lax-lax-amount.json
Normal 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
|
||||||
|
}
|
||||||
21
src/api/common/schemas/ledger-closed.json
Normal file
21
src/api/common/schemas/ledger-closed.json
Normal 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"]
|
||||||
|
}
|
||||||
13
src/api/common/schemas/ledger-options.json
Normal file
13
src/api/common/schemas/ledger-options.json
Normal 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
|
||||||
|
}
|
||||||
12
src/api/common/schemas/max-adjustment.json
Normal file
12
src/api/common/schemas/max-adjustment.json
Normal 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
|
||||||
|
}
|
||||||
12
src/api/common/schemas/min-adjustment.json
Normal file
12
src/api/common/schemas/min-adjustment.json
Normal 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
|
||||||
|
}
|
||||||
18
src/api/common/schemas/order-change.json
Normal file
18
src/api/common/schemas/order-change.json
Normal 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
|
||||||
|
}
|
||||||
@@ -4,10 +4,24 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"result": {"type": "string"},
|
"result": {"type": "string"},
|
||||||
"timestamp": {"type": "string"},
|
"timestamp": {"type": "string", "format": "date-time"},
|
||||||
"fee": {"$ref": "value"},
|
"fee": {"$ref": "value"},
|
||||||
"balanceChanges": {"type": "object"},
|
"balanceChanges": {
|
||||||
"orderbookChanges": {"type": "object"},
|
"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"},
|
"ledgerVersion": {"$ref": "ledgerVersion"},
|
||||||
"indexInLedger": {"type": "integer", "minimum": 0}
|
"indexInLedger": {"type": "integer", "minimum": 0}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"address": {"$ref": "address"},
|
"address": {"$ref": "address"},
|
||||||
|
"amount": {"$ref": "laxAmount"},
|
||||||
"currencies": {
|
"currencies": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -19,6 +20,9 @@
|
|||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"uniqueItems": true
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"not": {
|
||||||
|
"required": ["amount", "currencies"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -28,27 +32,10 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"address": {"$ref": "address"},
|
"address": {"$ref": "address"},
|
||||||
"amount": {
|
"amount": {"$ref": "laxLaxAmount"}
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"value": {
|
|
||||||
"description": "The quantity of the currency, denoted as a string to retain floating point precision",
|
|
||||||
"$ref": "value"
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"required": ["currency", "value"]
|
|
||||||
},
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"required": ["address", "amount"]
|
"required": ["address", "amount"],
|
||||||
|
"additionalProperties": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["source", "destination"],
|
"required": ["source", "destination"],
|
||||||
|
|||||||
@@ -3,13 +3,9 @@
|
|||||||
"title": "payment",
|
"title": "payment",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"source": {"$ref": "adjustment"},
|
"source": {"$ref": "sourceAdjustment"},
|
||||||
"destination": {"$ref": "adjustment"},
|
"destination": {"$ref": "destinationAdjustment"},
|
||||||
"paths": {"type": "string"},
|
"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": {
|
"memos": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
21
src/api/common/schemas/prepare.json
Normal file
21
src/api/common/schemas/prepare.json
Normal 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"]
|
||||||
|
}
|
||||||
17
src/api/common/schemas/remote-options.json
Normal file
17
src/api/common/schemas/remote-options.json
Normal 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
|
||||||
|
}
|
||||||
@@ -10,6 +10,6 @@
|
|||||||
"address": {"$ref": "address"},
|
"address": {"$ref": "address"},
|
||||||
"sequence": {"$ref": "sequence"}
|
"sequence": {"$ref": "sequence"}
|
||||||
},
|
},
|
||||||
"required": ["type", "id", "address", "sequence", "specification", "outcome"],
|
"required": ["type", "id", "address", "sequence", "specification"],
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"title": "value",
|
"title": "signedValue",
|
||||||
"description": "A string representation of a floating point number",
|
"description": "A string representation of a floating point number",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "[-]?^[0-9]*[.]?[0-9]+([eE][-+]?[0-9]+)?$"
|
"pattern": "^[-]?[0-9]*[.]?[0-9]+([eE][-+]?[0-9]+)?$"
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/api/common/schemas/sourceAdjustment.json
Normal file
9
src/api/common/schemas/sourceAdjustment.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "sourceAdjustment",
|
||||||
|
"type": "object",
|
||||||
|
"oneOf": [
|
||||||
|
{"$ref": "adjustment"},
|
||||||
|
{"$ref": "maxAdjustment"}
|
||||||
|
]
|
||||||
|
}
|
||||||
17
src/api/common/schemas/suspended-payment-cancellation.json
Normal file
17
src/api/common/schemas/suspended-payment-cancellation.json
Normal 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
|
||||||
|
}
|
||||||
28
src/api/common/schemas/suspended-payment-creation.json
Normal file
28
src/api/common/schemas/suspended-payment-creation.json
Normal 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
|
||||||
|
}
|
||||||
20
src/api/common/schemas/suspended-payment-execution.json
Normal file
20
src/api/common/schemas/suspended-payment-execution.json
Normal 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
|
||||||
|
}
|
||||||
6
src/api/common/schemas/tag.json
Normal file
6
src/api/common/schemas/tag.json
Normal 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"
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ const _ = require('lodash');
|
|||||||
const BigNumber = require('bignumber.js');
|
const BigNumber = require('bignumber.js');
|
||||||
const core = require('../../core');
|
const core = require('../../core');
|
||||||
const errors = require('./errors');
|
const errors = require('./errors');
|
||||||
|
const es6promisify = require('es6-promisify');
|
||||||
|
const keypairs = require('ripple-keypairs');
|
||||||
|
|
||||||
type Amount = {currency: string, issuer: string, value: string}
|
type Amount = {currency: string, issuer: string, value: string}
|
||||||
|
|
||||||
@@ -26,6 +28,13 @@ function toRippledAmount(amount: Amount): string|Amount {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
type AsyncFunction = (...x: any) => void
|
||||||
|
|
||||||
function wrapCatch(asyncFunction: AsyncFunction): AsyncFunction {
|
function wrapCatch(asyncFunction: AsyncFunction): AsyncFunction {
|
||||||
@@ -45,7 +54,7 @@ type Wrapper = (data: any) => any
|
|||||||
function composeAsync(wrapper: Wrapper, callback: Callback): Callback {
|
function composeAsync(wrapper: Wrapper, callback: Callback): Callback {
|
||||||
return function(error, data) {
|
return function(error, data) {
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let result;
|
let result;
|
||||||
@@ -59,6 +68,22 @@ function composeAsync(wrapper: Wrapper, callback: Callback): Callback {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
function convertExceptions<T>(f: () => T): () => T {
|
||||||
return function() {
|
return function() {
|
||||||
try {
|
try {
|
||||||
@@ -85,13 +110,20 @@ function convertKeysFromSnakeCaseToCamelCase(obj: any): any {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function promisify(asyncFunction: AsyncFunction): Function {
|
||||||
|
return es6promisify(wrapCatch(asyncFunction));
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
core,
|
core,
|
||||||
dropsToXrp,
|
dropsToXrp,
|
||||||
xrpToDrops,
|
xrpToDrops,
|
||||||
toRippledAmount,
|
toRippledAmount,
|
||||||
wrapCatch,
|
generateAddress,
|
||||||
composeAsync,
|
composeAsync,
|
||||||
|
wrapCatch,
|
||||||
convertExceptions,
|
convertExceptions,
|
||||||
convertKeysFromSnakeCaseToCamelCase
|
convertErrors,
|
||||||
|
convertKeysFromSnakeCaseToCamelCase,
|
||||||
|
promisify
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const core = require('./utils').core;
|
const deriveKeypair = require('ripple-keypairs').deriveKeypair;
|
||||||
const ValidationError = require('./errors').ValidationError;
|
const ValidationError = require('./errors').ValidationError;
|
||||||
const schemaValidate = require('./schema-validator').schemaValidate;
|
const schemaValidate = require('./schema-validator').schemaValidate;
|
||||||
|
|
||||||
@@ -9,17 +9,25 @@ function error(text) {
|
|||||||
return new ValidationError(text);
|
return new ValidationError(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateAddressAndSecret(obj: {address: string, secret: string}): void {
|
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 address = obj.address;
|
||||||
const secret = obj.secret;
|
const secret = obj.secret;
|
||||||
schemaValidate('address', address);
|
schemaValidate('address', address);
|
||||||
if (!secret) {
|
if (!secret) {
|
||||||
throw error('Parameter missing: secret');
|
throw error('Parameter missing: secret');
|
||||||
}
|
}
|
||||||
try {
|
if (!isValidSecret(secret)) {
|
||||||
core.Seed.from_json(secret).get_key(address);
|
throw error('Invalid parameter: secret');
|
||||||
} catch (exception) {
|
|
||||||
throw error('secret does not match address');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,13 +35,9 @@ function validateSecret(secret: string): void {
|
|||||||
if (!secret) {
|
if (!secret) {
|
||||||
throw error('Parameter missing: secret');
|
throw error('Parameter missing: secret');
|
||||||
}
|
}
|
||||||
if (typeof secret !== 'string' || secret[0] !== 's') {
|
if (typeof secret !== 'string' || secret[0] !== 's'
|
||||||
throw error('Invalid parameter');
|
|| !isValidSecret(secret)) {
|
||||||
}
|
throw error('Invalid parameter: secret');
|
||||||
|
|
||||||
const seed = new core.Seed().parse_base58(secret);
|
|
||||||
if (!seed.is_valid()) {
|
|
||||||
throw error('invalid seed');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,10 +61,17 @@ module.exports = {
|
|||||||
secret: validateSecret,
|
secret: validateSecret,
|
||||||
currency: _.partial(schemaValidate, 'currency'),
|
currency: _.partial(schemaValidate, 'currency'),
|
||||||
identifier: _.partial(schemaValidate, 'hash256'),
|
identifier: _.partial(schemaValidate, 'hash256'),
|
||||||
|
ledgerVersion: _.partial(schemaValidate, 'ledgerVersion'),
|
||||||
sequence: _.partial(schemaValidate, 'sequence'),
|
sequence: _.partial(schemaValidate, 'sequence'),
|
||||||
order: _.partial(schemaValidate, 'order'),
|
order: _.partial(schemaValidate, 'order'),
|
||||||
orderbook: _.partial(schemaValidate, 'orderbook'),
|
orderbook: _.partial(schemaValidate, 'orderbook'),
|
||||||
payment: _.partial(schemaValidate, 'payment'),
|
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'),
|
pathfind: _.partial(schemaValidate, 'pathfind'),
|
||||||
settings: _.partial(schemaValidate, 'settings'),
|
settings: _.partial(schemaValidate, 'settings'),
|
||||||
trustline: _.partial(schemaValidate, 'trustline'),
|
trustline: _.partial(schemaValidate, 'trustline'),
|
||||||
@@ -71,9 +82,12 @@ module.exports = {
|
|||||||
getAccountInfoOptions: _.partial(validateOptions, 'settings-options'),
|
getAccountInfoOptions: _.partial(validateOptions, 'settings-options'),
|
||||||
getTrustlinesOptions: _.partial(validateOptions, 'trustlines-options'),
|
getTrustlinesOptions: _.partial(validateOptions, 'trustlines-options'),
|
||||||
getBalancesOptions: _.partial(validateOptions, 'trustlines-options'),
|
getBalancesOptions: _.partial(validateOptions, 'trustlines-options'),
|
||||||
|
getBalanceSheetOptions: _.partial(validateOptions, 'balance-sheet-options'),
|
||||||
getOrdersOptions: _.partial(validateOptions, 'orders-options'),
|
getOrdersOptions: _.partial(validateOptions, 'orders-options'),
|
||||||
getOrderbookOptions: _.partial(validateOptions, 'orders-options'),
|
getOrderbookOptions: _.partial(validateOptions, 'orders-options'),
|
||||||
getTransactionOptions: _.partial(validateOptions, 'transaction-options'),
|
getTransactionOptions: _.partial(validateOptions, 'transaction-options'),
|
||||||
|
getLedgerOptions: _.partial(validateOptions, 'ledger-options'),
|
||||||
options: _.partial(validateOptions, 'options'),
|
options: _.partial(validateOptions, 'options'),
|
||||||
|
remoteOptions: _.partial(schemaValidate, 'remote-options'),
|
||||||
instructions: _.partial(schemaValidate, 'instructions')
|
instructions: _.partial(schemaValidate, 'instructions')
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('lodash');
|
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 server = require('./server/server');
|
||||||
const connect = server.connect;
|
const connect = server.connect;
|
||||||
const disconnect = server.disconnect;
|
const disconnect = server.disconnect;
|
||||||
@@ -14,6 +16,7 @@ const getTransaction = require('./ledger/transaction');
|
|||||||
const getTransactions = require('./ledger/transactions');
|
const getTransactions = require('./ledger/transactions');
|
||||||
const getTrustlines = require('./ledger/trustlines');
|
const getTrustlines = require('./ledger/trustlines');
|
||||||
const getBalances = require('./ledger/balances');
|
const getBalances = require('./ledger/balances');
|
||||||
|
const getBalanceSheet = require('./ledger/balance-sheet');
|
||||||
const getPaths = require('./ledger/pathfind');
|
const getPaths = require('./ledger/pathfind');
|
||||||
const getOrders = require('./ledger/orders');
|
const getOrders = require('./ledger/orders');
|
||||||
const getOrderbook = require('./ledger/orderbook');
|
const getOrderbook = require('./ledger/orderbook');
|
||||||
@@ -23,19 +26,36 @@ const preparePayment = require('./transaction/payment');
|
|||||||
const prepareTrustline = require('./transaction/trustline');
|
const prepareTrustline = require('./transaction/trustline');
|
||||||
const prepareOrder = require('./transaction/order');
|
const prepareOrder = require('./transaction/order');
|
||||||
const prepareOrderCancellation = require('./transaction/ordercancellation');
|
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 prepareSettings = require('./transaction/settings');
|
||||||
const sign = require('./transaction/sign');
|
const sign = require('./transaction/sign');
|
||||||
const submit = require('./transaction/submit');
|
const submit = require('./transaction/submit');
|
||||||
const errors = require('./common').errors;
|
const errors = require('./common').errors;
|
||||||
const convertExceptions = require('./common').convertExceptions;
|
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: {}) {
|
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});
|
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,
|
connect,
|
||||||
disconnect,
|
disconnect,
|
||||||
isConnected,
|
isConnected,
|
||||||
@@ -47,22 +67,35 @@ RippleAPI.prototype = {
|
|||||||
getTransactions,
|
getTransactions,
|
||||||
getTrustlines,
|
getTrustlines,
|
||||||
getBalances,
|
getBalances,
|
||||||
|
getBalanceSheet,
|
||||||
getPaths,
|
getPaths,
|
||||||
getOrders,
|
getOrders,
|
||||||
getOrderbook,
|
getOrderbook,
|
||||||
getSettings,
|
getSettings,
|
||||||
getAccountInfo,
|
getAccountInfo,
|
||||||
|
getLedger,
|
||||||
|
|
||||||
preparePayment,
|
preparePayment,
|
||||||
prepareTrustline,
|
prepareTrustline,
|
||||||
prepareOrder,
|
prepareOrder,
|
||||||
prepareOrderCancellation,
|
prepareOrderCancellation,
|
||||||
|
prepareSuspendedPaymentCreation,
|
||||||
|
prepareSuspendedPaymentExecution,
|
||||||
|
prepareSuspendedPaymentCancellation,
|
||||||
prepareSettings,
|
prepareSettings,
|
||||||
sign,
|
sign,
|
||||||
submit,
|
submit,
|
||||||
|
|
||||||
generateWallet,
|
generateAddress,
|
||||||
errors
|
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;
|
module.exports = RippleAPI;
|
||||||
|
|||||||
@@ -5,8 +5,45 @@ const utils = require('./utils');
|
|||||||
const removeUndefined = require('./parse/utils').removeUndefined;
|
const removeUndefined = require('./parse/utils').removeUndefined;
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const composeAsync = utils.common.composeAsync;
|
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;
|
const data = response.account_data;
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
sequence: data.Sequence,
|
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.address(account);
|
||||||
validate.getAccountInfoOptions(options);
|
validate.getAccountInfoOptions(options);
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
account: account,
|
account: account,
|
||||||
ledger: options.ledgerVersion
|
ledger: options.ledgerVersion || 'validated'
|
||||||
};
|
};
|
||||||
|
|
||||||
this.remote.requestAccountInfo(request,
|
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;
|
||||||
|
|||||||
68
src/api/ledger/balance-sheet.js
Normal file
68
src/api/ledger/balance-sheet.js
Normal 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;
|
||||||
@@ -6,6 +6,10 @@ const utils = require('./utils');
|
|||||||
const getTrustlines = require('./trustlines');
|
const getTrustlines = require('./trustlines');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const composeAsync = utils.common.composeAsync;
|
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) {
|
function getTrustlineBalanceAmount(trustline) {
|
||||||
return {
|
return {
|
||||||
@@ -24,16 +28,37 @@ function formatBalances(balances) {
|
|||||||
balances.trustlines.map(getTrustlineBalanceAmount));
|
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.address(account);
|
||||||
validate.getBalancesOptions(options);
|
validate.getBalancesOptions(options);
|
||||||
|
|
||||||
const ledgerVersion = options.ledgerVersion
|
|
||||||
|| this.remote.getLedgerSequence();
|
|
||||||
async.parallel({
|
async.parallel({
|
||||||
xrp: _.partial(utils.getXRPBalance, this.remote, account, ledgerVersion),
|
xrp: async.seq(
|
||||||
trustlines: _.partial(getTrustlines.bind(this), account, options)
|
_.partial(getLedgerVersionHelper, this.remote, options.ledgerVersion),
|
||||||
}, composeAsync(formatBalances, callback));
|
_.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
28
src/api/ledger/ledger.js
Normal 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;
|
||||||
@@ -3,21 +3,23 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const parseOrderbookOrder = require('./parse/orderbook-order');
|
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const composeAsync = utils.common.composeAsync;
|
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
|
// account is to specify a "perspective", which affects which unfunded offers
|
||||||
// are returned
|
// are returned
|
||||||
function getBookOffers(remote, account, ledgerVersion, limit,
|
function getBookOffers(remote, account, ledgerVersion, limit,
|
||||||
takerGets, takerPays, callback) {
|
takerGets, takerPays, callback
|
||||||
|
) {
|
||||||
remote.requestBookOffers(utils.renameCounterpartyToIssuerInOrder({
|
remote.requestBookOffers(utils.renameCounterpartyToIssuerInOrder({
|
||||||
taker_gets: takerGets,
|
taker_gets: takerGets,
|
||||||
taker_pays: takerPays,
|
taker_pays: takerPays,
|
||||||
ledger: ledgerVersion || 'validated',
|
ledger: ledgerVersion || 'validated',
|
||||||
limit: limit,
|
limit: limit,
|
||||||
taker: account
|
taker: account
|
||||||
}), composeAsync(data => data.offers, callback));
|
}), composeAsync(data => data.offers, convertErrors(callback)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSameIssue(a, b) {
|
function isSameIssue(a, b) {
|
||||||
@@ -62,7 +64,7 @@ function formatBidsAndAsks(orderbook, offers) {
|
|||||||
return {bids, asks};
|
return {bids, asks};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrderbook(account, orderbook, options, callback) {
|
function getOrderbookAsync(account, orderbook, options, callback) {
|
||||||
validate.address(account);
|
validate.address(account);
|
||||||
validate.orderbook(orderbook);
|
validate.orderbook(orderbook);
|
||||||
validate.getOrderbookOptions(options);
|
validate.getOrderbookOptions(options);
|
||||||
@@ -76,4 +78,9 @@ function getOrderbook(account, orderbook, options, callback) {
|
|||||||
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;
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const async = require('async');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const composeAsync = utils.common.composeAsync;
|
const composeAsync = utils.common.composeAsync;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
const parseAccountOrder = require('./parse/account-order');
|
const parseAccountOrder = require('./parse/account-order');
|
||||||
|
|
||||||
function requestAccountOffers(remote, address, ledgerVersion, options,
|
function requestAccountOffers(remote, address, ledgerVersion, marker, limit,
|
||||||
marker, limit, callback) {
|
callback
|
||||||
|
) {
|
||||||
remote.requestAccountOffers({
|
remote.requestAccountOffers({
|
||||||
account: address,
|
account: address,
|
||||||
marker: marker,
|
marker: marker,
|
||||||
@@ -17,20 +20,24 @@ function requestAccountOffers(remote, address, ledgerVersion, options,
|
|||||||
composeAsync((data) => ({
|
composeAsync((data) => ({
|
||||||
marker: data.marker,
|
marker: data.marker,
|
||||||
results: data.offers.map(_.partial(parseAccountOrder, address))
|
results: data.offers.map(_.partial(parseAccountOrder, address))
|
||||||
}), callback));
|
}), convertErrors(callback)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrders(account, options, callback) {
|
function getOrdersAsync(account, options, callback) {
|
||||||
validate.address(account);
|
validate.address(account);
|
||||||
validate.getOrdersOptions(options);
|
validate.getOrdersOptions(options);
|
||||||
|
|
||||||
const ledgerVersion = options.ledgerVersion
|
|
||||||
|| this.remote.getLedgerSequence();
|
|
||||||
const getter = _.partial(requestAccountOffers, this.remote, account,
|
const getter = _.partial(requestAccountOffers, this.remote, account,
|
||||||
ledgerVersion, options);
|
options.ledgerVersion);
|
||||||
utils.getRecursive(getter, options.limit,
|
utils.getRecursive(getter, options.limit,
|
||||||
composeAsync((orders) => _.sortBy(orders,
|
composeAsync((orders) => _.sortBy(orders,
|
||||||
(order) => order.properties.sequence), callback));
|
(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;
|
||||||
|
|||||||
50
src/api/ledger/parse/ledger.js
Normal file
50
src/api/ledger/parse/ledger.js
Normal 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;
|
||||||
@@ -8,21 +8,42 @@ function parsePaths(paths) {
|
|||||||
_.omit(step, ['type', 'type_hex'])));
|
_.omit(step, ['type', 'type_hex'])));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePathfind(sourceAddress: string,
|
function removeAnyCounterpartyEncoding(address: string, amount: Object) {
|
||||||
destinationAmount: Object, pathfindResult: Object): Object {
|
return amount.counterparty === address ?
|
||||||
return pathfindResult.alternatives.map(function(alternative) {
|
_.omit(amount, 'counterparty') : amount;
|
||||||
return {
|
}
|
||||||
source: {
|
|
||||||
address: sourceAddress,
|
function createAdjustment(address: string, adjustmentWithoutAddress: Object) {
|
||||||
amount: parseAmount(alternative.source_amount)
|
const amountKey = _.keys(adjustmentWithoutAddress)[0];
|
||||||
},
|
const amount = adjustmentWithoutAddress[amountKey];
|
||||||
destination: {
|
return _.set({address: address}, amountKey,
|
||||||
address: pathfindResult.destination_account,
|
removeAnyCounterpartyEncoding(address, amount));
|
||||||
amount: destinationAmount
|
}
|
||||||
},
|
|
||||||
paths: JSON.stringify(parsePaths(alternative.paths_computed))
|
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;
|
module.exports = parsePathfind;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
const _ = require('lodash');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const parseAmount = require('./amount');
|
const parseAmount = require('./amount');
|
||||||
@@ -17,17 +18,9 @@ function isQualityLimited(tx) {
|
|||||||
return (tx.Flags & Transaction.flags.Payment.LimitQuality) !== 0;
|
return (tx.Flags & Transaction.flags.Payment.LimitQuality) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePaymentMemos(tx) {
|
function removeGenericCounterparty(amount, address) {
|
||||||
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
return amount.counterparty === address ?
|
||||||
return undefined;
|
_.omit(amount, 'counterparty') : amount;
|
||||||
}
|
|
||||||
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 parsePayment(tx: Object): Object {
|
function parsePayment(tx: Object): Object {
|
||||||
@@ -35,20 +28,21 @@ function parsePayment(tx: Object): Object {
|
|||||||
|
|
||||||
const source = {
|
const source = {
|
||||||
address: tx.Account,
|
address: tx.Account,
|
||||||
amount: parseAmount(tx.SendMax || tx.Amount),
|
maxAmount: removeGenericCounterparty(
|
||||||
|
parseAmount(tx.SendMax || tx.Amount), tx.Account),
|
||||||
tag: tx.SourceTag
|
tag: tx.SourceTag
|
||||||
};
|
};
|
||||||
|
|
||||||
const destination = {
|
const destination = {
|
||||||
address: tx.Destination,
|
address: tx.Destination,
|
||||||
amount: parseAmount(tx.Amount),
|
amount: removeGenericCounterparty(parseAmount(tx.Amount), tx.Destination),
|
||||||
tag: tx.DestinationTag
|
tag: tx.DestinationTag
|
||||||
};
|
};
|
||||||
|
|
||||||
return utils.removeUndefined({
|
return utils.removeUndefined({
|
||||||
source: utils.removeUndefined(source),
|
source: utils.removeUndefined(source),
|
||||||
destination: utils.removeUndefined(destination),
|
destination: utils.removeUndefined(destination),
|
||||||
memos: parsePaymentMemos(tx),
|
memos: utils.parseMemos(tx),
|
||||||
invoiceID: tx.InvoiceID,
|
invoiceID: tx.InvoiceID,
|
||||||
paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined,
|
paths: tx.Paths ? JSON.stringify(tx.Paths) : undefined,
|
||||||
allowPartialPayment: isPartialPayment(tx) || undefined,
|
allowPartialPayment: isPartialPayment(tx) || undefined,
|
||||||
|
|||||||
16
src/api/ledger/parse/suspended-payment-cancellation.js
Normal file
16
src/api/ledger/parse/suspended-payment-cancellation.js
Normal 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;
|
||||||
39
src/api/ledger/parse/suspended-payment-creation.js
Normal file
39
src/api/ledger/parse/suspended-payment-creation.js
Normal 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;
|
||||||
25
src/api/ledger/parse/suspended-payment-execution.js
Normal file
25
src/api/ledger/parse/suspended-payment-execution.js
Normal 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;
|
||||||
@@ -7,6 +7,10 @@ const parseTrustline = require('./trustline');
|
|||||||
const parseOrder = require('./order');
|
const parseOrder = require('./order');
|
||||||
const parseOrderCancellation = require('./cancellation');
|
const parseOrderCancellation = require('./cancellation');
|
||||||
const parseSettings = require('./settings');
|
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) {
|
function parseTransactionType(type) {
|
||||||
const mapping = {
|
const mapping = {
|
||||||
@@ -15,7 +19,10 @@ function parseTransactionType(type) {
|
|||||||
OfferCreate: 'order',
|
OfferCreate: 'order',
|
||||||
OfferCancel: 'orderCancellation',
|
OfferCancel: 'orderCancellation',
|
||||||
AccountSet: 'settings',
|
AccountSet: 'settings',
|
||||||
SetRegularKey: 'settings'
|
SetRegularKey: 'settings',
|
||||||
|
SuspendedPaymentCreate: 'suspendedPaymentCreation',
|
||||||
|
SuspendedPaymentFinish: 'suspendedPaymentExecution',
|
||||||
|
SuspendedPaymentCancel: 'suspendedPaymentCancellation'
|
||||||
};
|
};
|
||||||
return mapping[type] || null;
|
return mapping[type] || null;
|
||||||
}
|
}
|
||||||
@@ -27,7 +34,10 @@ function parseTransaction(tx: Object): Object {
|
|||||||
'trustline': parseTrustline,
|
'trustline': parseTrustline,
|
||||||
'order': parseOrder,
|
'order': parseOrder,
|
||||||
'orderCancellation': parseOrderCancellation,
|
'orderCancellation': parseOrderCancellation,
|
||||||
'settings': parseSettings
|
'settings': parseSettings,
|
||||||
|
'suspendedPaymentCreation': parseSuspendedPaymentCreation,
|
||||||
|
'suspendedPaymentExecution': parseSuspendedPaymentExecution,
|
||||||
|
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation
|
||||||
};
|
};
|
||||||
const parser = mapping[type];
|
const parser = mapping[type];
|
||||||
assert(parser !== undefined, 'Unrecognized transaction type');
|
assert(parser !== undefined, 'Unrecognized transaction type');
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ function parseFlag(flagsValue, trueValue, falseValue) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseQuality(quality) {
|
function parseQuality(quality?: number) {
|
||||||
return (new BigNumber(quality)).shift(-9).toNumber();
|
if (typeof quality === 'number') {
|
||||||
|
return (new BigNumber(quality)).shift(-9).toNumber();
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTrustline(tx: Object): Object {
|
function parseTrustline(tx: Object): Object {
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ const toTimestamp = require('../../../core/utils').toTimestamp;
|
|||||||
const utils = require('../utils');
|
const utils = require('../utils');
|
||||||
const BigNumber = require('bignumber.js');
|
const BigNumber = require('bignumber.js');
|
||||||
|
|
||||||
function adjustQualityForXRP(quality: string, takerGetsCurrency: string,
|
function adjustQualityForXRP(
|
||||||
takerPaysCurrency: string) {
|
quality: string, takerGetsCurrency: string, takerPaysCurrency: string
|
||||||
|
) {
|
||||||
// quality = takerPays.value/takerGets.value
|
// quality = takerPays.value/takerGets.value
|
||||||
// using drops (1e-6 XRP) for XRP values
|
// using drops (1e-6 XRP) for XRP values
|
||||||
const numeratorShift = (takerPaysCurrency === 'XRP' ? -6 : 0);
|
const numeratorShift = (takerPaysCurrency === 'XRP' ? -6 : 0);
|
||||||
@@ -51,7 +52,7 @@ function parseOutcome(tx: Object): ?Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const balanceChanges = transactionParser.parseBalanceChanges(tx.meta);
|
const balanceChanges = transactionParser.parseBalanceChanges(tx.meta);
|
||||||
const orderbookChanges = transactionParser.parseOrderBookChanges(tx.meta);
|
const orderbookChanges = transactionParser.parseOrderbookChanges(tx.meta);
|
||||||
removeEmptyCounterpartyInBalanceChanges(balanceChanges);
|
removeEmptyCounterpartyInBalanceChanges(balanceChanges);
|
||||||
removeEmptyCounterpartyInOrderbookChanges(orderbookChanges);
|
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 = {
|
module.exports = {
|
||||||
parseOutcome,
|
parseOutcome,
|
||||||
|
parseMemos,
|
||||||
removeUndefined,
|
removeUndefined,
|
||||||
adjustQualityForXRP,
|
adjustQualityForXRP,
|
||||||
dropsToXrp: utils.common.dropsToXrp,
|
dropsToXrp: utils.common.dropsToXrp,
|
||||||
|
|||||||
@@ -4,14 +4,18 @@ const _ = require('lodash');
|
|||||||
const async = require('async');
|
const async = require('async');
|
||||||
const BigNumber = require('bignumber.js');
|
const BigNumber = require('bignumber.js');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const validate = utils.common.validate;
|
|
||||||
const parsePathfind = require('./parse/pathfind');
|
const parsePathfind = require('./parse/pathfind');
|
||||||
|
const validate = utils.common.validate;
|
||||||
const NotFoundError = utils.common.errors.NotFoundError;
|
const NotFoundError = utils.common.errors.NotFoundError;
|
||||||
|
const ValidationError = utils.common.errors.ValidationError;
|
||||||
const composeAsync = utils.common.composeAsync;
|
const composeAsync = utils.common.composeAsync;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
|
const toRippledAmount = utils.common.toRippledAmount;
|
||||||
|
|
||||||
type PathFindParams = {
|
type PathFindParams = {
|
||||||
src_currencies?: Array<string>, src_account: string, dst_amount: string,
|
src_currencies?: Array<string>, src_account: string,
|
||||||
dst_account?: string
|
dst_amount: string | Object, dst_account?: string,
|
||||||
|
src_amount?: string | Object
|
||||||
}
|
}
|
||||||
|
|
||||||
function addParams(params: PathFindParams, result: {}) {
|
function addParams(params: PathFindParams, result: {}) {
|
||||||
@@ -28,10 +32,11 @@ type PathFind = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function requestPathFind(remote, pathfind: PathFind, callback) {
|
function requestPathFind(remote, pathfind: PathFind, callback) {
|
||||||
|
const destinationAmount = _.assign({value: -1}, pathfind.destination.amount);
|
||||||
const params: PathFindParams = {
|
const params: PathFindParams = {
|
||||||
src_account: pathfind.source.address,
|
src_account: pathfind.source.address,
|
||||||
dst_account: pathfind.destination.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) {
|
if (typeof params.dst_amount === 'object' && !params.dst_amount.issuer) {
|
||||||
// Convert blank issuer to sender's address
|
// 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) {
|
if (pathfind.source.currencies && pathfind.source.currencies.length > 0) {
|
||||||
params.src_currencies = pathfind.source.currencies.map(amount =>
|
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,
|
remote.createPathFind(params,
|
||||||
composeAsync(_.partial(addParams, params), callback));
|
composeAsync(_.partial(addParams, params), convertErrors(callback)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDirectXrpPath(paths, xrpBalance) {
|
function addDirectXrpPath(paths, xrpBalance) {
|
||||||
@@ -78,19 +93,12 @@ function conditionallyAddDirectXRPPath(remote, address, paths, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDestinationCounterparty(amount, address) {
|
|
||||||
return amount.currency === 'XRP' || amount.counterparty ? amount :
|
|
||||||
_.assign({counterparty: address}, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatResponse(pathfind, paths) {
|
function formatResponse(pathfind, paths) {
|
||||||
if (paths.alternatives && paths.alternatives.length > 0) {
|
if (paths.alternatives && paths.alternatives.length > 0) {
|
||||||
const address = pathfind.source.address;
|
return parsePathfind(paths);
|
||||||
const destinationAmount = addDestinationCounterparty(
|
|
||||||
pathfind.destination.amount, pathfind.destination.address);
|
|
||||||
return parsePathfind(address, destinationAmount, paths);
|
|
||||||
}
|
}
|
||||||
if (!_.includes(paths.destination_currencies,
|
if (paths.destination_currencies !== undefined &&
|
||||||
|
!_.includes(paths.destination_currencies,
|
||||||
pathfind.destination.amount.currency)) {
|
pathfind.destination.amount.currency)) {
|
||||||
throw new NotFoundError('No paths found. ' +
|
throw new NotFoundError('No paths found. ' +
|
||||||
'The destination_account does not accept ' +
|
'The destination_account does not accept ' +
|
||||||
@@ -110,7 +118,7 @@ function formatResponse(pathfind, paths) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPaths(pathfind, callback) {
|
function getPathsAsync(pathfind, callback) {
|
||||||
validate.pathfind(pathfind);
|
validate.pathfind(pathfind);
|
||||||
|
|
||||||
const address = pathfind.source.address;
|
const address = pathfind.source.address;
|
||||||
@@ -120,4 +128,8 @@ function getPaths(pathfind, callback) {
|
|||||||
], composeAsync(_.partial(formatResponse, 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;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const validate = utils.common.validate;
|
|||||||
const parseFields = require('./parse/fields');
|
const parseFields = require('./parse/fields');
|
||||||
const composeAsync = utils.common.composeAsync;
|
const composeAsync = utils.common.composeAsync;
|
||||||
const AccountFlags = utils.common.constants.AccountFlags;
|
const AccountFlags = utils.common.constants.AccountFlags;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
|
|
||||||
function parseFlags(value) {
|
function parseFlags(value) {
|
||||||
const settings = {};
|
const settings = {};
|
||||||
@@ -24,17 +25,21 @@ function formatSettings(response) {
|
|||||||
return _.assign({}, parsedFlags, parsedFields);
|
return _.assign({}, parsedFlags, parsedFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSettings(account, options, callback) {
|
function getSettingsAsync(account, options, callback) {
|
||||||
validate.address(account);
|
validate.address(account);
|
||||||
validate.getSettingsOptions(options);
|
validate.getSettingsOptions(options);
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
account: account,
|
account: account,
|
||||||
ledger: options.ledgerVersion
|
ledger: options.ledgerVersion || 'validated'
|
||||||
};
|
};
|
||||||
|
|
||||||
this.remote.requestAccountInfo(request,
|
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;
|
||||||
|
|||||||
147
src/api/ledger/transaction-types.js
Normal file
147
src/api/ledger/transaction-types.js
Normal 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
|
||||||
@@ -6,9 +6,18 @@ const utils = require('./utils');
|
|||||||
const parseTransaction = require('./parse/transaction');
|
const parseTransaction = require('./parse/transaction');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const errors = utils.common.errors;
|
const errors = utils.common.errors;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
const RippleError = require('../../core/rippleerror').RippleError;
|
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) {
|
if (tx.date) {
|
||||||
callback(null, tx);
|
callback(null, tx);
|
||||||
return;
|
return;
|
||||||
@@ -29,46 +38,76 @@ function attachTransactionDate(remote, tx, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTransactionInRange(tx, options) {
|
function isTransactionInRange(tx: Object, options: TransactionOptions) {
|
||||||
return (!options.minLedgerVersion
|
return (!options.minLedgerVersion
|
||||||
|| tx.ledger_index >= options.minLedgerVersion)
|
|| tx.ledger_index >= options.minLedgerVersion)
|
||||||
&& (!options.maxLedgerVersion
|
&& (!options.maxLedgerVersion
|
||||||
|| tx.ledger_index <= options.maxLedgerVersion);
|
|| tx.ledger_index <= options.maxLedgerVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransaction(identifier, options, callback) {
|
function getTransactionAsync(identifier: string, options: TransactionOptions,
|
||||||
|
callback: GetTransactionResponseCallback
|
||||||
|
) {
|
||||||
validate.identifier(identifier);
|
validate.identifier(identifier);
|
||||||
validate.getTransactionOptions(options);
|
validate.getTransactionOptions(options);
|
||||||
|
|
||||||
const remote = this.remote;
|
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_;
|
let error = error_;
|
||||||
|
|
||||||
|
if (!error && tx && tx.validated !== true) {
|
||||||
|
return callback(new errors.NotFoundError('Transaction not found'));
|
||||||
|
}
|
||||||
|
|
||||||
if (error instanceof RippleError && error.remote &&
|
if (error instanceof RippleError && error.remote &&
|
||||||
error.remote.error === 'txnNotFound') {
|
error.remote.error === 'txnNotFound') {
|
||||||
error = new errors.NotFoundError('Transaction not found');
|
error = new errors.NotFoundError('Transaction not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Missing complete ledger range
|
||||||
if (error instanceof errors.NotFoundError
|
if (error instanceof errors.NotFoundError
|
||||||
&& !utils.hasCompleteLedgerRange(remote,
|
&& !utils.hasCompleteLedgerRange(remote, options.minLedgerVersion,
|
||||||
options.minLedgerVersion, maxLedgerVersion)) {
|
maxLedgerVersion)) {
|
||||||
callback(new errors.MissingLedgerHistoryError('Transaction not found,'
|
if (utils.isPendingLedgerVersion(remote, maxLedgerVersion)) {
|
||||||
+ ' but the server\'s ledger history is incomplete'));
|
callback(new errors.PendingLedgerVersionError());
|
||||||
} else if (!error && !isTransactionInRange(tx, options)) {
|
} 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'));
|
callback(new errors.NotFoundError('Transaction not found'));
|
||||||
|
// Transaction is not found
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
callback(error);
|
convertErrors(callback)(error);
|
||||||
|
} else if (!tx) {
|
||||||
|
callback(new errors.ApiError('Internal error'));
|
||||||
} else {
|
} else {
|
||||||
callback(error, parseTransaction(tx));
|
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([
|
async.waterfall([
|
||||||
_.partial(remote.requestTx.bind(remote), {hash: identifier, binary: false}),
|
_.partial(remote.requestTx.bind(remote),
|
||||||
|
{hash: identifier, binary: false}),
|
||||||
_.partial(attachTransactionDate, remote)
|
_.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;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const parseTransaction = require('./parse/transaction');
|
|||||||
const getTransaction = require('./transaction');
|
const getTransaction = require('./transaction');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const composeAsync = utils.common.composeAsync;
|
const composeAsync = utils.common.composeAsync;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
|
|
||||||
function parseAccountTxTransaction(tx) {
|
function parseAccountTxTransaction(tx) {
|
||||||
// rippled uses a different response format for 'account_tx' than 'tx'
|
// rippled uses a different response format for 'account_tx' than 'tx'
|
||||||
@@ -15,6 +16,21 @@ function parseAccountTxTransaction(tx) {
|
|||||||
return parseTransaction(tx.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) {
|
function transactionFilter(address, filters, tx) {
|
||||||
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
if (filters.excludeFailures && tx.outcome.result !== 'tesSUCCESS') {
|
||||||
return false;
|
return false;
|
||||||
@@ -28,8 +44,7 @@ function transactionFilter(address, filters, tx) {
|
|||||||
if (filters.initiated === false && tx.address === address) {
|
if (filters.initiated === false && tx.address === address) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (filters.counterparty && tx.address !== filters.counterparty
|
if (filters.counterparty && !counterpartyFilter(filters, tx)) {
|
||||||
&& tx.specification.destination.address !== filters.counterparty) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -41,10 +56,23 @@ function orderFilter(options, tx) {
|
|||||||
utils.compareTransactions(tx, options.startTx) < 0);
|
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) {
|
function getAccountTx(remote, address, options, marker, limit, callback) {
|
||||||
const params = {
|
const params = {
|
||||||
account: address,
|
account: address,
|
||||||
|
// -1 is equivalent to earliest available validated ledger
|
||||||
ledger_index_min: options.minLedgerVersion || -1,
|
ledger_index_min: options.minLedgerVersion || -1,
|
||||||
|
// -1 is equivalent to most recent available validated ledger
|
||||||
ledger_index_max: options.maxLedgerVersion || -1,
|
ledger_index_max: options.maxLedgerVersion || -1,
|
||||||
forward: options.earliestFirst,
|
forward: options.earliestFirst,
|
||||||
binary: options.binary,
|
binary: options.binary,
|
||||||
@@ -52,16 +80,9 @@ function getAccountTx(remote, address, options, marker, limit, callback) {
|
|||||||
marker: marker
|
marker: marker
|
||||||
};
|
};
|
||||||
|
|
||||||
remote.requestAccountTx(params, (error, data) => {
|
remote.requestAccountTx(params,
|
||||||
return error ? callback(error) : callback(null, {
|
composeAsync(_.partial(formatPartialResponse, address, options),
|
||||||
marker: data.marker,
|
convertErrors(callback)));
|
||||||
results: data.transactions
|
|
||||||
.filter((tx) => tx.validated)
|
|
||||||
.map(parseAccountTxTransaction)
|
|
||||||
.filter(_.partial(transactionFilter, address, options))
|
|
||||||
.filter(_.partial(orderFilter, options))
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForLedgerGaps(remote, options, transactions) {
|
function checkForLedgerGaps(remote, options, transactions) {
|
||||||
@@ -98,27 +119,27 @@ function getTransactionsInternal(remote, address, options, callback) {
|
|||||||
utils.getRecursive(getter, options.limit, composeAsync(format, callback));
|
utils.getRecursive(getter, options.limit, composeAsync(format, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTransactions(account, options, callback) {
|
function getTransactionsAsync(account, options, callback) {
|
||||||
validate.address(account);
|
validate.address(account);
|
||||||
validate.getTransactionsOptions(options);
|
validate.getTransactionsOptions(options);
|
||||||
|
|
||||||
const defaults = {maxLedgerVersion: this.remote.getLedgerSequence()};
|
const defaults = {maxLedgerVersion: -1};
|
||||||
if (options.start) {
|
if (options.start) {
|
||||||
getTransaction.bind(this)(options.start, {}, (error, tx) => {
|
getTransaction.call(this, options.start).then(tx => {
|
||||||
if (error) {
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const ledgerVersion = tx.outcome.ledgerVersion;
|
const ledgerVersion = tx.outcome.ledgerVersion;
|
||||||
const bound = options.earliestFirst ?
|
const bound = options.earliestFirst ?
|
||||||
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion};
|
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion};
|
||||||
const newOptions = _.assign(defaults, options, {startTx: tx}, bound);
|
const newOptions = _.assign(defaults, options, {startTx: tx}, bound);
|
||||||
getTransactionsInternal(this.remote, account, newOptions, callback);
|
getTransactionsInternal(this.remote, account, newOptions, callback);
|
||||||
});
|
}).catch(callback);
|
||||||
} else {
|
} else {
|
||||||
const newOptions = _.assign(defaults, options);
|
const newOptions = _.assign(defaults, options);
|
||||||
getTransactionsInternal(this.remote, account, 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;
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const async = require('async');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
|
const composeAsync = utils.common.composeAsync;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
const parseAccountTrustline = require('./parse/account-trustline');
|
const parseAccountTrustline = require('./parse/account-trustline');
|
||||||
|
|
||||||
function currencyFilter(currency, trustline) {
|
function currencyFilter(currency, trustline) {
|
||||||
return currency === null || trustline.specification.currency === currency;
|
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,
|
function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
|
||||||
callback) {
|
callback
|
||||||
|
) {
|
||||||
const requestOptions = {
|
const requestOptions = {
|
||||||
account: address,
|
account: address,
|
||||||
ledger: ledgerVersion,
|
ledger: ledgerVersion,
|
||||||
@@ -19,27 +31,27 @@ function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
|
|||||||
peer: options.counterparty
|
peer: options.counterparty
|
||||||
};
|
};
|
||||||
|
|
||||||
remote.requestAccountLines(requestOptions, (error, data) => {
|
remote.requestAccountLines(requestOptions,
|
||||||
return error ? callback(error) :
|
composeAsync(_.partial(formatResponse, options),
|
||||||
callback(null, {
|
convertErrors(callback)));
|
||||||
marker: data.marker,
|
|
||||||
results: data.lines.map(parseAccountTrustline)
|
|
||||||
.filter(_.partial(currencyFilter, options.currency || null))
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTrustlines(account: string, options: {currency: string,
|
function getTrustlinesAsync(account: string, options: {currency: string,
|
||||||
counterparty: string, limit: number, ledgerVersion: number},
|
counterparty: string, limit: number, ledgerVersion: number},
|
||||||
callback: () => void): void {
|
callback: () => void
|
||||||
|
): void {
|
||||||
validate.address(account);
|
validate.address(account);
|
||||||
validate.getTrustlinesOptions(options);
|
validate.getTrustlinesOptions(options);
|
||||||
|
|
||||||
const ledgerVersion = options.ledgerVersion
|
|
||||||
|| this.remote.getLedgerSequence();
|
|
||||||
const getter = _.partial(getAccountLines, this.remote, account,
|
const getter = _.partial(getAccountLines, this.remote, account,
|
||||||
ledgerVersion, options);
|
options.ledgerVersion, options);
|
||||||
utils.getRecursive(getter, options.limit, callback);
|
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;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const assert = require('assert');
|
|||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const dropsToXrp = common.dropsToXrp;
|
const dropsToXrp = common.dropsToXrp;
|
||||||
const composeAsync = common.composeAsync;
|
const composeAsync = common.composeAsync;
|
||||||
|
import type {Remote} from '../../core/remote';
|
||||||
|
|
||||||
type Callback = (err: any, data: any) => void
|
type Callback = (err: any, data: any) => void
|
||||||
|
|
||||||
@@ -13,7 +14,9 @@ function clamp(value: number, min: number, max: number): number {
|
|||||||
return Math.min(Math.max(value, min), max);
|
return Math.min(Math.max(value, min), max);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getXRPBalance(remote: any, address: string, ledgerVersion?: number, callback: Callback): void {
|
function getXRPBalance(remote: Remote, address: string, ledgerVersion?: number,
|
||||||
|
callback: Callback
|
||||||
|
): void {
|
||||||
remote.requestAccountInfo({account: address, ledger: ledgerVersion},
|
remote.requestAccountInfo({account: address, ledger: ledgerVersion},
|
||||||
composeAsync((data) => dropsToXrp(data.account_data.Balance), callback));
|
composeAsync((data) => dropsToXrp(data.account_data.Balance), callback));
|
||||||
}
|
}
|
||||||
@@ -22,7 +25,9 @@ type Getter = (marker: ?string, limit: number, callback: Callback) => void
|
|||||||
|
|
||||||
// If the marker is omitted from a response, you have reached the end
|
// If the marker is omitted from a response, you have reached the end
|
||||||
// getter(marker, limit, callback), callback(error, {marker, results})
|
// getter(marker, limit, callback), callback(error, {marker, results})
|
||||||
function getRecursiveRecur(getter: Getter, marker?: string, limit: number, callback: Callback): void {
|
function getRecursiveRecur(getter: Getter, marker?: string, limit: number,
|
||||||
|
callback: Callback
|
||||||
|
): void {
|
||||||
getter(marker, limit, (error, data) => {
|
getter(marker, limit, (error, data) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return callback(error);
|
return callback(error);
|
||||||
@@ -79,33 +84,58 @@ function signum(num) {
|
|||||||
* @returns {Number} [-1, 0, 1]
|
* @returns {Number} [-1, 0, 1]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type Outcome = {outcome: {ledgerVersion: string, indexInLedger: string}};
|
type Outcome = {outcome: {ledgerVersion: number, indexInLedger: number}};
|
||||||
|
|
||||||
function compareTransactions(first: Outcome, second: Outcome): number {
|
function compareTransactions(first: Outcome, second: Outcome): number {
|
||||||
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
|
if (!first.outcome || !second.outcome) {
|
||||||
return signum(Number(first.outcome.indexInLedger) -
|
return 0;
|
||||||
Number(second.outcome.indexInLedger));
|
|
||||||
}
|
}
|
||||||
return Number(first.outcome.ledgerVersion) <
|
if (first.outcome.ledgerVersion === second.outcome.ledgerVersion) {
|
||||||
Number(second.outcome.ledgerVersion) ? -1 : 1;
|
return signum(first.outcome.indexInLedger - second.outcome.indexInLedger);
|
||||||
|
}
|
||||||
|
return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasCompleteLedgerRange(remote: any, minLedgerVersion: number,
|
function hasCompleteLedgerRange(remote: Remote, minLedgerVersion?: number,
|
||||||
maxLedgerVersion: number): boolean {
|
maxLedgerVersion?: number
|
||||||
|
): boolean {
|
||||||
|
|
||||||
const firstLedgerVersion = 32570; // earlier versions have been lost
|
const firstLedgerVersion = 32570; // earlier versions have been lost
|
||||||
return remote.getServer().hasLedgerRange(
|
return remote.getServer().hasLedgerRange(
|
||||||
minLedgerVersion || firstLedgerVersion,
|
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 = {
|
module.exports = {
|
||||||
getXRPBalance,
|
getXRPBalance,
|
||||||
|
getLedgerOptionsWithLedgerVersion,
|
||||||
compareTransactions,
|
compareTransactions,
|
||||||
renameCounterpartyToIssuer,
|
renameCounterpartyToIssuer,
|
||||||
renameCounterpartyToIssuerInOrder,
|
renameCounterpartyToIssuerInOrder,
|
||||||
getRecursive,
|
getRecursive,
|
||||||
hasCompleteLedgerRange,
|
hasCompleteLedgerRange,
|
||||||
wrapCatch: common.wrapCatch,
|
isPendingLedgerVersion,
|
||||||
|
promisify: common.promisify,
|
||||||
clamp: clamp,
|
clamp: clamp,
|
||||||
common: common
|
common: common
|
||||||
};
|
};
|
||||||
|
|||||||
74
src/api/offline/ledgerhash.js
Normal file
74
src/api/offline/ledgerhash.js
Normal 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;
|
||||||
@@ -4,19 +4,41 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
import type {Remote} from '../../core/remote';
|
||||||
|
|
||||||
// If a ledger is not received in this time, consider the connection offline
|
// If a ledger is not received in this time, consider the connection offline
|
||||||
const CONNECTION_TIMEOUT = 1000 * 30;
|
const CONNECTION_TIMEOUT = 1000 * 30;
|
||||||
|
|
||||||
function connect(callback: (err: any, data: any) => void): void {
|
type GetServerInfoResponse = {
|
||||||
this.remote.connect(callback);
|
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 {
|
function isUpToDate(remote: Remote): boolean {
|
||||||
this.remote.disconnect(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isUpToDate(remote): boolean {
|
|
||||||
const server = remote.getServer();
|
const server = remote.getServer();
|
||||||
return Boolean(server) && (remote._stand_alone
|
return Boolean(server) && (remote._stand_alone
|
||||||
|| (Date.now() - server._lastLedgerClose) <= CONNECTION_TIMEOUT);
|
|| (Date.now() - server._lastLedgerClose) <= CONNECTION_TIMEOUT);
|
||||||
@@ -26,23 +48,72 @@ function isConnected(): boolean {
|
|||||||
return Boolean(this.remote._ledger_current_index) && isUpToDate(this.remote);
|
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) => {
|
this.remote.requestServerInfo((error, response) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
const message = _.get(error, ['remote', 'error_message'], error.message);
|
const message = _.get(error, ['remote', 'error_message'], error.message);
|
||||||
callback(new common.errors.RippledNetworkError(message));
|
callback(new common.errors.RippledNetworkError(message));
|
||||||
} else {
|
} else {
|
||||||
callback(null, common.convertKeysFromSnakeCaseToCamelCase(response.info));
|
callback(null,
|
||||||
|
common.convertKeysFromSnakeCaseToCamelCase(response.info));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFee(): number {
|
function getFee(): ?number {
|
||||||
return common.dropsToXrp(this.remote.createTransaction()._computeFee());
|
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 {
|
function getLedgerVersion(): Promise<number> {
|
||||||
return this.remote.getLedgerSequence();
|
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 = {
|
module.exports = {
|
||||||
@@ -51,5 +122,6 @@ module.exports = {
|
|||||||
isConnected,
|
isConnected,
|
||||||
getServerInfo,
|
getServerInfo,
|
||||||
getFee,
|
getFee,
|
||||||
getLedgerVersion
|
getLedgerVersion,
|
||||||
|
formatLedgerClose
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,9 +30,14 @@ function createOrderTransaction(account, order) {
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareOrder(account, order, instructions, callback) {
|
function prepareOrderAsync(account, order, instructions, callback) {
|
||||||
const transaction = createOrderTransaction(account, order);
|
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;
|
||||||
|
|||||||
@@ -13,9 +13,18 @@ function createOrderCancellationTransaction(account, sequence) {
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareOrderCancellation(account, sequence, instructions, callback) {
|
function prepareOrderCancellationAsync(account, sequence, instructions,
|
||||||
|
callback
|
||||||
|
) {
|
||||||
const transaction = createOrderCancellationTransaction(account, sequence);
|
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;
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const BigNumber = require('bignumber.js');
|
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const toRippledAmount = utils.common.toRippledAmount;
|
const toRippledAmount = utils.common.toRippledAmount;
|
||||||
const Transaction = utils.common.core.Transaction;
|
const Transaction = utils.common.core.Transaction;
|
||||||
|
const ValidationError = utils.common.errors.ValidationError;
|
||||||
|
|
||||||
function isSendMaxAllowed(payment) {
|
function isXRPToXRPPayment(payment) {
|
||||||
const srcAmt = payment.source.amount;
|
const sourceCurrency = _.get(payment, 'source.maxAmount.currency');
|
||||||
const dstAmt = payment.destination.amount;
|
const destinationCurrency = _.get(payment, 'destination.amount.currency');
|
||||||
|
return sourceCurrency === 'XRP' && destinationCurrency === 'XRP';
|
||||||
// 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 isIOUWithoutCounterparty(amount) {
|
function isIOUWithoutCounterparty(amount) {
|
||||||
@@ -29,24 +24,49 @@ function applyAnyCounterpartyEncoding(payment) {
|
|||||||
// https://ripple.com/build/transactions/
|
// https://ripple.com/build/transactions/
|
||||||
// #special-issuer-values-for-sendmax-and-amount
|
// #special-issuer-values-for-sendmax-and-amount
|
||||||
// https://ripple.com/build/ripple-rest/#counterparties-in-payments
|
// https://ripple.com/build/ripple-rest/#counterparties-in-payments
|
||||||
if (isIOUWithoutCounterparty(payment.source.amount)) {
|
_.forEach([payment.source, payment.destination], (adjustment) => {
|
||||||
payment.source.amount.counterparty = payment.source.address;
|
_.forEach(['amount', 'minAmount', 'maxAmount'], (key) => {
|
||||||
}
|
if (isIOUWithoutCounterparty(adjustment[key])) {
|
||||||
if (isIOUWithoutCounterparty(payment.destination.amount)) {
|
adjustment[key].counterparty = adjustment.address;
|
||||||
payment.destination.amount.counterparty = payment.destination.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);
|
applyAnyCounterpartyEncoding(payment);
|
||||||
validate.address(account);
|
validate.address(account);
|
||||||
validate.payment(payment);
|
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();
|
const transaction = new Transaction();
|
||||||
transaction.payment({
|
transaction.payment({
|
||||||
from: payment.source.address,
|
from: payment.source.address,
|
||||||
to: payment.destination.address,
|
to: payment.destination.address,
|
||||||
amount: toRippledAmount(payment.destination.amount)
|
amount: toRippledAmount(amount)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (payment.invoiceID) {
|
if (payment.invoiceID) {
|
||||||
@@ -58,36 +78,51 @@ function createPaymentTransaction(account, payment) {
|
|||||||
if (payment.destination.tag) {
|
if (payment.destination.tag) {
|
||||||
transaction.destinationTag(payment.destination.tag);
|
transaction.destinationTag(payment.destination.tag);
|
||||||
}
|
}
|
||||||
if (payment.paths) {
|
|
||||||
transaction.paths(JSON.parse(payment.paths));
|
|
||||||
}
|
|
||||||
if (payment.memos) {
|
if (payment.memos) {
|
||||||
_.forEach(payment.memos, memo =>
|
_.forEach(payment.memos, memo =>
|
||||||
transaction.addMemo(memo.type, memo.format, memo.data)
|
transaction.addMemo(memo.type, memo.format, memo.data)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (payment.allowPartialPayment) {
|
|
||||||
transaction.setFlags(['PartialPayment']);
|
|
||||||
}
|
|
||||||
if (payment.noDirectRipple) {
|
if (payment.noDirectRipple) {
|
||||||
transaction.setFlags(['NoRippleDirect']);
|
transaction.setFlags(['NoRippleDirect']);
|
||||||
}
|
}
|
||||||
if (payment.limitQuality) {
|
if (payment.limitQuality) {
|
||||||
transaction.setFlags(['LimitQuality']);
|
transaction.setFlags(['LimitQuality']);
|
||||||
}
|
}
|
||||||
if (isSendMaxAllowed(payment)) {
|
if (!isXRPToXRPPayment(payment)) {
|
||||||
const maxValue = new BigNumber(payment.source.amount.value)
|
// Don't set SendMax for XRP->XRP payment
|
||||||
.plus(payment.source.slippage || 0).toString();
|
// temREDUNDANT_SEND_MAX removed in:
|
||||||
const maxAmount = _.assign({}, payment.source.amount, {value: maxValue});
|
// https://github.com/ripple/rippled/commit/
|
||||||
transaction.sendMax(toRippledAmount(maxAmount));
|
// 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;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function preparePayment(account, payment, instructions, callback) {
|
function preparePaymentAsync(account, payment, instructions, callback) {
|
||||||
const transaction = createPaymentTransaction(account, payment);
|
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;
|
||||||
|
|||||||
@@ -90,9 +90,14 @@ function createSettingsTransaction(account, settings) {
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareSettings(account, settings, instructions, callback) {
|
function prepareSettingsAsync(account, settings, instructions, callback) {
|
||||||
const transaction = createSettingsTransaction(account, settings);
|
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;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
|
const keypairs = require('ripple-keypairs');
|
||||||
const core = utils.common.core;
|
const core = utils.common.core;
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
|
|
||||||
@@ -15,16 +16,6 @@ const validate = utils.common.validate;
|
|||||||
* some arbitrary string. For example "TXN".
|
* some arbitrary string. For example "TXN".
|
||||||
*/
|
*/
|
||||||
const HASH_TX_ID = 0x54584E00; // 'TXN'
|
const HASH_TX_ID = 0x54584E00; // 'TXN'
|
||||||
const HASH_TX_SIGN = 0x53545800; // 'STX'
|
|
||||||
const HASH_TX_SIGN_TESTNET = 0x73747800; // 'stx'
|
|
||||||
|
|
||||||
function getKeyPair(secret) {
|
|
||||||
return core.Seed.from_json(secret).get_key();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPublicKeyHex(keypair) {
|
|
||||||
return keypair.to_hex_pub();
|
|
||||||
}
|
|
||||||
|
|
||||||
function serialize(txJSON) {
|
function serialize(txJSON) {
|
||||||
return core.SerializedObject.from_json(txJSON);
|
return core.SerializedObject.from_json(txJSON);
|
||||||
@@ -34,31 +25,26 @@ function hashSerialization(serialized, prefix) {
|
|||||||
return serialized.hash(prefix || HASH_TX_ID).to_hex();
|
return serialized.hash(prefix || HASH_TX_ID).to_hex();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hashJSON(txJSON, prefix) {
|
function signingData(txJSON) {
|
||||||
return hashSerialization(serialize(txJSON), prefix);
|
return core.Transaction.from_json(txJSON).signingData().buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function signingHash(txJSON, isTestNet=false) {
|
function computeSignature(txJSON, privateKey) {
|
||||||
return hashJSON(txJSON, isTestNet ? HASH_TX_SIGN_TESTNET : HASH_TX_SIGN);
|
return keypairs.sign(signingData(txJSON), privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeSignature(txJSON, keypair) {
|
function sign(txJSON: string, secret: string
|
||||||
const signature = keypair.sign(signingHash(txJSON));
|
): {signedTransaction: string; id: string} {
|
||||||
return core.sjcl.codec.hex.fromBits(signature).toUpperCase();
|
const tx = JSON.parse(txJSON);
|
||||||
}
|
validate.txJSON(tx);
|
||||||
|
|
||||||
function sign(txJSON: {Account: string; SigningPubKey: string,
|
|
||||||
TxnSignature: string}, secret: string):
|
|
||||||
{signedTransaction: string; id: string} {
|
|
||||||
validate.txJSON(txJSON);
|
|
||||||
validate.secret(secret);
|
validate.secret(secret);
|
||||||
|
|
||||||
const keypair = getKeyPair(secret);
|
const keypair = keypairs.deriveKeypair(secret);
|
||||||
if (txJSON.SigningPubKey === undefined) {
|
if (tx.SigningPubKey === undefined) {
|
||||||
txJSON.SigningPubKey = getPublicKeyHex(keypair);
|
tx.SigningPubKey = keypair.publicKey;
|
||||||
}
|
}
|
||||||
txJSON.TxnSignature = computeSignature(txJSON, keypair);
|
tx.TxnSignature = computeSignature(tx, keypair.privateKey);
|
||||||
const serialized = serialize(txJSON);
|
const serialized = serialize(tx);
|
||||||
return {
|
return {
|
||||||
signedTransaction: serialized.to_hex(),
|
signedTransaction: serialized.to_hex(),
|
||||||
id: hashSerialization(serialized, HASH_TX_ID)
|
id: hashSerialization(serialized, HASH_TX_ID)
|
||||||
|
|||||||
@@ -1,17 +1,44 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
const _ = require('lodash');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const validate = utils.common.validate;
|
const validate = utils.common.validate;
|
||||||
const Request = utils.common.core.Request;
|
const Request = utils.common.core.Request;
|
||||||
|
const convertErrors = utils.common.convertErrors;
|
||||||
|
|
||||||
function submit(txBlob: string, callback: (err: any, data: any) => void): void {
|
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);
|
validate.blob(txBlob);
|
||||||
const request = new Request(this.remote, 'submit');
|
const request = new Request(this.remote, 'submit');
|
||||||
request.message.tx_blob = txBlob;
|
request.message.tx_blob = txBlob;
|
||||||
request.request(null,
|
request.request(null,
|
||||||
utils.common.composeAsync(
|
utils.common.composeAsync(
|
||||||
data => utils.common.convertKeysFromSnakeCaseToCamelCase(data),
|
data => utils.common.convertKeysFromSnakeCaseToCamelCase(data),
|
||||||
callback));
|
convertSubmitErrors(convertErrors(callback))));
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit(txBlob: string) {
|
||||||
|
return utils.promisify(submitAsync.bind(this))(txBlob);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = submit;
|
module.exports = submit;
|
||||||
|
|||||||
40
src/api/transaction/suspended-payment-cancellation.js
Normal file
40
src/api/transaction/suspended-payment-cancellation.js
Normal 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;
|
||||||
57
src/api/transaction/suspended-payment-creation.js
Normal file
57
src/api/transaction/suspended-payment-creation.js
Normal 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;
|
||||||
50
src/api/transaction/suspended-payment-execution.js
Normal file
50
src/api/transaction/suspended-payment-execution.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* @flow */
|
||||||
|
'use strict';
|
||||||
|
const _ = require('lodash');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const validate = utils.common.validate;
|
||||||
|
const Transaction = utils.common.core.Transaction;
|
||||||
|
|
||||||
|
function createSuspendedPaymentExecutionTransaction(account, payment) {
|
||||||
|
validate.address(account);
|
||||||
|
validate.suspendedPaymentExecution(payment);
|
||||||
|
|
||||||
|
const transaction = new Transaction();
|
||||||
|
transaction.suspendedPaymentFinish({
|
||||||
|
account: account,
|
||||||
|
owner: payment.owner,
|
||||||
|
paymentSequence: payment.paymentSequence
|
||||||
|
});
|
||||||
|
|
||||||
|
if (payment.method) {
|
||||||
|
transaction.setMethod(payment.method);
|
||||||
|
}
|
||||||
|
if (payment.digest) {
|
||||||
|
transaction.setDigest(payment.digest);
|
||||||
|
}
|
||||||
|
if (payment.proof) {
|
||||||
|
transaction.setProof(payment.proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment.memos) {
|
||||||
|
_.forEach(payment.memos, memo =>
|
||||||
|
transaction.addMemo(memo.type, memo.format, memo.data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareSuspendedPaymentExecutionAsync(account, payment, instructions,
|
||||||
|
callback) {
|
||||||
|
const transaction =
|
||||||
|
createSuspendedPaymentExecutionTransaction(account, payment);
|
||||||
|
utils.prepareTransaction(transaction, this.remote, instructions, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareSuspendedPaymentExecution(account: string, payment: Object,
|
||||||
|
instructions = {}) {
|
||||||
|
return utils.promisify(prepareSuspendedPaymentExecutionAsync)
|
||||||
|
.call(this, account, payment, instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = prepareSuspendedPaymentExecution;
|
||||||
@@ -12,7 +12,8 @@ const TrustSetFlags = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function convertQuality(quality) {
|
function convertQuality(quality) {
|
||||||
return (new BigNumber(quality)).shift(9).truncated().toNumber();
|
return quality === undefined ? undefined :
|
||||||
|
(new BigNumber(quality)).shift(9).truncated().toNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTrustlineTransaction(account, trustline) {
|
function createTrustlineTransaction(account, trustline) {
|
||||||
@@ -32,9 +33,15 @@ function createTrustlineTransaction(account, trustline) {
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareTrustline(account, trustline, instructions, callback) {
|
function prepareTrustlineAsync(account, trustline, instructions, callback) {
|
||||||
const transaction = createTrustlineTransaction(account, trustline);
|
const transaction = createTrustlineTransaction(account, trustline);
|
||||||
utils.createTxJSON(transaction, this.remote, instructions, callback);
|
utils.prepareTransaction(transaction, this.remote, instructions, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = utils.wrapCatch(prepareTrustline);
|
function prepareTrustline(account: string, trustline: Object, instructions = {}
|
||||||
|
) {
|
||||||
|
return utils.promisify(prepareTrustlineAsync.bind(this))(
|
||||||
|
account, trustline, instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = prepareTrustline;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
const _ = require('lodash');
|
||||||
|
const async = require('async');
|
||||||
const BigNumber = require('bignumber.js');
|
const BigNumber = require('bignumber.js');
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
const composeAsync = common.composeAsync;
|
||||||
|
|
||||||
function setTransactionBitFlags(transaction: any, values: any, flags: any):
|
function setTransactionBitFlags(transaction: any, values: any, flags: any
|
||||||
void {
|
): void {
|
||||||
for (const flagName in flags) {
|
for (const flagName in flags) {
|
||||||
const flagValue = values[flagName];
|
const flagValue = values[flagName];
|
||||||
const flagConversions = flags[flagName];
|
const flagConversions = flags[flagName];
|
||||||
@@ -18,53 +21,91 @@ function setTransactionBitFlags(transaction: any, values: any, flags: any):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFeeDrops(remote) {
|
function getFeeDrops(remote, callback) {
|
||||||
const feeUnits = 10; // all transactions currently have a fee of 10 fee units
|
const feeUnits = 10; // all transactions currently have a fee of 10 fee units
|
||||||
return remote.feeTx(feeUnits).to_text();
|
remote.feeTxAsync(feeUnits, (err, data) => {
|
||||||
|
callback(err, data ? data.to_text() : undefined);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTxJSON(transaction: any, remote: any, instructions: any,
|
function formatPrepareResponse(txJSON) {
|
||||||
callback: (err: ?(typeof Error), data: {tx_json: any}) => void): void {
|
const instructions = {
|
||||||
|
fee: txJSON.Fee,
|
||||||
|
sequence: txJSON.Sequence,
|
||||||
|
maxLedgerVersion: txJSON.LastLedgerSequence
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
txJSON: JSON.stringify(txJSON),
|
||||||
|
instructions: _.omit(instructions, _.isUndefined)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type Callback = (err: ?(typeof Error),
|
||||||
|
data: {txJSON: string, instructions: any}) => void;
|
||||||
|
function prepareTransaction(transaction: any, remote: any, instructions: any,
|
||||||
|
callback: Callback
|
||||||
|
): void {
|
||||||
common.validate.instructions(instructions);
|
common.validate.instructions(instructions);
|
||||||
|
|
||||||
transaction.complete();
|
transaction.complete();
|
||||||
const account = transaction.getAccount();
|
const account = transaction.getAccount();
|
||||||
const txJSON = transaction.tx_json;
|
const txJSON = transaction.tx_json;
|
||||||
|
|
||||||
if (instructions.maxLedgerVersion !== undefined) {
|
|
||||||
txJSON.LastLedgerSequence = parseInt(instructions.maxLedgerVersion, 10);
|
|
||||||
} else {
|
|
||||||
const offset = instructions.maxLedgerVersionOffset !== undefined ?
|
|
||||||
parseInt(instructions.maxLedgerVersionOffset, 10) : 3;
|
|
||||||
txJSON.LastLedgerSequence = remote.getLedgerSequence() + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instructions.fee !== undefined) {
|
function prepareMaxLedgerVersion(callback_) {
|
||||||
txJSON.Fee = common.xrpToDrops(instructions.fee);
|
if (instructions.maxLedgerVersion !== undefined) {
|
||||||
} else {
|
txJSON.LastLedgerSequence = parseInt(instructions.maxLedgerVersion, 10);
|
||||||
const serverFeeDrops = getFeeDrops(remote);
|
callback_();
|
||||||
if (instructions.maxFee !== undefined) {
|
|
||||||
const maxFeeDrops = common.xrpToDrops(instructions.maxFee);
|
|
||||||
txJSON.Fee = BigNumber.min(serverFeeDrops, maxFeeDrops).toString();
|
|
||||||
} else {
|
} else {
|
||||||
txJSON.Fee = serverFeeDrops;
|
const offset = instructions.maxLedgerVersionOffset !== undefined ?
|
||||||
|
parseInt(instructions.maxLedgerVersionOffset, 10) : 3;
|
||||||
|
remote.getLedgerSequence((error, ledgerVersion) => {
|
||||||
|
txJSON.LastLedgerSequence = ledgerVersion + offset;
|
||||||
|
callback_(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instructions.sequence !== undefined) {
|
function prepareFee(callback_) {
|
||||||
txJSON.Sequence = parseInt(instructions.sequence, 10);
|
if (instructions.fee !== undefined) {
|
||||||
callback(null, txJSON);
|
txJSON.Fee = common.xrpToDrops(instructions.fee);
|
||||||
} else {
|
callback_();
|
||||||
remote.findAccount(account).getNextSequence(function(error, sequence) {
|
} else {
|
||||||
txJSON.Sequence = sequence;
|
getFeeDrops(remote, composeAsync((serverFeeDrops) => {
|
||||||
callback(null, txJSON);
|
if (instructions.maxFee !== undefined) {
|
||||||
});
|
const maxFeeDrops = common.xrpToDrops(instructions.maxFee);
|
||||||
|
txJSON.Fee = BigNumber.min(serverFeeDrops, maxFeeDrops).toString();
|
||||||
|
} else {
|
||||||
|
txJSON.Fee = serverFeeDrops;
|
||||||
|
}
|
||||||
|
}, callback_));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepareSequence(callback_) {
|
||||||
|
if (instructions.sequence !== undefined) {
|
||||||
|
txJSON.Sequence = parseInt(instructions.sequence, 10);
|
||||||
|
callback_(null, formatPrepareResponse(txJSON));
|
||||||
|
} else {
|
||||||
|
remote.findAccount(account).getNextSequence(function(error, sequence) {
|
||||||
|
txJSON.Sequence = sequence;
|
||||||
|
callback_(error, formatPrepareResponse(txJSON));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
prepareMaxLedgerVersion,
|
||||||
|
prepareFee,
|
||||||
|
prepareSequence
|
||||||
|
], common.convertErrors(function(error, results) {
|
||||||
|
callback(error, results && results[2]);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
setTransactionBitFlags: setTransactionBitFlags,
|
setTransactionBitFlags,
|
||||||
createTxJSON: createTxJSON,
|
prepareTransaction,
|
||||||
wrapCatch: common.wrapCatch,
|
common,
|
||||||
common: common
|
promisify: common.promisify
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,13 +12,12 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const util = require('util');
|
|
||||||
const extend = require('extend');
|
const extend = require('extend');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const util = require('util');
|
||||||
const UInt160 = require('./uint160').UInt160;
|
const {deriveAddress} = require('ripple-keypairs');
|
||||||
const TransactionManager = require('./transactionmanager').TransactionManager;
|
const {EventEmitter} = require('events');
|
||||||
const sjcl = require('./utils').sjcl;
|
const {TransactionManager} = require('./transactionmanager');
|
||||||
const Base = require('./base').Base;
|
const {isValidAddress} = require('ripple-address-codec');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor Account
|
* @constructor Account
|
||||||
@@ -26,14 +25,13 @@ const Base = require('./base').Base;
|
|||||||
* @param {String} account
|
* @param {String} account
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Account(remote, account) {
|
function Account(remote, address) {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
this._remote = remote;
|
this._remote = remote;
|
||||||
this._account = UInt160.from_json(account);
|
this._address = address;
|
||||||
this._account_id = this._account.to_json();
|
|
||||||
this._subs = 0;
|
this._subs = 0;
|
||||||
|
|
||||||
// Ledger entry object
|
// Ledger entry object
|
||||||
@@ -41,10 +39,10 @@ function Account(remote, account) {
|
|||||||
this._entry = { };
|
this._entry = { };
|
||||||
|
|
||||||
function listenerAdded(type) {
|
function listenerAdded(type) {
|
||||||
if (~Account.subscribeEvents.indexOf(type)) {
|
if (_.includes(Account.subscribeEvents, type)) {
|
||||||
if (!self._subs && self._remote._connected) {
|
if (!self._subs && self._remote._connected) {
|
||||||
self._remote.requestSubscribe()
|
self._remote.requestSubscribe()
|
||||||
.addAccount(self._account_id)
|
.addAccount(self._address)
|
||||||
.broadcast().request();
|
.broadcast().request();
|
||||||
}
|
}
|
||||||
self._subs += 1;
|
self._subs += 1;
|
||||||
@@ -54,11 +52,11 @@ function Account(remote, account) {
|
|||||||
this.on('newListener', listenerAdded);
|
this.on('newListener', listenerAdded);
|
||||||
|
|
||||||
function listenerRemoved(type) {
|
function listenerRemoved(type) {
|
||||||
if (~Account.subscribeEvents.indexOf(type)) {
|
if (_.includes(Account.subscribeEvents, type)) {
|
||||||
self._subs -= 1;
|
self._subs -= 1;
|
||||||
if (!self._subs && self._remote._connected) {
|
if (!self._subs && self._remote._connected) {
|
||||||
self._remote.requestUnsubscribe()
|
self._remote.requestUnsubscribe()
|
||||||
.addAccount(self._account_id)
|
.addAccount(self._address)
|
||||||
.broadcast().request();
|
.broadcast().request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,8 +65,8 @@ function Account(remote, account) {
|
|||||||
this.on('removeListener', listenerRemoved);
|
this.on('removeListener', listenerRemoved);
|
||||||
|
|
||||||
function attachAccount(request) {
|
function attachAccount(request) {
|
||||||
if (self._account.is_valid() && self._subs) {
|
if (isValidAddress(self._address) && self._subs) {
|
||||||
request.add_account(self._account_id);
|
request.addAccount(self._address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ function Account(remote, account) {
|
|||||||
let changed = false;
|
let changed = false;
|
||||||
|
|
||||||
transaction.mmeta.each(function(an) {
|
transaction.mmeta.each(function(an) {
|
||||||
const isAccount = an.fields.Account === self._account_id;
|
const isAccount = an.fields.Account === self._address;
|
||||||
const isAccountRoot = isAccount && (an.entryType === 'AccountRoot');
|
const isAccountRoot = isAccount && (an.entryType === 'AccountRoot');
|
||||||
|
|
||||||
if (isAccountRoot) {
|
if (isAccountRoot) {
|
||||||
@@ -112,7 +110,7 @@ util.inherits(Account, EventEmitter);
|
|||||||
Account.subscribeEvents = ['transaction', 'entry'];
|
Account.subscribeEvents = ['transaction', 'entry'];
|
||||||
|
|
||||||
Account.prototype.toJson = function() {
|
Account.prototype.toJson = function() {
|
||||||
return this._account.to_json();
|
return this._address;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +120,7 @@ Account.prototype.toJson = function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.isValid = function() {
|
Account.prototype.isValid = function() {
|
||||||
return this._account.is_valid();
|
return isValidAddress(this._address);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,7 +130,7 @@ Account.prototype.isValid = function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Account.prototype.getInfo = function(callback) {
|
Account.prototype.getInfo = function(callback) {
|
||||||
return this._remote.requestAccountInfo({account: this._account_id}, callback);
|
return this._remote.requestAccountInfo({account: this._address}, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,7 +209,7 @@ Account.prototype.lines = function(callback_) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._remote.requestAccountLines({account: this._account_id}, accountLines);
|
this._remote.requestAccountLines({account: this._address}, accountLines);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -276,7 +274,7 @@ Account.prototype.notifyTx = function(transaction) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isThisAccount = (account === this._account_id);
|
const isThisAccount = (account === this._address);
|
||||||
|
|
||||||
this.emit(isThisAccount ? 'transaction-outbound' : 'transaction-inbound',
|
this.emit(isThisAccount ? 'transaction-outbound' : 'transaction-inbound',
|
||||||
transaction);
|
transaction);
|
||||||
@@ -332,7 +330,7 @@ Account.prototype.publicKeyIsActive = function(public_key, callback) {
|
|||||||
// Catch the case of unfunded accounts
|
// Catch the case of unfunded accounts
|
||||||
if (!account_info_res) {
|
if (!account_info_res) {
|
||||||
|
|
||||||
if (public_key_as_uint160 === self._account_id) {
|
if (public_key_as_uint160 === self._address) {
|
||||||
async_callback(null, true);
|
async_callback(null, true);
|
||||||
} else {
|
} else {
|
||||||
async_callback(null, false);
|
async_callback(null, false);
|
||||||
@@ -374,25 +372,17 @@ Account.prototype.publicKeyIsActive = function(public_key, callback) {
|
|||||||
* @returns {RippleAddress} Ripple Address
|
* @returns {RippleAddress} Ripple Address
|
||||||
*/
|
*/
|
||||||
Account._publicKeyToAddress = function(public_key) {
|
Account._publicKeyToAddress = function(public_key) {
|
||||||
// Based on functions in /src/js/ripple/keypair.js
|
if (isValidAddress(public_key)) {
|
||||||
function hexToUInt160(publicKey) {
|
|
||||||
const bits = sjcl.codec.hex.toBits(publicKey);
|
|
||||||
const hash = sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
|
|
||||||
const address = UInt160.from_bits(hash);
|
|
||||||
address.set_version(Base.VER_ACCOUNT_ID);
|
|
||||||
|
|
||||||
return address.to_json();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UInt160.is_valid(public_key)) {
|
|
||||||
return public_key;
|
return public_key;
|
||||||
} else if (/^[0-9a-fA-F]+$/.test(public_key)) {
|
} else if (/^[0-9a-fA-F]+$/.test(public_key)) {
|
||||||
return hexToUInt160(public_key);
|
return deriveAddress(public_key);
|
||||||
} else { // eslint-disable-line no-else-return
|
} else { // eslint-disable-line no-else-return
|
||||||
throw new Error('Public key is invalid. Must be a UInt160 or a hex string');
|
throw new Error('Public key is invalid. Must be a UInt160 or a hex string');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Account = Account;
|
module.exports = {
|
||||||
|
Account
|
||||||
|
};
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
// vim:sw=2:sts=2:ts=8:et
|
||||||
|
|||||||
@@ -6,23 +6,23 @@
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const extend = require('extend');
|
const extend = require('extend');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const UInt160 = require('./uint160').UInt160;
|
|
||||||
const Seed = require('./seed').Seed;
|
|
||||||
const Currency = require('./currency').Currency;
|
const Currency = require('./currency').Currency;
|
||||||
const Value = require('./value').Value;
|
const {XRPValue, IOUValue} = require('ripple-lib-value');
|
||||||
const IOUValue = require('./iouvalue').IOUValue;
|
const {isValidAddress} = require('ripple-address-codec');
|
||||||
const XRPValue = require('./xrpvalue').XRPValue;
|
const {ACCOUNT_ONE, ACCOUNT_ZERO} = require('./constants');
|
||||||
|
|
||||||
|
type Value = XRPValue | IOUValue;
|
||||||
|
|
||||||
function Amount(value = new XRPValue(NaN)) {
|
function Amount(value = new XRPValue(NaN)) {
|
||||||
// Json format:
|
// Json format:
|
||||||
// integer : XRP
|
// integer : XRP
|
||||||
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
|
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
|
||||||
assert(value instanceof Value);
|
assert(value instanceof XRPValue || value instanceof IOUValue);
|
||||||
|
|
||||||
this._value = value;
|
this._value = value;
|
||||||
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
|
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
|
||||||
this._currency = new Currency();
|
this._currency = new Currency();
|
||||||
this._issuer = new UInt160();
|
this._issuer = 'NaN';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,13 +49,13 @@ const consts = {
|
|||||||
// Maximum possible amount for non-XRP currencies using the maximum mantissa
|
// Maximum possible amount for non-XRP currencies using the maximum mantissa
|
||||||
// with maximum exponent. Corresponds to hex 0xEC6386F26FC0FFFF.
|
// with maximum exponent. Corresponds to hex 0xEC6386F26FC0FFFF.
|
||||||
max_value: '9999999999999999e80',
|
max_value: '9999999999999999e80',
|
||||||
// Minimum possible amount for non-XRP currencies.
|
// Minimum nonzero absolute value for non-XRP currencies.
|
||||||
min_value: '-1000000000000000e-96'
|
min_value: '1000000000000000e-96'
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_XRP_VALUE = new XRPValue(1e11);
|
const MAX_XRP_VALUE = new XRPValue(1e11);
|
||||||
const MAX_IOU_VALUE = new IOUValue(consts.max_value);
|
const MAX_IOU_VALUE = new IOUValue(consts.max_value);
|
||||||
const MIN_IOU_VALUE = new IOUValue(consts.min_value).abs();
|
const MIN_IOU_VALUE = new IOUValue(consts.min_value);
|
||||||
|
|
||||||
const bi_xns_unit = new IOUValue(1e6);
|
const bi_xns_unit = new IOUValue(1e6);
|
||||||
|
|
||||||
@@ -105,44 +105,56 @@ Amount.NaN = function() {
|
|||||||
return result; // but let's be careful
|
return result; // but let's be careful
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Amount.from_components_unsafe = function(value: Value, currency: Currency,
|
||||||
|
issuer: string, isNative: boolean
|
||||||
|
) {
|
||||||
|
const result = new Amount(value);
|
||||||
|
result._is_native = isNative;
|
||||||
|
result._currency = currency;
|
||||||
|
result._issuer = issuer;
|
||||||
|
|
||||||
|
result._value = value.isZero() && value.isNegative() ?
|
||||||
|
value.negate() : value;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
// be sure that _is_native is set properly BEFORE calling _set_value
|
// be sure that _is_native is set properly BEFORE calling _set_value
|
||||||
Amount.prototype._set_value = function(value: Value) {
|
Amount.prototype._set_value = function(value: Value) {
|
||||||
|
|
||||||
this._value = value.isZero() && value.isNegative() ?
|
this._value = value.isZero() && value.isNegative() ?
|
||||||
value.negate() : value;
|
value.negate() : value;
|
||||||
this._check_limits();
|
this._check_limits();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a new value which is the absolute value of this.
|
// Returns a new value which is the absolute value of this.
|
||||||
Amount.prototype.abs = function() {
|
Amount.prototype.abs = function() {
|
||||||
|
|
||||||
return this._copy(this._value.abs());
|
return this._copy(this._value.abs());
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.add = function(addend) {
|
Amount.prototype.add = function(addend) {
|
||||||
const addendAmount = Amount.from_json(addend);
|
const addendAmount = addend instanceof Amount ?
|
||||||
|
addend : Amount.from_json(addend);
|
||||||
|
|
||||||
if (!this.is_comparable(addendAmount)) {
|
if (!this.is_comparable(addendAmount)) {
|
||||||
return new Amount();
|
return new Amount();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._copy(this._value.add(addendAmount._value));
|
return this._copy(this._value.add(addendAmount._value));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.subtract = function(subtrahend) {
|
Amount.prototype.subtract = function(subtrahend) {
|
||||||
// Correctness over speed, less code has less bugs, reuse add code.
|
// Correctness over speed, less code has less bugs, reuse add code.
|
||||||
return this.add(Amount.from_json(subtrahend).negate());
|
const subsAmount = subtrahend instanceof Amount ?
|
||||||
|
subtrahend : Amount.from_json(subtrahend);
|
||||||
|
return this.add(subsAmount.negate());
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX Diverges from cpp.
|
// XXX Diverges from cpp.
|
||||||
Amount.prototype.multiply = function(multiplicand) {
|
Amount.prototype.multiply = function(multiplicand) {
|
||||||
|
const multiplicandValue = multiplicand instanceof Amount ?
|
||||||
|
multiplicand._value :
|
||||||
|
Amount.from_json(multiplicand)._value;
|
||||||
|
|
||||||
const multiplicandAmount = Amount.from_json(multiplicand);
|
return this._copy(this._value.multiply(multiplicandValue));
|
||||||
|
|
||||||
return this._copy(this._value.multiply(multiplicandAmount._value));
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,9 +163,11 @@ Amount.prototype.scale = function(scaleFactor) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.divide = function(divisor) {
|
Amount.prototype.divide = function(divisor) {
|
||||||
const divisorAmount = Amount.from_json(divisor);
|
const divisorValue = divisor instanceof Amount ?
|
||||||
|
divisor._value :
|
||||||
|
Amount.from_json(divisor)._value;
|
||||||
|
|
||||||
return this._copy(this._value.divide(divisorAmount._value));
|
return this._copy(this._value.divide(divisorValue));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,7 +225,7 @@ Amount.prototype.ratio_human = function(denom, opts) {
|
|||||||
//
|
//
|
||||||
// To compensate, we multiply the numerator by 10^xns_precision.
|
// To compensate, we multiply the numerator by 10^xns_precision.
|
||||||
if (denominator._is_native) {
|
if (denominator._is_native) {
|
||||||
numerator._set_value(numerator.multiply(bi_xns_unit));
|
numerator._set_value(numerator._value.multiply(bi_xns_unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
return numerator.divide(denominator);
|
return numerator.divide(denominator);
|
||||||
@@ -344,7 +358,7 @@ Amount.prototype._check_limits = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.clone = function(negate) {
|
Amount.prototype.clone = function(negate) {
|
||||||
return this.copyTo(new Amount(), negate);
|
return this.copyTo(new Amount(this._value), negate);
|
||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype._copy = function(value) {
|
Amount.prototype._copy = function(value) {
|
||||||
@@ -354,9 +368,10 @@ Amount.prototype._copy = function(value) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.compareTo = function(to) {
|
Amount.prototype.compareTo = function(to) {
|
||||||
const toAmount = Amount.from_json(to);
|
const toAmount = to instanceof Amount ? to : Amount.from_json(to);
|
||||||
|
|
||||||
if (!this.is_comparable(toAmount)) {
|
if (!this.is_comparable(toAmount)) {
|
||||||
return new Amount();
|
throw new Error('Not comparable');
|
||||||
}
|
}
|
||||||
return this._value.comparedTo(toAmount._value);
|
return this._value.comparedTo(toAmount._value);
|
||||||
};
|
};
|
||||||
@@ -384,7 +399,7 @@ Amount.prototype.equals = function(d, ignore_issuer) {
|
|||||||
&& this._is_native === d._is_native
|
&& this._is_native === d._is_native
|
||||||
&& this._value.equals(d._value)
|
&& this._value.equals(d._value)
|
||||||
&& (this._is_native || (this._currency.equals(d._currency)
|
&& (this._is_native || (this._currency.equals(d._currency)
|
||||||
&& (ignore_issuer || this._issuer.equals(d._issuer))));
|
&& (ignore_issuer || this._issuer === d._issuer)));
|
||||||
};
|
};
|
||||||
|
|
||||||
// True if Amounts are valid and both native or non-native.
|
// True if Amounts are valid and both native or non-native.
|
||||||
@@ -410,9 +425,8 @@ Amount.prototype.is_valid = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.is_valid_full = function() {
|
Amount.prototype.is_valid_full = function() {
|
||||||
return this.is_valid()
|
return this.is_valid() && this._currency.is_valid()
|
||||||
&& this._currency.is_valid()
|
&& isValidAddress(this._issuer) && this._issuer !== ACCOUNT_ZERO;
|
||||||
&& this._issuer.is_valid();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.is_zero = function() {
|
Amount.prototype.is_zero = function() {
|
||||||
@@ -514,7 +528,7 @@ Amount.prototype.parse_human = function(j, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.parse_issuer = function(issuer) {
|
Amount.prototype.parse_issuer = function(issuer) {
|
||||||
this._issuer = UInt160.from_json(issuer);
|
this._issuer = issuer;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -565,7 +579,7 @@ function(quality, counterCurrency, counterIssuer, opts) {
|
|||||||
const offset = parseInt(offset_hex, 16) - 100;
|
const offset = parseInt(offset_hex, 16) - 100;
|
||||||
|
|
||||||
this._currency = Currency.from_json(counterCurrency);
|
this._currency = Currency.from_json(counterCurrency);
|
||||||
this._issuer = UInt160.from_json(counterIssuer);
|
this._issuer = counterIssuer;
|
||||||
this._is_native = this._currency.is_native();
|
this._is_native = this._currency.is_native();
|
||||||
|
|
||||||
if (this._is_native && baseCurrency.is_native()) {
|
if (this._is_native && baseCurrency.is_native()) {
|
||||||
@@ -607,7 +621,8 @@ function(quality, counterCurrency, counterIssuer, opts) {
|
|||||||
}
|
}
|
||||||
if (this._is_native) {
|
if (this._is_native) {
|
||||||
this._set_value(
|
this._set_value(
|
||||||
new XRPValue(nativeAdjusted.round(6, Value.getBNRoundDown()).toString()));
|
new XRPValue(nativeAdjusted.round(6, XRPValue.getBNRoundDown())
|
||||||
|
.toString()));
|
||||||
} else {
|
} else {
|
||||||
this._set_value(nativeAdjusted);
|
this._set_value(nativeAdjusted);
|
||||||
}
|
}
|
||||||
@@ -624,7 +639,7 @@ function(quality, counterCurrency, counterIssuer, opts) {
|
|||||||
Amount.prototype.parse_number = function(n) {
|
Amount.prototype.parse_number = function(n) {
|
||||||
this._is_native = false;
|
this._is_native = false;
|
||||||
this._currency = Currency.from_json(1);
|
this._currency = Currency.from_json(1);
|
||||||
this._issuer = UInt160.from_json(1);
|
this._issuer = ACCOUNT_ONE;
|
||||||
this._set_value(new IOUValue(n));
|
this._set_value(new IOUValue(n));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -640,15 +655,15 @@ Amount.prototype.parse_json = function(j) {
|
|||||||
if (m) {
|
if (m) {
|
||||||
this._currency = Currency.from_json(m[2]);
|
this._currency = Currency.from_json(m[2]);
|
||||||
if (m[3]) {
|
if (m[3]) {
|
||||||
this._issuer = UInt160.from_json(m[3]);
|
this._issuer = m[3];
|
||||||
} else {
|
} else {
|
||||||
this._issuer = UInt160.from_json('1');
|
this._issuer = 'NaN';
|
||||||
}
|
}
|
||||||
this.parse_value(m[1]);
|
this.parse_value(m[1]);
|
||||||
} else {
|
} else {
|
||||||
this.parse_native(j);
|
this.parse_native(j);
|
||||||
this._currency = Currency.from_json('0');
|
this._currency = Currency.from_json('0');
|
||||||
this._issuer = UInt160.from_json('0');
|
this._issuer = ACCOUNT_ZERO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -667,9 +682,10 @@ Amount.prototype.parse_json = function(j) {
|
|||||||
// Parse the passed value to sanitize and copy it.
|
// Parse the passed value to sanitize and copy it.
|
||||||
this._currency.parse_json(j.currency, true); // Never XRP.
|
this._currency.parse_json(j.currency, true); // Never XRP.
|
||||||
|
|
||||||
if (typeof j.issuer === 'string') {
|
if (typeof j.issuer !== 'string') {
|
||||||
this._issuer.parse_json(j.issuer);
|
throw new Error('issuer must be a string');
|
||||||
}
|
}
|
||||||
|
this._issuer = j.issuer;
|
||||||
|
|
||||||
this.parse_value(j.value);
|
this.parse_value(j.value);
|
||||||
}
|
}
|
||||||
@@ -705,7 +721,7 @@ Amount.prototype.parse_native = function(j) {
|
|||||||
// Requires _currency to be set!
|
// Requires _currency to be set!
|
||||||
Amount.prototype.parse_value = function(j) {
|
Amount.prototype.parse_value = function(j) {
|
||||||
this._is_native = false;
|
this._is_native = false;
|
||||||
const newValue = new IOUValue(j, Value.getBNRoundDown());
|
const newValue = new IOUValue(j, IOUValue.getBNRoundDown());
|
||||||
this._set_value(newValue);
|
this._set_value(newValue);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -717,12 +733,7 @@ Amount.prototype.set_currency = function(c) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.set_issuer = function(issuer) {
|
Amount.prototype.set_issuer = function(issuer) {
|
||||||
if (issuer instanceof UInt160) {
|
this._issuer = issuer;
|
||||||
this._issuer = issuer;
|
|
||||||
} else {
|
|
||||||
this._issuer = UInt160.from_json(issuer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -730,6 +741,14 @@ Amount.prototype.to_number = function() {
|
|||||||
return Number(this.to_text());
|
return Number(this.to_text());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// this one is needed because Value.abs creates new BigNumber,
|
||||||
|
// and BigNumber constructor is very slow, so we want to
|
||||||
|
// call it only if absolutely necessary
|
||||||
|
function absValue(value: Value): Value {
|
||||||
|
return value.isNegative() ? value.abs() : value;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert only value to JSON wire format.
|
// Convert only value to JSON wire format.
|
||||||
Amount.prototype.to_text = function() {
|
Amount.prototype.to_text = function() {
|
||||||
if (!this.is_valid()) {
|
if (!this.is_valid()) {
|
||||||
@@ -743,8 +762,8 @@ Amount.prototype.to_text = function() {
|
|||||||
// not native
|
// not native
|
||||||
const offset = this._value.getExponent() - 15;
|
const offset = this._value.getExponent() - 15;
|
||||||
const sign = this._value.isNegative() ? '-' : '';
|
const sign = this._value.isNegative() ? '-' : '';
|
||||||
const mantissa = utils.getMantissa16FromString(
|
const mantissa =
|
||||||
this._value.abs().toString());
|
utils.getMantissa16FromString(absValue(this._value).toString());
|
||||||
if (offset !== 0 && (offset < -25 || offset > -4)) {
|
if (offset !== 0 && (offset < -25 || offset > -4)) {
|
||||||
// Use e notation.
|
// Use e notation.
|
||||||
// XXX Clamp output.
|
// XXX Clamp output.
|
||||||
@@ -912,7 +931,7 @@ Amount.prototype.to_human_full = function(options) {
|
|||||||
const opts = options || {};
|
const opts = options || {};
|
||||||
const value = this.to_human(opts);
|
const value = this.to_human(opts);
|
||||||
const currency = this._currency.to_human();
|
const currency = this._currency.to_human();
|
||||||
const issuer = this._issuer.to_json(opts);
|
const issuer = this._issuer;
|
||||||
const base = value + '/' + currency;
|
const base = value + '/' + currency;
|
||||||
return this.is_native() ? base : (base + '/' + issuer);
|
return this.is_native() ? base : (base + '/' + issuer);
|
||||||
};
|
};
|
||||||
@@ -928,21 +947,21 @@ Amount.prototype.to_json = function() {
|
|||||||
this._currency.to_hex() : this._currency.to_json()
|
this._currency.to_hex() : this._currency.to_json()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this._issuer.is_valid()) {
|
if (isValidAddress(this._issuer)) {
|
||||||
amount_json.issuer = this._issuer.to_json();
|
amount_json.issuer = this._issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return amount_json;
|
return amount_json;
|
||||||
};
|
};
|
||||||
|
|
||||||
Amount.prototype.to_text_full = function(opts) {
|
Amount.prototype.to_text_full = function() {
|
||||||
if (!this.is_valid()) {
|
if (!this.is_valid()) {
|
||||||
return 'NaN';
|
return 'NaN';
|
||||||
}
|
}
|
||||||
return this._is_native
|
return this._is_native
|
||||||
? this.to_human() + '/XRP'
|
? this.to_human() + '/XRP'
|
||||||
: this.to_text() + '/' + this._currency.to_json()
|
: this.to_text() + '/' + this._currency.to_json()
|
||||||
+ '/' + this._issuer.to_json(opts);
|
+ '/' + this._issuer;
|
||||||
};
|
};
|
||||||
|
|
||||||
// For debugging.
|
// For debugging.
|
||||||
@@ -971,20 +990,11 @@ Amount.prototype.not_equals_why = function(d, ignore_issuer) {
|
|||||||
if (!this._currency.equals(d._currency)) {
|
if (!this._currency.equals(d._currency)) {
|
||||||
return 'Non-XRP currency differs.';
|
return 'Non-XRP currency differs.';
|
||||||
}
|
}
|
||||||
if (!ignore_issuer && !this._issuer.equals(d._issuer)) {
|
if (!ignore_issuer && this._issuer !== d._issuer) {
|
||||||
return 'Non-XRP issuer differs: '
|
return 'Non-XRP issuer differs: ' + d._issuer + '/' + this._issuer;
|
||||||
+ d._issuer.to_json()
|
|
||||||
+ '/'
|
|
||||||
+ this._issuer.to_json();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Amount = Amount;
|
exports.Amount = Amount;
|
||||||
|
|
||||||
// DEPRECATED: Include the corresponding files instead.
|
|
||||||
exports.Currency = Currency;
|
|
||||||
exports.Seed = Seed;
|
|
||||||
exports.UInt160 = UInt160;
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
// vim:sw=2:sts=2:ts=8:et
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const UInt160 = require('./uint160').UInt160;
|
|
||||||
const Amount = require('./amount').Amount;
|
const Amount = require('./amount').Amount;
|
||||||
|
const UInt160 = require('./uint160').UInt160;
|
||||||
const Utils = require('./orderbookutils');
|
const Utils = require('./orderbookutils');
|
||||||
|
|
||||||
function assertValidNumber(number, message) {
|
function assertValidNumber(number, message) {
|
||||||
@@ -18,32 +18,70 @@ function assertValidLegOneOffer(legOneOffer, message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AutobridgeCalculator(currencyGets, currencyPays,
|
function AutobridgeCalculator(currencyGets, currencyPays,
|
||||||
legOneOffers, legTwoOffers, issuerGets, issuerPays) {
|
legOneOffers, legTwoOffers, issuerGets, issuerPays
|
||||||
|
) {
|
||||||
this._currencyGets = currencyGets;
|
this._currencyGets = currencyGets;
|
||||||
this._currencyPays = currencyPays;
|
this._currencyPays = currencyPays;
|
||||||
|
this._currencyGetsHex = currencyGets.to_hex();
|
||||||
|
this._currencyPaysHex = currencyPays.to_hex();
|
||||||
this._issuerGets = issuerGets;
|
this._issuerGets = issuerGets;
|
||||||
|
this._issuerGetsObj = UInt160.from_json(issuerGets);
|
||||||
this._issuerPays = issuerPays;
|
this._issuerPays = issuerPays;
|
||||||
|
this._issuerPaysObj = UInt160.from_json(issuerPays);
|
||||||
this.legOneOffers = _.cloneDeep(legOneOffers);
|
this.legOneOffers = _.cloneDeep(legOneOffers);
|
||||||
this.legTwoOffers = _.cloneDeep(legTwoOffers);
|
this.legTwoOffers = _.cloneDeep(legTwoOffers);
|
||||||
|
|
||||||
this._ownerFundsLeftover = {};
|
this._ownerFundsLeftover = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NULL_AMOUNT = Utils.normalizeAmount('0');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates an ordered array of autobridged offers by quality
|
* Calculates an ordered array of autobridged offers by quality
|
||||||
*
|
*
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AutobridgeCalculator.prototype.calculate = function() {
|
AutobridgeCalculator.prototype.calculate = function(callback) {
|
||||||
let legOnePointer = 0;
|
|
||||||
let legTwoPointer = 0;
|
|
||||||
|
|
||||||
let offersAutobridged = [];
|
const legOnePointer = 0;
|
||||||
|
const legTwoPointer = 0;
|
||||||
|
|
||||||
|
const offersAutobridged = [];
|
||||||
|
|
||||||
this.clearOwnerFundsLeftover();
|
this.clearOwnerFundsLeftover();
|
||||||
|
|
||||||
|
this._calculateInternal(legOnePointer, legTwoPointer, offersAutobridged,
|
||||||
|
callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
AutobridgeCalculator.prototype._calculateInternal = function(
|
||||||
|
legOnePointer_, legTwoPointer_, offersAutobridged, callback
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Amount class is calling _check_limits after each operation in strict mode,
|
||||||
|
// and _check_limits is very computationally expensive, so we turning it off
|
||||||
|
// whle doing calculations
|
||||||
|
this._oldMode = Amount.strict_mode;
|
||||||
|
Amount.strict_mode = false;
|
||||||
|
|
||||||
|
let legOnePointer = legOnePointer_;
|
||||||
|
let legTwoPointer = legTwoPointer_;
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
while (this.legOneOffers[legOnePointer] && this.legTwoOffers[legTwoPointer]) {
|
while (this.legOneOffers[legOnePointer] && this.legTwoOffers[legTwoPointer]) {
|
||||||
|
// manually implement cooperative multitasking that yields after 30ms
|
||||||
|
// of execution so user's browser stays responsive
|
||||||
|
const lasted = (Date.now() - startTime);
|
||||||
|
if (lasted > 30) {
|
||||||
|
setTimeout(this._calculateInternal.bind(this, legOnePointer,
|
||||||
|
legTwoPointer, offersAutobridged, callback), 0);
|
||||||
|
|
||||||
|
Amount.strict_mode = this._oldMode;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const legOneOffer = this.legOneOffers[legOnePointer];
|
const legOneOffer = this.legOneOffers[legOnePointer];
|
||||||
const legTwoOffer = this.legTwoOffers[legTwoPointer];
|
const legTwoOffer = this.legTwoOffers[legTwoPointer];
|
||||||
const leftoverFunds = this.getLeftoverOwnerFunds(legOneOffer.Account);
|
const leftoverFunds = this.getLeftoverOwnerFunds(legOneOffer.Account);
|
||||||
@@ -55,8 +93,10 @@ AutobridgeCalculator.prototype.calculate = function() {
|
|||||||
this.adjustLegOneFundedAmount(legOneOffer);
|
this.adjustLegOneFundedAmount(legOneOffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer,
|
||||||
const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer);
|
this._currencyPays, this._issuerPaysObj);
|
||||||
|
const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer,
|
||||||
|
this._currencyGets, this._issuerGetsObj);
|
||||||
|
|
||||||
if (legOneTakerGetsFunded.is_zero()) {
|
if (legOneTakerGetsFunded.is_zero()) {
|
||||||
legOnePointer++;
|
legOnePointer++;
|
||||||
@@ -70,14 +110,17 @@ AutobridgeCalculator.prototype.calculate = function() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (legOneTakerGetsFunded.compareTo(legTwoTakerPaysFunded) > 0) {
|
// using private fields for speed
|
||||||
|
if (legOneTakerGetsFunded._value.comparedTo(
|
||||||
|
legTwoTakerPaysFunded._value) > 0) {
|
||||||
autobridgedOffer = this.getAutobridgedOfferWithClampedLegOne(
|
autobridgedOffer = this.getAutobridgedOfferWithClampedLegOne(
|
||||||
legOneOffer,
|
legOneOffer,
|
||||||
legTwoOffer
|
legTwoOffer
|
||||||
);
|
);
|
||||||
|
|
||||||
legTwoPointer++;
|
legTwoPointer++;
|
||||||
} else if (legTwoTakerPaysFunded.compareTo(legOneTakerGetsFunded) > 0) {
|
} else if (legTwoTakerPaysFunded._value.comparedTo(
|
||||||
|
legOneTakerGetsFunded._value) > 0) {
|
||||||
autobridgedOffer = this.getAutobridgedOfferWithClampedLegTwo(
|
autobridgedOffer = this.getAutobridgedOfferWithClampedLegTwo(
|
||||||
legOneOffer,
|
legOneOffer,
|
||||||
legTwoOffer
|
legTwoOffer
|
||||||
@@ -97,7 +140,8 @@ AutobridgeCalculator.prototype.calculate = function() {
|
|||||||
offersAutobridged.push(autobridgedOffer);
|
offersAutobridged.push(autobridgedOffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return offersAutobridged;
|
Amount.strict_mode = this._oldMode;
|
||||||
|
callback(offersAutobridged);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,15 +156,20 @@ AutobridgeCalculator.prototype.calculate = function() {
|
|||||||
|
|
||||||
AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegOne =
|
AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegOne =
|
||||||
function(legOneOffer, legTwoOffer) {
|
function(legOneOffer, legTwoOffer) {
|
||||||
const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer,
|
||||||
const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer);
|
this._currencyPays, this._issuerPaysObj);
|
||||||
const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets);
|
const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer,
|
||||||
|
this._currencyGets, this._issuerGetsObj);
|
||||||
|
const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
|
|
||||||
const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer);
|
const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer,
|
||||||
|
this._currencyGets, this._issuerGetsObj);
|
||||||
const autobridgedTakerPays = legTwoTakerPaysFunded.multiply(legOneQuality);
|
const autobridgedTakerPays = legTwoTakerPaysFunded.multiply(legOneQuality);
|
||||||
|
|
||||||
if (legOneOffer.Account === legTwoOffer.Account) {
|
if (legOneOffer.Account === legTwoOffer.Account) {
|
||||||
const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer);
|
const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
const updatedTakerGets = legOneTakerGets.subtract(legTwoTakerPaysFunded);
|
const updatedTakerGets = legOneTakerGets.subtract(legTwoTakerPaysFunded);
|
||||||
|
|
||||||
this.setLegOneTakerGets(legOneOffer, updatedTakerGets);
|
this.setLegOneTakerGets(legOneOffer, updatedTakerGets);
|
||||||
@@ -152,15 +201,20 @@ function(legOneOffer, legTwoOffer) {
|
|||||||
|
|
||||||
AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegTwo =
|
AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegTwo =
|
||||||
function(legOneOffer, legTwoOffer) {
|
function(legOneOffer, legTwoOffer) {
|
||||||
const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer,
|
||||||
const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer);
|
this._currencyPays, this._issuerPaysObj);
|
||||||
const legTwoQuality = Utils.getOfferQuality(legTwoOffer, this._currencyGets);
|
const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer,
|
||||||
|
this._currencyGets, this._issuerGetsObj);
|
||||||
|
const legTwoQuality = Utils.getOfferQuality(legTwoOffer, this._currencyGets,
|
||||||
|
this._currencyGets, this._issuerGetsObj);
|
||||||
|
|
||||||
const autobridgedTakerGets = legOneTakerGetsFunded.divide(legTwoQuality);
|
const autobridgedTakerGets = legOneTakerGetsFunded.divide(legTwoQuality);
|
||||||
const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer);
|
const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
|
|
||||||
// Update funded amount since leg two offer was not completely consumed
|
// Update funded amount since leg two offer was not completely consumed
|
||||||
legTwoOffer.taker_gets_funded = Utils.getOfferTakerGetsFunded(legTwoOffer)
|
legTwoOffer.taker_gets_funded = Utils.getOfferTakerGetsFunded(legTwoOffer,
|
||||||
|
this._currencyGets, this._issuerGetsObj)
|
||||||
.subtract(autobridgedTakerGets)
|
.subtract(autobridgedTakerGets)
|
||||||
.to_text();
|
.to_text();
|
||||||
legTwoOffer.taker_pays_funded = legTwoTakerPaysFunded
|
legTwoOffer.taker_pays_funded = legTwoTakerPaysFunded
|
||||||
@@ -184,8 +238,10 @@ function(legOneOffer, legTwoOffer) {
|
|||||||
|
|
||||||
AutobridgeCalculator.prototype.getAutobridgedOfferWithoutClamps =
|
AutobridgeCalculator.prototype.getAutobridgedOfferWithoutClamps =
|
||||||
function(legOneOffer, legTwoOffer) {
|
function(legOneOffer, legTwoOffer) {
|
||||||
const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer);
|
const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer,
|
||||||
const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer);
|
this._currencyGets, this._issuerGetsObj);
|
||||||
|
const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
|
|
||||||
return this.formatAutobridgedOffer(
|
return this.formatAutobridgedOffer(
|
||||||
autobridgedTakerGets,
|
autobridgedTakerGets,
|
||||||
@@ -210,9 +266,7 @@ AutobridgeCalculator.prototype.clearOwnerFundsLeftover = function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
AutobridgeCalculator.prototype.resetOwnerFundsLeftover = function(account) {
|
AutobridgeCalculator.prototype.resetOwnerFundsLeftover = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
this._ownerFundsLeftover[account] = NULL_AMOUNT.clone();
|
||||||
|
|
||||||
this._ownerFundsLeftover[account] = Utils.normalizeAmount('0');
|
|
||||||
|
|
||||||
return this._ownerFundsLeftover[account];
|
return this._ownerFundsLeftover[account];
|
||||||
};
|
};
|
||||||
@@ -226,12 +280,10 @@ AutobridgeCalculator.prototype.resetOwnerFundsLeftover = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
AutobridgeCalculator.prototype.getLeftoverOwnerFunds = function(account) {
|
AutobridgeCalculator.prototype.getLeftoverOwnerFunds = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
|
|
||||||
let amount = this._ownerFundsLeftover[account];
|
let amount = this._ownerFundsLeftover[account];
|
||||||
|
|
||||||
if (!amount) {
|
if (!amount) {
|
||||||
amount = Utils.normalizeAmount('0');
|
amount = NULL_AMOUNT.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
return amount;
|
return amount;
|
||||||
@@ -248,7 +300,6 @@ AutobridgeCalculator.prototype.getLeftoverOwnerFunds = function(account) {
|
|||||||
|
|
||||||
AutobridgeCalculator.prototype.addLeftoverOwnerFunds =
|
AutobridgeCalculator.prototype.addLeftoverOwnerFunds =
|
||||||
function(account, amount) {
|
function(account, amount) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
assert(amount instanceof Amount, 'Amount is invalid');
|
assert(amount instanceof Amount, 'Amount is invalid');
|
||||||
|
|
||||||
this._ownerFundsLeftover[account] = this.getLeftoverOwnerFunds(account)
|
this._ownerFundsLeftover[account] = this.getLeftoverOwnerFunds(account)
|
||||||
@@ -266,7 +317,6 @@ function(account, amount) {
|
|||||||
|
|
||||||
AutobridgeCalculator.prototype.setLeftoverOwnerFunds =
|
AutobridgeCalculator.prototype.setLeftoverOwnerFunds =
|
||||||
function(account, amount) {
|
function(account, amount) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
assert(amount instanceof Amount, 'Amount is invalid');
|
assert(amount instanceof Amount, 'Amount is invalid');
|
||||||
|
|
||||||
this._ownerFundsLeftover[account] = amount;
|
this._ownerFundsLeftover[account] = amount;
|
||||||
@@ -291,13 +341,13 @@ function(takerGets, takerPays) {
|
|||||||
|
|
||||||
autobridgedOffer.TakerGets = {
|
autobridgedOffer.TakerGets = {
|
||||||
value: takerGets.to_text(),
|
value: takerGets.to_text(),
|
||||||
currency: this._currencyGets.to_hex(),
|
currency: this._currencyGetsHex,
|
||||||
issuer: this._issuerGets
|
issuer: this._issuerGets
|
||||||
};
|
};
|
||||||
|
|
||||||
autobridgedOffer.TakerPays = {
|
autobridgedOffer.TakerPays = {
|
||||||
value: takerPays.to_text(),
|
value: takerPays.to_text(),
|
||||||
currency: this._currencyPays.to_hex(),
|
currency: this._currencyPaysHex,
|
||||||
issuer: this._issuerPays
|
issuer: this._issuerPays
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -308,7 +358,9 @@ function(takerGets, takerPays) {
|
|||||||
|
|
||||||
autobridgedOffer.autobridged = true;
|
autobridgedOffer.autobridged = true;
|
||||||
|
|
||||||
autobridgedOffer.BookDirectory = Utils.convertOfferQualityToHex(quality);
|
autobridgedOffer.BookDirectory =
|
||||||
|
Utils.convertOfferQualityToHexFromText(autobridgedOffer.quality);
|
||||||
|
autobridgedOffer.qualityHex = autobridgedOffer.BookDirectory;
|
||||||
|
|
||||||
return autobridgedOffer;
|
return autobridgedOffer;
|
||||||
};
|
};
|
||||||
@@ -325,11 +377,13 @@ function(takerGets, takerPays) {
|
|||||||
AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) {
|
AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) {
|
||||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||||
|
|
||||||
legOneOffer.initTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
legOneOffer.initTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
|
|
||||||
this.setLegOneTakerGetsFunded(
|
this.setLegOneTakerGetsFunded(
|
||||||
legOneOffer,
|
legOneOffer,
|
||||||
Utils.getOfferTakerGets(legOneOffer)
|
Utils.getOfferTakerGets(legOneOffer, this._currencyPays,
|
||||||
|
this._issuerPaysObj)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -350,7 +404,8 @@ AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) {
|
|||||||
AutobridgeCalculator.prototype.clampLegOneOwnerFunds = function(legOneOffer) {
|
AutobridgeCalculator.prototype.clampLegOneOwnerFunds = function(legOneOffer) {
|
||||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||||
|
|
||||||
const takerGets = Utils.getOfferTakerGets(legOneOffer);
|
const takerGets = Utils.getOfferTakerGets(legOneOffer, this._currencyPays,
|
||||||
|
this._issuerPaysObj);
|
||||||
|
|
||||||
if (takerGets.compareTo(legOneOffer.initTakerGetsFunded) > 0) {
|
if (takerGets.compareTo(legOneOffer.initTakerGetsFunded) > 0) {
|
||||||
// After clamping, TakerGets is still greater than initial funded amount
|
// After clamping, TakerGets is still greater than initial funded amount
|
||||||
@@ -375,12 +430,16 @@ function(legOneOffer) {
|
|||||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||||
assert(!legOneOffer.is_fully_funded, 'Leg one offer cannot be fully funded');
|
assert(!legOneOffer.is_fully_funded, 'Leg one offer cannot be fully funded');
|
||||||
|
|
||||||
const fundedSum = Utils.getOfferTakerGetsFunded(legOneOffer)
|
const fundedSum = Utils.getOfferTakerGetsFunded(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj)
|
||||||
.add(this.getLeftoverOwnerFunds(legOneOffer.Account));
|
.add(this.getLeftoverOwnerFunds(legOneOffer.Account));
|
||||||
|
|
||||||
if (fundedSum.compareTo(Utils.getOfferTakerGets(legOneOffer)) >= 0) {
|
if (fundedSum.compareTo(Utils.getOfferTakerGets(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj)) >= 0
|
||||||
|
) {
|
||||||
// There are enough extra funds to fully fund the offer
|
// There are enough extra funds to fully fund the offer
|
||||||
const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer);
|
const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
const updatedLeftover = fundedSum.subtract(legOneTakerGets);
|
const updatedLeftover = fundedSum.subtract(legOneTakerGets);
|
||||||
|
|
||||||
this.setLegOneTakerGetsFunded(legOneOffer, legOneTakerGets);
|
this.setLegOneTakerGetsFunded(legOneOffer, legOneTakerGets);
|
||||||
@@ -407,8 +466,9 @@ function setLegOneTakerGetsFunded(legOneOffer, takerGetsFunded) {
|
|||||||
|
|
||||||
legOneOffer.taker_gets_funded = takerGetsFunded.to_text();
|
legOneOffer.taker_gets_funded = takerGetsFunded.to_text();
|
||||||
legOneOffer.taker_pays_funded = takerGetsFunded
|
legOneOffer.taker_pays_funded = takerGetsFunded
|
||||||
.multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets))
|
.multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets,
|
||||||
.to_text();
|
this._currencyPays, this._issuerPaysObj))
|
||||||
|
.to_text();
|
||||||
|
|
||||||
if (legOneOffer.taker_gets_funded === legOneOffer.TakerGets.value) {
|
if (legOneOffer.taker_gets_funded === legOneOffer.TakerGets.value) {
|
||||||
legOneOffer.is_fully_funded = true;
|
legOneOffer.is_fully_funded = true;
|
||||||
@@ -428,10 +488,11 @@ function(legOneOffer, takerGets) {
|
|||||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||||
assert(takerGets instanceof Amount, 'Taker gets funded is invalid');
|
assert(takerGets instanceof Amount, 'Taker gets funded is invalid');
|
||||||
|
|
||||||
const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets);
|
const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets,
|
||||||
|
this._currencyPays, this._issuerPaysObj);
|
||||||
|
|
||||||
legOneOffer.TakerGets = takerGets.to_text();
|
legOneOffer.TakerGets = takerGets.to_text();
|
||||||
legOneOffer.TakerPays = takerGets.multiply(legOneQuality);
|
legOneOffer.TakerPays = takerGets.multiply(legOneQuality).to_json();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = AutobridgeCalculator;
|
module.exports = AutobridgeCalculator;
|
||||||
|
|||||||
127
src/core/base.js
127
src/core/base.js
@@ -1,18 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const _ = require('lodash');
|
|
||||||
const sjcl = require('./utils').sjcl;
|
const BN = require('bn.js');
|
||||||
const utils = require('./utils');
|
|
||||||
const extend = require('extend');
|
const extend = require('extend');
|
||||||
const convertBase = require('./baseconverter');
|
const {encode, decode} = require('ripple-address-codec');
|
||||||
|
|
||||||
const Base = {};
|
const Base = {};
|
||||||
|
|
||||||
const alphabets = Base.alphabets = {
|
|
||||||
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
|
|
||||||
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
|
|
||||||
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|
||||||
};
|
|
||||||
|
|
||||||
extend(Base, {
|
extend(Base, {
|
||||||
VER_NONE: 1,
|
VER_NONE: 1,
|
||||||
VER_NODE_PUBLIC: 28,
|
VER_NODE_PUBLIC: 28,
|
||||||
@@ -21,134 +14,44 @@ extend(Base, {
|
|||||||
VER_ACCOUNT_PUBLIC: 35,
|
VER_ACCOUNT_PUBLIC: 35,
|
||||||
VER_ACCOUNT_PRIVATE: 34,
|
VER_ACCOUNT_PRIVATE: 34,
|
||||||
VER_FAMILY_GENERATOR: 41,
|
VER_FAMILY_GENERATOR: 41,
|
||||||
VER_FAMILY_SEED: 33
|
VER_FAMILY_SEED: 33,
|
||||||
});
|
VER_ED25519_SEED: [0x01, 0xE1, 0x4B]
|
||||||
|
|
||||||
function sha256(bytes) {
|
|
||||||
return sjcl.codec.bytes.fromBits(
|
|
||||||
sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function encodeString(alphabet, input) {
|
|
||||||
if (input.length === 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const leadingZeros = _.takeWhile(input, function(d) {
|
|
||||||
return d === 0;
|
|
||||||
});
|
|
||||||
const out = convertBase(input, 256, 58).map(function(digit) {
|
|
||||||
if (digit < 0 || digit >= alphabet.length) {
|
|
||||||
throw new Error('Value ' + digit + ' is out of bounds for encoding');
|
|
||||||
}
|
|
||||||
return alphabet[digit];
|
|
||||||
});
|
|
||||||
const prefix = leadingZeros.map(function() {
|
|
||||||
return alphabet[0];
|
|
||||||
});
|
|
||||||
return prefix.concat(out).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function decodeString(indexes, input) {
|
|
||||||
if (input.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const input58 = input.split('').map(function(c) {
|
|
||||||
const charCode = c.charCodeAt(0);
|
|
||||||
if (charCode >= indexes.length || indexes[charCode] === -1) {
|
|
||||||
throw new Error('Character ' + c + ' is not valid for encoding');
|
|
||||||
}
|
|
||||||
return indexes[charCode];
|
|
||||||
});
|
|
||||||
const leadingZeros = _.takeWhile(input58, function(d) {
|
|
||||||
return d === 0;
|
|
||||||
});
|
|
||||||
const out = convertBase(input58, 58, 256);
|
|
||||||
return leadingZeros.concat(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Base58(alphabet) {
|
|
||||||
const indexes = utils.arraySet(128, -1);
|
|
||||||
for (let i = 0; i < alphabet.length; i++) {
|
|
||||||
indexes[alphabet.charCodeAt(i)] = i;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
decode: decodeString.bind(null, indexes),
|
|
||||||
encode: encodeString.bind(null, alphabet)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Base.encoders = {};
|
|
||||||
Object.keys(alphabets).forEach(function(alphabet) {
|
|
||||||
Base.encoders[alphabet] = new Base58(alphabets[alphabet]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// --> input: big-endian array of bytes.
|
// --> input: big-endian array of bytes.
|
||||||
// <-- string at least as long as input.
|
// <-- string at least as long as input.
|
||||||
Base.encode = function(input, alpha) {
|
Base.encode = function(input, alphabet) {
|
||||||
return this.encoders[alpha || 'ripple'].encode(input);
|
return encode(input, {alphabet});
|
||||||
};
|
};
|
||||||
|
|
||||||
// --> input: String
|
// --> input: String
|
||||||
// <-- array of bytes or undefined.
|
// <-- array of bytes or undefined.
|
||||||
Base.decode = function(input, alpha) {
|
Base.decode = function(input, alphabet) {
|
||||||
if (typeof input !== 'string') {
|
if (typeof input !== 'string') {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return this.encoders[alpha || 'ripple'].decode(input);
|
return decode(input, {alphabet});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Base.verify_checksum = function(bytes) {
|
|
||||||
const computed = sha256(sha256(bytes.slice(0, -4))).slice(0, 4);
|
|
||||||
const checksum = bytes.slice(-4);
|
|
||||||
return _.isEqual(computed, checksum);
|
|
||||||
};
|
|
||||||
|
|
||||||
// --> input: Array
|
// --> input: Array
|
||||||
// <-- String
|
// <-- String
|
||||||
Base.encode_check = function(version, input, alphabet) {
|
Base.encode_check = function(version, input, alphabet) {
|
||||||
const buffer = [].concat(version, input);
|
return encode(input, {version, alphabet});
|
||||||
const check = sha256(sha256(buffer)).slice(0, 4);
|
|
||||||
|
|
||||||
return Base.encode([].concat(buffer, check), alphabet);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --> input : String
|
// --> input : String
|
||||||
// <-- NaN || sjcl.bn
|
// <-- NaN || BN
|
||||||
Base.decode_check = function(version, input, alphabet) {
|
Base.decode_check = function(version, input, alphabet) {
|
||||||
const buffer = Base.decode(input, alphabet);
|
try {
|
||||||
|
const decoded = decode(input, {version, alphabet});
|
||||||
if (!buffer || buffer.length < 5) {
|
return new BN(decoded);
|
||||||
|
} catch (e) {
|
||||||
return NaN;
|
return NaN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single valid version
|
|
||||||
if (typeof version === 'number' && buffer[0] !== version) {
|
|
||||||
return NaN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiple allowed versions
|
|
||||||
if (Array.isArray(version) && _.every(version, function(v) {
|
|
||||||
return v !== buffer[0];
|
|
||||||
})) {
|
|
||||||
return NaN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Base.verify_checksum(buffer)) {
|
|
||||||
return NaN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll use the version byte to add a leading zero, this ensures JSBN doesn't
|
|
||||||
// intrepret the value as a negative number
|
|
||||||
buffer[0] = 0;
|
|
||||||
|
|
||||||
return sjcl.bn.fromBits(
|
|
||||||
sjcl.codec.bytes.toBits(buffer.slice(0, -4)));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Base = Base;
|
exports.Base = Base;
|
||||||
|
|||||||
@@ -1,28 +1,41 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
function normalize(digitArray) {
|
function normalize(digitArray) {
|
||||||
while (digitArray[0] === 0) {
|
let i = 0;
|
||||||
digitArray.shift();
|
while (digitArray[i] === 0) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
digitArray.splice(0, i);
|
||||||
}
|
}
|
||||||
return digitArray;
|
return digitArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
function divmod(digitArray, base, divisor) {
|
function divmod(digitArray, base, divisor) {
|
||||||
var remainder = 0;
|
let remainder = 0;
|
||||||
var quotient = [];
|
let temp;
|
||||||
for (var j = 0; j < digitArray.length; j++) {
|
let divided;
|
||||||
var temp = remainder * base + parseInt(digitArray[j], 10);
|
let j = -1;
|
||||||
quotient.push(Math.floor(temp / divisor));
|
|
||||||
|
const length = digitArray.length;
|
||||||
|
const quotient = new Array(length);
|
||||||
|
|
||||||
|
while (++j < length) {
|
||||||
|
temp = remainder * base + digitArray[j];
|
||||||
|
divided = temp / divisor;
|
||||||
|
quotient[j] = divided << 0;
|
||||||
remainder = temp % divisor;
|
remainder = temp % divisor;
|
||||||
}
|
}
|
||||||
return {quotient: normalize(quotient), remainder: remainder};
|
return {quotient: normalize(quotient), remainder: remainder};
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertBase(digitArray, fromBase, toBase) {
|
function convertBase(digitArray, fromBase, toBase) {
|
||||||
var result = [];
|
const result = [];
|
||||||
var dividend = digitArray;
|
let dividend = digitArray;
|
||||||
|
let qr;
|
||||||
while (dividend.length > 0) {
|
while (dividend.length > 0) {
|
||||||
var qr = divmod(dividend, fromBase, toBase);
|
qr = divmod(dividend, fromBase, toBase);
|
||||||
result.unshift(qr.remainder);
|
result.unshift(qr.remainder);
|
||||||
dividend = qr.quotient;
|
dividend = qr.quotient;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/*eslint no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/
|
/*eslint-disable max-len,spaced-comment,array-bracket-spacing,key-spacing*/
|
||||||
|
/*eslint-disable no-multi-spaces,comma-spacing*/
|
||||||
|
/*eslint-disable no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data type map.
|
* Data type map.
|
||||||
@@ -52,7 +54,8 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
// Common types
|
// Common types
|
||||||
1: { // Int16
|
1: { // Int16
|
||||||
1: 'LedgerEntryType',
|
1: 'LedgerEntryType',
|
||||||
2: 'TransactionType'
|
2: 'TransactionType',
|
||||||
|
3: 'SignerWeight'
|
||||||
},
|
},
|
||||||
2: { // Int32
|
2: { // Int32
|
||||||
2: 'Flags',
|
2: 'Flags',
|
||||||
@@ -87,7 +90,11 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
31: 'ReserveBase',
|
31: 'ReserveBase',
|
||||||
32: 'ReserveIncrement',
|
32: 'ReserveIncrement',
|
||||||
33: 'SetFlag',
|
33: 'SetFlag',
|
||||||
34: 'ClearFlag'
|
34: 'ClearFlag',
|
||||||
|
35: 'SignerQuorum',
|
||||||
|
36: 'CancelAfter',
|
||||||
|
37: 'FinishAfter',
|
||||||
|
38: 'SignerListID'
|
||||||
},
|
},
|
||||||
3: { // Int64
|
3: { // Int64
|
||||||
1: 'IndexNext',
|
1: 'IndexNext',
|
||||||
@@ -116,7 +123,8 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
17: 'InvoiceID',
|
17: 'InvoiceID',
|
||||||
18: 'Nickname',
|
18: 'Nickname',
|
||||||
19: 'Amendment',
|
19: 'Amendment',
|
||||||
20: 'TicketID'
|
20: 'TicketID',
|
||||||
|
21: 'Digest'
|
||||||
},
|
},
|
||||||
6: { // Amount
|
6: { // Amount
|
||||||
1: 'Amount',
|
1: 'Amount',
|
||||||
@@ -146,7 +154,8 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
11: 'CreateCode',
|
11: 'CreateCode',
|
||||||
12: 'MemoType',
|
12: 'MemoType',
|
||||||
13: 'MemoData',
|
13: 'MemoData',
|
||||||
14: 'MemoFormat'
|
14: 'MemoFormat',
|
||||||
|
17: 'Proof'
|
||||||
},
|
},
|
||||||
8: { // Account
|
8: { // Account
|
||||||
1: 'Account',
|
1: 'Account',
|
||||||
@@ -166,13 +175,15 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
7: 'FinalFields',
|
7: 'FinalFields',
|
||||||
8: 'NewFields',
|
8: 'NewFields',
|
||||||
9: 'TemplateEntry',
|
9: 'TemplateEntry',
|
||||||
10: 'Memo'
|
10: 'Memo',
|
||||||
|
11: 'SignerEntry',
|
||||||
|
16: 'Signer'
|
||||||
},
|
},
|
||||||
15: { // Array
|
15: { // Array
|
||||||
1: undefined, // end of Array
|
1: undefined, // end of Array
|
||||||
2: 'SigningAccounts',
|
2: 'SigningAccounts',
|
||||||
3: 'TxnSignatures',
|
3: 'Signers',
|
||||||
4: 'Signatures',
|
4: 'SignerEntries',
|
||||||
5: 'Template',
|
5: 'Template',
|
||||||
6: 'Necessary',
|
6: 'Necessary',
|
||||||
7: 'Sufficient',
|
7: 'Sufficient',
|
||||||
@@ -183,7 +194,7 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
// Uncommon types
|
// Uncommon types
|
||||||
16: { // Int8
|
16: { // Int8
|
||||||
1: 'CloseResolution',
|
1: 'CloseResolution',
|
||||||
2: 'TemplateEntryType',
|
2: 'Method',
|
||||||
3: 'TransactionResult'
|
3: 'TransactionResult'
|
||||||
},
|
},
|
||||||
17: { // Hash160
|
17: { // Hash160
|
||||||
@@ -202,17 +213,17 @@ const FIELDS_MAP = exports.fields = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let INVERSE_FIELDS_MAP = exports.fieldsInverseMap = { };
|
const INVERSE_FIELDS_MAP = exports.fieldsInverseMap = { };
|
||||||
|
|
||||||
Object.keys(FIELDS_MAP).forEach(function(k1) {
|
Object.keys(FIELDS_MAP).forEach(function(k1) {
|
||||||
Object.keys(FIELDS_MAP[k1]).forEach(function(k2) {
|
Object.keys(FIELDS_MAP[k1]).forEach(function(k2) {
|
||||||
INVERSE_FIELDS_MAP[FIELDS_MAP[k1][k2]] = [ Number(k1), Number(k2) ];
|
INVERSE_FIELDS_MAP[FIELDS_MAP[k1][k2]] = [Number(k1), Number(k2)];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const REQUIRED = exports.REQUIRED = 0,
|
const REQUIRED = exports.REQUIRED = 0;
|
||||||
OPTIONAL = exports.OPTIONAL = 1,
|
const OPTIONAL = exports.OPTIONAL = 1;
|
||||||
DEFAULT = exports.DEFAULT = 2;
|
const DEFAULT = exports.DEFAULT = 2;
|
||||||
|
|
||||||
const base = [
|
const base = [
|
||||||
[ 'TransactionType' , REQUIRED ],
|
[ 'TransactionType' , REQUIRED ],
|
||||||
@@ -226,76 +237,100 @@ const base = [
|
|||||||
[ 'SigningPubKey' , REQUIRED ],
|
[ 'SigningPubKey' , REQUIRED ],
|
||||||
[ 'TxnSignature' , OPTIONAL ],
|
[ 'TxnSignature' , OPTIONAL ],
|
||||||
[ 'AccountTxnID' , OPTIONAL ],
|
[ 'AccountTxnID' , OPTIONAL ],
|
||||||
[ 'Memos' , OPTIONAL ]
|
[ 'Memos' , OPTIONAL ],
|
||||||
|
[ 'Signers' , OPTIONAL ]
|
||||||
];
|
];
|
||||||
|
|
||||||
exports.tx = {
|
exports.tx = {
|
||||||
AccountSet: [3].concat(base, [
|
AccountSet: [3].concat(base, [
|
||||||
[ 'EmailHash' , OPTIONAL ],
|
['EmailHash' , OPTIONAL],
|
||||||
[ 'WalletLocator' , OPTIONAL ],
|
['WalletLocator' , OPTIONAL],
|
||||||
[ 'WalletSize' , OPTIONAL ],
|
['WalletSize' , OPTIONAL],
|
||||||
[ 'MessageKey' , OPTIONAL ],
|
['MessageKey' , OPTIONAL],
|
||||||
[ 'Domain' , OPTIONAL ],
|
['Domain' , OPTIONAL],
|
||||||
[ 'TransferRate' , OPTIONAL ],
|
['TransferRate' , OPTIONAL],
|
||||||
[ 'SetFlag' , OPTIONAL ],
|
['SetFlag' , OPTIONAL],
|
||||||
[ 'ClearFlag' , OPTIONAL ]
|
['ClearFlag' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
TrustSet: [20].concat(base, [
|
TrustSet: [20].concat(base, [
|
||||||
[ 'LimitAmount' , OPTIONAL ],
|
['LimitAmount' , OPTIONAL],
|
||||||
[ 'QualityIn' , OPTIONAL ],
|
['QualityIn' , OPTIONAL],
|
||||||
[ 'QualityOut' , OPTIONAL ]
|
['QualityOut' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
OfferCreate: [7].concat(base, [
|
OfferCreate: [7].concat(base, [
|
||||||
[ 'TakerPays' , REQUIRED ],
|
['TakerPays' , REQUIRED],
|
||||||
[ 'TakerGets' , REQUIRED ],
|
['TakerGets' , REQUIRED],
|
||||||
[ 'Expiration' , OPTIONAL ],
|
['Expiration' , OPTIONAL],
|
||||||
[ 'OfferSequence' , OPTIONAL ]
|
['OfferSequence' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
OfferCancel: [8].concat(base, [
|
OfferCancel: [8].concat(base, [
|
||||||
[ 'OfferSequence' , REQUIRED ]
|
['OfferSequence' , REQUIRED]
|
||||||
]),
|
]),
|
||||||
SetRegularKey: [5].concat(base, [
|
SetRegularKey: [5].concat(base, [
|
||||||
[ 'RegularKey' , OPTIONAL ]
|
['RegularKey' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
Payment: [0].concat(base, [
|
Payment: [0].concat(base, [
|
||||||
[ 'Destination' , REQUIRED ],
|
['Destination' , REQUIRED],
|
||||||
[ 'Amount' , REQUIRED ],
|
['Amount' , REQUIRED],
|
||||||
[ 'SendMax' , OPTIONAL ],
|
['SendMax' , OPTIONAL],
|
||||||
[ 'Paths' , DEFAULT ],
|
['Paths' , DEFAULT],
|
||||||
[ 'InvoiceID' , OPTIONAL ],
|
['InvoiceID' , OPTIONAL],
|
||||||
[ 'DestinationTag' , OPTIONAL ]
|
['DestinationTag' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
Contract: [9].concat(base, [
|
Contract: [9].concat(base, [
|
||||||
[ 'Expiration' , REQUIRED ],
|
['Expiration' , REQUIRED],
|
||||||
[ 'BondAmount' , REQUIRED ],
|
['BondAmount' , REQUIRED],
|
||||||
[ 'StampEscrow' , REQUIRED ],
|
['StampEscrow' , REQUIRED],
|
||||||
[ 'RippleEscrow' , REQUIRED ],
|
['RippleEscrow' , REQUIRED],
|
||||||
[ 'CreateCode' , OPTIONAL ],
|
['CreateCode' , OPTIONAL],
|
||||||
[ 'FundCode' , OPTIONAL ],
|
['FundCode' , OPTIONAL],
|
||||||
[ 'RemoveCode' , OPTIONAL ],
|
['RemoveCode' , OPTIONAL],
|
||||||
[ 'ExpireCode' , OPTIONAL ]
|
['ExpireCode' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
RemoveContract: [10].concat(base, [
|
RemoveContract: [10].concat(base, [
|
||||||
[ 'Target' , REQUIRED ]
|
['Target' , REQUIRED]
|
||||||
]),
|
]),
|
||||||
EnableFeature: [100].concat(base, [
|
EnableFeature: [100].concat(base, [
|
||||||
[ 'Feature' , REQUIRED ]
|
['Feature' , REQUIRED]
|
||||||
]),
|
]),
|
||||||
EnableAmendment: [100].concat(base, [
|
EnableAmendment: [100].concat(base, [
|
||||||
[ 'Amendment' , REQUIRED ]
|
['Amendment' , REQUIRED]
|
||||||
]),
|
]),
|
||||||
SetFee: [101].concat(base, [
|
SetFee: [101].concat(base, [
|
||||||
[ 'BaseFee' , REQUIRED ],
|
['BaseFee' , REQUIRED],
|
||||||
[ 'ReferenceFeeUnits' , REQUIRED ],
|
['ReferenceFeeUnits' , REQUIRED],
|
||||||
[ 'ReserveBase' , REQUIRED ],
|
['ReserveBase' , REQUIRED],
|
||||||
[ 'ReserveIncrement' , REQUIRED ]
|
['ReserveIncrement' , REQUIRED]
|
||||||
]),
|
]),
|
||||||
TicketCreate: [10].concat(base, [
|
TicketCreate: [10].concat(base, [
|
||||||
[ 'Target' , OPTIONAL ],
|
['Target' , OPTIONAL],
|
||||||
[ 'Expiration' , OPTIONAL ]
|
['Expiration' , OPTIONAL]
|
||||||
]),
|
]),
|
||||||
TicketCancel: [11].concat(base, [
|
TicketCancel: [11].concat(base, [
|
||||||
[ 'TicketID' , REQUIRED ]
|
['TicketID' , REQUIRED]
|
||||||
|
]),
|
||||||
|
SignerListSet: [12].concat(base, [
|
||||||
|
['SignerQuorum', REQUIRED],
|
||||||
|
['SignerEntries', OPTIONAL]
|
||||||
|
]),
|
||||||
|
SuspendedPaymentCreate: [1].concat(base, [
|
||||||
|
['Destination' , REQUIRED],
|
||||||
|
['Amount' , REQUIRED],
|
||||||
|
['Digest' , OPTIONAL],
|
||||||
|
['CancelAfter' , OPTIONAL],
|
||||||
|
['FinishAfter' , OPTIONAL],
|
||||||
|
['DestinationTag' , OPTIONAL]
|
||||||
|
]),
|
||||||
|
SuspendedPaymentFinish: [2].concat(base, [
|
||||||
|
['Owner' , REQUIRED],
|
||||||
|
['OfferSequence' , REQUIRED],
|
||||||
|
['Method' , OPTIONAL],
|
||||||
|
['Digest' , OPTIONAL],
|
||||||
|
['Proof' , OPTIONAL]
|
||||||
|
]),
|
||||||
|
SuspendedPaymentCancel: [4].concat(base, [
|
||||||
|
['Owner' , REQUIRED],
|
||||||
|
['OfferSequence' , REQUIRED]
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -396,13 +431,22 @@ exports.ledger = {
|
|||||||
['LedgerIndex', OPTIONAL],
|
['LedgerIndex', OPTIONAL],
|
||||||
['Balance', REQUIRED],
|
['Balance', REQUIRED],
|
||||||
['LowLimit', REQUIRED],
|
['LowLimit', REQUIRED],
|
||||||
['HighLimit', REQUIRED]])
|
['HighLimit', REQUIRED]]),
|
||||||
|
SignerList: [83].concat(sleBase,[
|
||||||
|
['OwnerNode', REQUIRED],
|
||||||
|
['SignerQuorum', REQUIRED],
|
||||||
|
['SignerEntries', REQUIRED],
|
||||||
|
['SignerListID', REQUIRED],
|
||||||
|
['PreviousTxnID', REQUIRED],
|
||||||
|
['PreviousTxnLgrSeq', REQUIRED]
|
||||||
|
])
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.metadata = [
|
exports.metadata = [
|
||||||
[ 'TransactionIndex' , REQUIRED ],
|
['DeliveredAmount' , OPTIONAL],
|
||||||
[ 'TransactionResult' , REQUIRED ],
|
['TransactionIndex' , REQUIRED],
|
||||||
[ 'AffectedNodes' , REQUIRED ]
|
['TransactionResult' , REQUIRED],
|
||||||
|
['AffectedNodes' , REQUIRED]
|
||||||
];
|
];
|
||||||
|
|
||||||
exports.ter = {
|
exports.ter = {
|
||||||
@@ -422,7 +466,7 @@ exports.ter = {
|
|||||||
tecNO_LINE_REDUNDANT : 127,
|
tecNO_LINE_REDUNDANT : 127,
|
||||||
tecPATH_DRY : 128,
|
tecPATH_DRY : 128,
|
||||||
tecUNFUNDED : 129, // Deprecated, old ambiguous unfunded.
|
tecUNFUNDED : 129, // Deprecated, old ambiguous unfunded.
|
||||||
tecMASTER_DISABLED : 130,
|
tecNO_ALTERNATIVE_KEY : 130,
|
||||||
tecNO_REGULAR_KEY : 131,
|
tecNO_REGULAR_KEY : 131,
|
||||||
tecOWNERS : 132,
|
tecOWNERS : 132,
|
||||||
tecNO_ISSUER : 133,
|
tecNO_ISSUER : 133,
|
||||||
@@ -436,5 +480,6 @@ exports.ter = {
|
|||||||
tecINSUFFICIENT_RESERVE : 141,
|
tecINSUFFICIENT_RESERVE : 141,
|
||||||
tecNEED_MASTER_KEY : 142,
|
tecNEED_MASTER_KEY : 142,
|
||||||
tecDST_TAG_NEEDED : 143,
|
tecDST_TAG_NEEDED : 143,
|
||||||
tecINTERNAL : 144
|
tecINTERNAL : 144,
|
||||||
|
tecOVERSIZE : 145
|
||||||
};
|
};
|
||||||
|
|||||||
6
src/core/constants.js
Normal file
6
src/core/constants.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ACCOUNT_ZERO: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||||
|
ACCOUNT_ONE: 'rrrrrrrrrrrrrrrrrrrrBZbvji'
|
||||||
|
};
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var extend = require('extend');
|
const extend = require('extend');
|
||||||
var UInt160 = require('./uint160').UInt160;
|
const UInt160 = require('./uint160').UInt160;
|
||||||
var utils = require('./utils');
|
const utils = require('./utils');
|
||||||
var Float = require('./ieee754').Float;
|
const Float = require('./ieee754').Float;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Currency support
|
// Currency support
|
||||||
//
|
//
|
||||||
|
|
||||||
var Currency = extend(function() {
|
const Currency = extend(function() {
|
||||||
// Internal form: 0 = XRP. 3 letter-code.
|
// Internal form: 0 = XRP. 3 letter-code.
|
||||||
// XXX Internal should be 0 or hex with three letter annotation when valid.
|
// XXX Internal should be 0 or hex with three letter annotation when valid.
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ var Currency = extend(function() {
|
|||||||
this._update();
|
this._update();
|
||||||
}, UInt160);
|
}, UInt160);
|
||||||
|
|
||||||
Currency.prototype = extend({}, UInt160.prototype);
|
Currency.prototype = Object.create(extend({}, UInt160.prototype));
|
||||||
Currency.prototype.constructor = Currency;
|
Currency.prototype.constructor = Currency;
|
||||||
|
|
||||||
Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
|
Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
|
||||||
@@ -61,12 +61,12 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*eslint-disable max-len*/
|
/* eslint-disable max-len*/
|
||||||
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9\<\>\(\)\{\}\[\]\|\?\!\@\#\$\%\^\&]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
|
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9\<\>\(\)\{\}\[\]\|\?\!\@\#\$\%\^\&]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
|
||||||
/*eslint-enable max-len*/
|
/* eslint-enable max-len*/
|
||||||
|
|
||||||
Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
||||||
return (new Currency()).parse_json(j, shouldInterpretXrpAsIou);
|
return (new Currency()).parse_json(j, shouldInterpretXrpAsIou);
|
||||||
};
|
};
|
||||||
|
|
||||||
Currency.from_human = function(j, opts) {
|
Currency.from_human = function(j, opts) {
|
||||||
@@ -78,7 +78,7 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
|
|
||||||
if (j instanceof Currency) {
|
if (j instanceof Currency) {
|
||||||
this._value = j.copyTo({})._value;
|
this._value = j._value;
|
||||||
this._update();
|
this._update();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -111,10 +111,10 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// match the given string to see if it's in an allowed format
|
// match the given string to see if it's in an allowed format
|
||||||
var matches = j.match(this.human_RE);
|
const matches = j.match(this.human_RE);
|
||||||
|
|
||||||
if (matches) {
|
if (matches) {
|
||||||
var currencyCode = matches[1];
|
let currencyCode = matches[1];
|
||||||
|
|
||||||
// for the currency 'XRP' case
|
// for the currency 'XRP' case
|
||||||
// we drop everything else that could have been provided
|
// we drop everything else that could have been provided
|
||||||
@@ -131,14 +131,14 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
// the full currency is matched as it is part of the valid currency
|
// the full currency is matched as it is part of the valid currency
|
||||||
// format, but not stored
|
// format, but not stored
|
||||||
// var full_currency = matches[2] || '';
|
// var full_currency = matches[2] || '';
|
||||||
var interest = matches[3] || '';
|
const interest = matches[3] || '';
|
||||||
|
|
||||||
// interest is defined as interest per year, per annum (pa)
|
// interest is defined as interest per year, per annum (pa)
|
||||||
var percentage = interest.match(/(-?\d+\.?\d+)/);
|
let percentage = interest.match(/(-?\d+\.?\d+)/);
|
||||||
|
|
||||||
currencyCode = currencyCode.toUpperCase();
|
currencyCode = currencyCode.toUpperCase();
|
||||||
|
|
||||||
var currencyData = utils.arraySet(20, 0);
|
const currencyData = utils.arraySet(20, 0);
|
||||||
|
|
||||||
if (percentage) {
|
if (percentage) {
|
||||||
/*
|
/*
|
||||||
@@ -164,15 +164,15 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
|
|
||||||
// the interest or demurrage is expressed as a yearly (per annum)
|
// the interest or demurrage is expressed as a yearly (per annum)
|
||||||
// value
|
// value
|
||||||
var secondsPerYear = 31536000; // 60 * 60 * 24 * 365
|
const secondsPerYear = 31536000; // 60 * 60 * 24 * 365
|
||||||
|
|
||||||
// Calculating the interest e-fold
|
// Calculating the interest e-fold
|
||||||
// 0.5% demurrage is expressed 0.995, 0.005 less than 1
|
// 0.5% demurrage is expressed 0.995, 0.005 less than 1
|
||||||
// 0.5% interest is expressed as 1.005, 0.005 more than 1
|
// 0.5% interest is expressed as 1.005, 0.005 more than 1
|
||||||
var interestEfold = secondsPerYear / Math.log(1 + percentage / 100);
|
const interestEfold = secondsPerYear / Math.log(1 + percentage / 100);
|
||||||
var bytes = Float.toIEEE754Double(interestEfold);
|
const bytes = Float.toIEEE754Double(interestEfold);
|
||||||
|
|
||||||
for (var i = 0; i <= bytes.length; i++) {
|
for (let i = 0; i <= bytes.length; i++) {
|
||||||
currencyData[8 + i] = bytes[i] & 0xff;
|
currencyData[8 + i] = bytes[i] & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,10 +204,10 @@ Currency.prototype.parse_human = function(j) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Currency.prototype._update = function() {
|
Currency.prototype._update = function() {
|
||||||
var bytes = this.to_bytes();
|
const bytes = this.to_bytes();
|
||||||
|
|
||||||
// is it 0 everywhere except 12, 13, 14?
|
// is it 0 everywhere except 12, 13, 14?
|
||||||
var isZeroExceptInStandardPositions = true;
|
let isZeroExceptInStandardPositions = true;
|
||||||
|
|
||||||
if (!bytes) {
|
if (!bytes) {
|
||||||
return;
|
return;
|
||||||
@@ -219,7 +219,7 @@ Currency.prototype._update = function() {
|
|||||||
this._interest_period = NaN;
|
this._interest_period = NaN;
|
||||||
this._iso_code = '';
|
this._iso_code = '';
|
||||||
|
|
||||||
for (var i = 0; i < 20; i++) {
|
for (let i = 0; i < 20; i++) {
|
||||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
|
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
|
||||||
&& (i === 12 || i === 13 || i === 14 || bytes[i] === 0);
|
&& (i === 12 || i === 13 || i === 14 || bytes[i] === 0);
|
||||||
}
|
}
|
||||||
@@ -249,6 +249,34 @@ Currency.prototype._update = function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns copy.
|
||||||
|
*
|
||||||
|
* This copies code from UInt.copyTo so we do not call _update,
|
||||||
|
* bvecause to_bytes is very expensive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Currency.prototype.copyTo = function(d) {
|
||||||
|
d._value = this._value;
|
||||||
|
|
||||||
|
if (this._version_byte !== undefined) {
|
||||||
|
d._version_byte = this._version_byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d.is_valid()) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
d._native = this._native;
|
||||||
|
d._type = this._type;
|
||||||
|
d._interest_start = this._interest_start;
|
||||||
|
d._interest_period = this._interest_period;
|
||||||
|
d._iso_code = this._iso_code;
|
||||||
|
|
||||||
|
return d;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// XXX Probably not needed anymore?
|
// XXX Probably not needed anymore?
|
||||||
/*
|
/*
|
||||||
Currency.prototype.parse_bytes = function(byte_array) {
|
Currency.prototype.parse_bytes = function(byte_array) {
|
||||||
@@ -300,18 +328,20 @@ Currency.prototype.has_interest = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {number} referenceDate number of seconds since the Ripple Epoch
|
* @param {number} referenceDate_ number of seconds since the Ripple Epoch
|
||||||
* (0:00 on January 1, 2000 UTC) used to calculate the
|
* (0:00 on January 1, 2000 UTC) used to calculate the
|
||||||
* interest over provided interval pass in one years
|
* interest over provided interval pass in one years
|
||||||
* worth of seconds to ge the yearly interest
|
* worth of seconds to ge the yearly interest
|
||||||
* @returns {number} interest for provided interval, can be negative for
|
* @returns {number} interest for provided interval, can be negative for
|
||||||
* demurred currencies
|
* demurred currencies
|
||||||
*/
|
*/
|
||||||
Currency.prototype.get_interest_at = function(referenceDate) {
|
Currency.prototype.get_interest_at = function(referenceDate_) {
|
||||||
if (!this.has_interest()) {
|
if (!this.has_interest()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let referenceDate = referenceDate_;
|
||||||
|
|
||||||
// use one year as a default period
|
// use one year as a default period
|
||||||
if (!referenceDate) {
|
if (!referenceDate) {
|
||||||
referenceDate = this._interest_start + 3600 * 24 * 365;
|
referenceDate = this._interest_start + 3600 * 24 * 365;
|
||||||
@@ -326,13 +356,14 @@ Currency.prototype.get_interest_at = function(referenceDate) {
|
|||||||
/ this._interest_period);
|
/ this._interest_period);
|
||||||
};
|
};
|
||||||
|
|
||||||
Currency.prototype.get_interest_percentage_at
|
Currency.prototype.get_interest_percentage_at = function(referenceDate,
|
||||||
= function(referenceDate, decimals) {
|
decimals
|
||||||
var interest = this.get_interest_at(referenceDate, decimals);
|
) {
|
||||||
|
let interest = this.get_interest_at(referenceDate, decimals);
|
||||||
|
|
||||||
// convert to percentage
|
// convert to percentage
|
||||||
interest = (interest * 100) - 100;
|
interest = (interest * 100) - 100;
|
||||||
var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
|
const decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
|
||||||
|
|
||||||
// round to two decimals behind the dot
|
// round to two decimals behind the dot
|
||||||
return Math.round(interest * decimalMultiplier) / decimalMultiplier;
|
return Math.round(interest * decimalMultiplier) / decimalMultiplier;
|
||||||
@@ -347,18 +378,14 @@ Currency.prototype.get_interest_percentage_at
|
|||||||
// return UInt.prototype.is_valid() && ...;
|
// return UInt.prototype.is_valid() && ...;
|
||||||
// };
|
// };
|
||||||
|
|
||||||
Currency.prototype.to_json = function(opts) {
|
Currency.prototype.to_json = function(opts = {}) {
|
||||||
if (!this.is_valid()) {
|
if (!this.is_valid()) {
|
||||||
// XXX This is backwards compatible behavior, but probably not very good.
|
// XXX This is backwards compatible behavior, but probably not very good.
|
||||||
return 'XRP';
|
return 'XRP';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts) {
|
let currency;
|
||||||
opts = {};
|
const fullName = opts && opts.full_name ? ' - ' + opts.full_name : '';
|
||||||
}
|
|
||||||
|
|
||||||
var currency;
|
|
||||||
var fullName = opts && opts.full_name ? ' - ' + opts.full_name : '';
|
|
||||||
opts.show_interest = opts.show_interest !== undefined
|
opts.show_interest = opts.show_interest !== undefined
|
||||||
? opts.show_interest
|
? opts.show_interest
|
||||||
: this.has_interest();
|
: this.has_interest();
|
||||||
@@ -366,8 +393,8 @@ Currency.prototype.to_json = function(opts) {
|
|||||||
if (!opts.force_hex && /^[A-Z0-9]{3}$/.test(this._iso_code)) {
|
if (!opts.force_hex && /^[A-Z0-9]{3}$/.test(this._iso_code)) {
|
||||||
currency = this._iso_code + fullName;
|
currency = this._iso_code + fullName;
|
||||||
if (opts.show_interest) {
|
if (opts.show_interest) {
|
||||||
var decimals = !isNaN(opts.decimals) ? opts.decimals : undefined;
|
const decimals = !isNaN(opts.decimals) ? opts.decimals : undefined;
|
||||||
var interestPercentage = this.has_interest()
|
const interestPercentage = this.has_interest()
|
||||||
? this.get_interest_percentage_at(
|
? this.get_interest_percentage_at(
|
||||||
this._interest_start + 3600 * 24 * 365, decimals
|
this._interest_start + 3600 * 24 * 365, decimals
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ exports.HASH_LEAF_NODE = 0x4D4C4E00; // 'MLN'
|
|||||||
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
|
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
|
||||||
// inner transaction to sign (TESTNET)
|
// inner transaction to sign (TESTNET)
|
||||||
exports.HASH_TX_SIGN_TESTNET = 0x73747800; // 'stx'
|
exports.HASH_TX_SIGN_TESTNET = 0x73747800; // 'stx'
|
||||||
|
// inner transaction to multisign
|
||||||
|
exports.HASH_TX_MULTISIGN = 0x534D5400; // 'SMT'
|
||||||
|
|
||||||
Object.keys(exports).forEach(function(k) {
|
Object.keys(exports).forEach(function(k) {
|
||||||
exports[k + '_BYTES'] = toBytes(exports[k]);
|
exports[k + '_BYTES'] = toBytes(exports[k]);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ exports.Base = require('./base').Base;
|
|||||||
exports.UInt128 = require('./uint128').UInt128;
|
exports.UInt128 = require('./uint128').UInt128;
|
||||||
exports.UInt160 = require('./uint160').UInt160;
|
exports.UInt160 = require('./uint160').UInt160;
|
||||||
exports.UInt256 = require('./uint256').UInt256;
|
exports.UInt256 = require('./uint256').UInt256;
|
||||||
exports.Seed = require('./seed').Seed;
|
|
||||||
exports.Meta = require('./meta').Meta;
|
exports.Meta = require('./meta').Meta;
|
||||||
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
||||||
exports.RippleError = require('./rippleerror').RippleError;
|
exports.RippleError = require('./rippleerror').RippleError;
|
||||||
@@ -24,44 +23,8 @@ exports._test = {
|
|||||||
Log: require('./log'),
|
Log: require('./log'),
|
||||||
PathFind: require('./pathfind').PathFind,
|
PathFind: require('./pathfind').PathFind,
|
||||||
TransactionManager: require('./transactionmanager').TransactionManager,
|
TransactionManager: require('./transactionmanager').TransactionManager,
|
||||||
RangeSet: require('./rangeset').RangeSet
|
RangeSet: require('./rangeset').RangeSet,
|
||||||
|
HashPrefixes: require('./hashprefixes')
|
||||||
};
|
};
|
||||||
|
|
||||||
// Important: We do not guarantee any specific version of SJCL or for any
|
|
||||||
// specific features to be included. The version and configuration may change at
|
|
||||||
// any time without warning.
|
|
||||||
//
|
|
||||||
// However, for programs that are tied to a specific version of ripple.js like
|
|
||||||
// the official client, it makes sense to expose the SJCL instance so we don't
|
|
||||||
// have to include it twice.
|
|
||||||
exports.sjcl = require('./utils').sjcl;
|
|
||||||
exports.Wallet = require('ripple-wallet-generator')({sjcl: exports.sjcl});
|
|
||||||
exports.types = require('./serializedtypes');
|
exports.types = require('./serializedtypes');
|
||||||
|
|
||||||
// camelCase to under_scored API conversion
|
|
||||||
function attachUnderscored(name) {
|
|
||||||
const o = exports[name];
|
|
||||||
|
|
||||||
Object.keys(o.prototype).forEach(function(key) {
|
|
||||||
const UPPERCASE = /([A-Z]{1})[a-z]+/g;
|
|
||||||
|
|
||||||
if (!UPPERCASE.test(key)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const underscored = key.replace(UPPERCASE, function(c) {
|
|
||||||
return '_' + c.toLowerCase();
|
|
||||||
});
|
|
||||||
|
|
||||||
o.prototype[underscored] = o.prototype[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
['Remote',
|
|
||||||
'Request',
|
|
||||||
'Transaction',
|
|
||||||
'Account',
|
|
||||||
'Server'
|
|
||||||
].forEach(attachUnderscored);
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
/* @flow */
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const Value = require('./value').Value;
|
|
||||||
const XRPValue = require('./xrpvalue').XRPValue;
|
|
||||||
const GlobalBigNumber = require('bignumber.js');
|
|
||||||
const BigNumber = GlobalBigNumber.another({
|
|
||||||
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
|
||||||
DECIMAL_PLACES: 40
|
|
||||||
});
|
|
||||||
const rippleUnits = new BigNumber(1e6);
|
|
||||||
|
|
||||||
class IOUValue extends Value {
|
|
||||||
|
|
||||||
constructor(value: string | BigNumber, roundingMode: ?number = null,
|
|
||||||
base: ?number = null) {
|
|
||||||
|
|
||||||
super(new BigNumber(value, base).toDigits(16, roundingMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
multiply(multiplicand: Value) {
|
|
||||||
if (multiplicand instanceof XRPValue) {
|
|
||||||
return super.multiply(
|
|
||||||
new IOUValue(
|
|
||||||
multiplicand._value.times(rippleUnits)));
|
|
||||||
}
|
|
||||||
return super.multiply(multiplicand);
|
|
||||||
}
|
|
||||||
|
|
||||||
divide(divisor: Value) {
|
|
||||||
if (divisor instanceof XRPValue) {
|
|
||||||
return super.divide(
|
|
||||||
new IOUValue(divisor._value.times(rippleUnits)));
|
|
||||||
}
|
|
||||||
return super.divide(divisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
negate() {
|
|
||||||
return new IOUValue(this._value.neg());
|
|
||||||
}
|
|
||||||
|
|
||||||
_canonicalize(value) {
|
|
||||||
if (value.isNaN()) {
|
|
||||||
throw new Error('Invalid result');
|
|
||||||
}
|
|
||||||
return new IOUValue(value.toPrecision(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
equals(comparator) {
|
|
||||||
return (comparator instanceof IOUValue)
|
|
||||||
&& this._value.equals(comparator._value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.IOUValue = IOUValue;
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/*eslint new-cap: 1*/
|
|
||||||
|
|
||||||
var sjcl = require('./utils').sjcl;
|
|
||||||
|
|
||||||
var UInt160 = require('./uint160').UInt160;
|
|
||||||
var UInt256 = require('./uint256').UInt256;
|
|
||||||
var Base = require('./base').Base;
|
|
||||||
|
|
||||||
function KeyPair() {
|
|
||||||
this._curve = sjcl.ecc.curves.k256;
|
|
||||||
this._secret = null;
|
|
||||||
this._pubkey = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyPair.from_bn_secret = function(j) {
|
|
||||||
return (j instanceof this) ? j.clone() : (new this()).parse_bn_secret(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
KeyPair.prototype.parse_bn_secret = function(j) {
|
|
||||||
this._secret = new sjcl.ecc.ecdsa.secretKey(sjcl.ecc.curves.k256, j);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @return {sjcl.ecc.ecdsa.publicKey} public key
|
|
||||||
*/
|
|
||||||
KeyPair.prototype._pub = function() {
|
|
||||||
var curve = this._curve;
|
|
||||||
|
|
||||||
if (!this._pubkey && this._secret) {
|
|
||||||
var exponent = this._secret._exponent;
|
|
||||||
|
|
||||||
this._pubkey = new sjcl.ecc.ecdsa.publicKey(curve, curve.G.mult(exponent));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._pubkey;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*
|
|
||||||
* @return {sjcl.bitArray} public key bits in compressed form
|
|
||||||
*/
|
|
||||||
KeyPair.prototype._pub_bits = function() {
|
|
||||||
var pub = this._pub();
|
|
||||||
|
|
||||||
if (!pub) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var point = pub._point, y_even = point.y.mod(2).equals(0);
|
|
||||||
|
|
||||||
return sjcl.bitArray.concat(
|
|
||||||
[sjcl.bitArray.partial(8, y_even ? 0x02 : 0x03)],
|
|
||||||
point.x.toBits(this._curve.r.bitLength())
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {String} public key bytes in compressed form, hex encoded.
|
|
||||||
*/
|
|
||||||
KeyPair.prototype.to_hex_pub = function() {
|
|
||||||
var bits = this._pub_bits();
|
|
||||||
|
|
||||||
if (!bits) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sjcl.codec.hex.fromBits(bits).toUpperCase();
|
|
||||||
};
|
|
||||||
|
|
||||||
function sha256_ripemd160(bits) {
|
|
||||||
return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyPair.prototype.get_address = function() {
|
|
||||||
var bits = this._pub_bits();
|
|
||||||
|
|
||||||
if (!bits) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var hash = sha256_ripemd160(bits);
|
|
||||||
|
|
||||||
var address = UInt160.from_bits(hash);
|
|
||||||
address.set_version(Base.VER_ACCOUNT_ID);
|
|
||||||
return address;
|
|
||||||
};
|
|
||||||
|
|
||||||
KeyPair.prototype.sign = function(hash) {
|
|
||||||
var PARANOIA_256_BITS = 6; // sjcl constant for ensuring 256 bits of entropy
|
|
||||||
hash = UInt256.from_json(hash);
|
|
||||||
var sig = this._secret.sign(hash.to_bits(), PARANOIA_256_BITS);
|
|
||||||
sig = this._secret.canonicalizeSignature(sig);
|
|
||||||
return this._secret.encodeDER(sig);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.KeyPair = KeyPair;
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
/* eslint-disable valid-jsdoc */
|
|
||||||
'use strict';
|
'use strict';
|
||||||
var Transaction = require('./transaction').Transaction;
|
const BigNumber = require('bignumber.js');
|
||||||
var SHAMap = require('./shamap').SHAMap;
|
const Transaction = require('./transaction').Transaction;
|
||||||
var SHAMapTreeNode = require('./shamap').SHAMapTreeNode;
|
const SHAMap = require('./shamap').SHAMap;
|
||||||
var SerializedObject = require('./serializedobject').SerializedObject;
|
const SHAMapTreeNode = require('./shamap').SHAMapTreeNode;
|
||||||
var stypes = require('./serializedtypes');
|
const SerializedObject = require('./serializedobject').SerializedObject;
|
||||||
var UInt160 = require('./uint160').UInt160;
|
const stypes = require('./serializedtypes');
|
||||||
var Currency = require('./currency').Currency;
|
const UInt160 = require('./uint160').UInt160;
|
||||||
|
const Currency = require('./currency').Currency;
|
||||||
|
|
||||||
function Ledger() {
|
function Ledger() {
|
||||||
this.ledger_json = {};
|
this.ledger_json = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ledger.from_json = function(v) {
|
Ledger.from_json = function(v) {
|
||||||
var ledger = new Ledger();
|
const ledger = new Ledger();
|
||||||
ledger.parse_json(v);
|
ledger.parse_json(v);
|
||||||
return ledger;
|
return ledger;
|
||||||
};
|
};
|
||||||
@@ -23,14 +23,13 @@ Ledger.space = require('./ledgerspaces');
|
|||||||
/**
|
/**
|
||||||
* Generate the key for an AccountRoot entry.
|
* Generate the key for an AccountRoot entry.
|
||||||
*
|
*
|
||||||
* @param {String|UInt160} account Ripple Account
|
* @param {String|UInt160} accountArg - Ripple Account
|
||||||
* @return {UInt256}
|
* @return {UInt256}
|
||||||
*/
|
*/
|
||||||
Ledger.calcAccountRootEntryHash =
|
Ledger.calcAccountRootEntryHash =
|
||||||
Ledger.prototype.calcAccountRootEntryHash = function(account) {
|
Ledger.prototype.calcAccountRootEntryHash = function(accountArg) {
|
||||||
account = UInt160.from_json(account);
|
const account = UInt160.from_json(accountArg);
|
||||||
|
const index = new SerializedObject();
|
||||||
var index = new SerializedObject();
|
|
||||||
|
|
||||||
index.append([0, Ledger.space.account.charCodeAt(0)]);
|
index.append([0, Ledger.space.account.charCodeAt(0)]);
|
||||||
index.append(account.to_bytes());
|
index.append(account.to_bytes());
|
||||||
@@ -41,17 +40,15 @@ Ledger.prototype.calcAccountRootEntryHash = function(account) {
|
|||||||
/**
|
/**
|
||||||
* Generate the key for an Offer entry.
|
* Generate the key for an Offer entry.
|
||||||
*
|
*
|
||||||
* @param {String|UInt160} account Ripple Account
|
* @param {String|UInt160} accountArg - Ripple Account
|
||||||
* @param {Number} sequence Sequence number of the OfferCreate transaction
|
* @param {Number} sequence - Sequence number of the OfferCreate transaction
|
||||||
* that instantiated this offer.
|
* that instantiated this offer.
|
||||||
* @return {UInt256}
|
* @return {UInt256}
|
||||||
*/
|
*/
|
||||||
Ledger.calcOfferEntryHash =
|
Ledger.calcOfferEntryHash =
|
||||||
Ledger.prototype.calcOfferEntryHash = function(account, sequence) {
|
Ledger.prototype.calcOfferEntryHash = function(accountArg, sequence) {
|
||||||
account = UInt160.from_json(account);
|
const account = UInt160.from_json(accountArg);
|
||||||
sequence = parseInt(sequence, 10);
|
const index = new SerializedObject();
|
||||||
|
|
||||||
var index = new SerializedObject();
|
|
||||||
|
|
||||||
index.append([0, Ledger.space.offer.charCodeAt(0)]);
|
index.append([0, Ledger.space.offer.charCodeAt(0)]);
|
||||||
index.append(account.to_bytes());
|
index.append(account.to_bytes());
|
||||||
@@ -65,17 +62,17 @@ Ledger.prototype.calcOfferEntryHash = function(account, sequence) {
|
|||||||
*
|
*
|
||||||
* The ordering of the two account parameters does not matter.
|
* The ordering of the two account parameters does not matter.
|
||||||
*
|
*
|
||||||
* @param {String|UInt160} account1 First Ripple Account
|
* @param {String|UInt160} _account1 - First Ripple Account
|
||||||
* @param {String|UInt160} account2 Second Ripple Account
|
* @param {String|UInt160} _account2 - Second Ripple Account
|
||||||
* @param {String|Currency} currency The currency code
|
* @param {String|Currency} _currency - The currency code
|
||||||
* @return {UInt256}
|
* @return {UInt256}
|
||||||
*/
|
*/
|
||||||
Ledger.calcRippleStateEntryHash =
|
Ledger.calcRippleStateEntryHash =
|
||||||
Ledger.prototype.calcRippleStateEntryHash = function(
|
Ledger.prototype.calcRippleStateEntryHash = function(
|
||||||
account1, account2, currency) {
|
_account1, _account2, _currency) {
|
||||||
currency = Currency.from_json(currency);
|
const currency = Currency.from_json(_currency);
|
||||||
account1 = UInt160.from_json(account1);
|
const account1 = UInt160.from_json(_account1);
|
||||||
account2 = UInt160.from_json(account2);
|
const account2 = UInt160.from_json(_account2);
|
||||||
|
|
||||||
if (!account1.is_valid()) {
|
if (!account1.is_valid()) {
|
||||||
throw new Error('Invalid first account');
|
throw new Error('Invalid first account');
|
||||||
@@ -87,18 +84,14 @@ Ledger.prototype.calcRippleStateEntryHash = function(
|
|||||||
throw new Error('Invalid currency');
|
throw new Error('Invalid currency');
|
||||||
}
|
}
|
||||||
|
|
||||||
// The lower ID has to come first
|
const swap = account1.greater_than(account2);
|
||||||
if (account1.to_bn().greaterEquals(account2.to_bn())) {
|
const lowAccount = swap ? account2 : account1;
|
||||||
var tmp = account2;
|
const highAccount = swap ? account1 : account2;
|
||||||
account2 = account1;
|
const index = new SerializedObject();
|
||||||
account1 = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = new SerializedObject();
|
|
||||||
|
|
||||||
index.append([0, Ledger.space.rippleState.charCodeAt(0)]);
|
index.append([0, Ledger.space.rippleState.charCodeAt(0)]);
|
||||||
index.append(account1.to_bytes());
|
index.append(lowAccount.to_bytes());
|
||||||
index.append(account2.to_bytes());
|
index.append(highAccount.to_bytes());
|
||||||
index.append(currency.to_bytes());
|
index.append(currency.to_bytes());
|
||||||
|
|
||||||
return index.hash();
|
return index.hash();
|
||||||
@@ -109,13 +102,13 @@ Ledger.prototype.parse_json = function(v) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ledger.prototype.calc_tx_hash = function() {
|
Ledger.prototype.calc_tx_hash = function() {
|
||||||
var tx_map = new SHAMap();
|
const tx_map = new SHAMap();
|
||||||
|
|
||||||
this.ledger_json.transactions.forEach(function(tx_json) {
|
this.ledger_json.transactions.forEach(function(tx_json) {
|
||||||
var tx = Transaction.from_json(tx_json);
|
const tx = Transaction.from_json(tx_json);
|
||||||
var meta = SerializedObject.from_json(tx_json.metaData);
|
const meta = SerializedObject.from_json(tx_json.metaData);
|
||||||
|
|
||||||
var data = new SerializedObject();
|
const data = new SerializedObject();
|
||||||
stypes.VariableLength.serialize(data, tx.serialize().to_hex());
|
stypes.VariableLength.serialize(data, tx.serialize().to_hex());
|
||||||
stypes.VariableLength.serialize(data, meta.to_hex());
|
stypes.VariableLength.serialize(data, meta.to_hex());
|
||||||
tx_map.add_item(tx.hash(), data, SHAMapTreeNode.TYPE_TRANSACTION_MD);
|
tx_map.add_item(tx.hash(), data, SHAMapTreeNode.TYPE_TRANSACTION_MD);
|
||||||
@@ -125,22 +118,23 @@ Ledger.prototype.calc_tx_hash = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param options .sanity_test {Boolean}
|
* @param {Object} options - object
|
||||||
* @return hash of shamap
|
|
||||||
*
|
*
|
||||||
* If `true`, will serialize each accountState item to binary and then back to
|
* @param {Boolean} [options.sanity_test=false] - If `true`, will serialize each
|
||||||
* json before finally serializing for hashing. This is mostly to expose any
|
* accountState item to binary and then back to json before finally
|
||||||
* issues with ripple-lib's binary <--> json codecs.
|
* serializing for hashing. This is mostly to expose any issues with
|
||||||
|
* ripple-lib's binary <--> json codecs.
|
||||||
*
|
*
|
||||||
|
* @return {UInt256} - hash of shamap
|
||||||
*/
|
*/
|
||||||
Ledger.prototype.calc_account_hash = function(options) {
|
Ledger.prototype.calc_account_hash = function(options) {
|
||||||
var account_map = new SHAMap();
|
const account_map = new SHAMap();
|
||||||
var erred;
|
let erred;
|
||||||
|
|
||||||
this.ledger_json.accountState.forEach(function(le) {
|
this.ledger_json.accountState.forEach(function(le) {
|
||||||
var data = SerializedObject.from_json(le);
|
let data = SerializedObject.from_json(le);
|
||||||
|
|
||||||
var json;
|
let json;
|
||||||
if (options && options.sanity_test) {
|
if (options && options.sanity_test) {
|
||||||
try {
|
try {
|
||||||
json = data.to_json();
|
json = data.to_json();
|
||||||
@@ -163,4 +157,24 @@ Ledger.prototype.calc_account_hash = function(options) {
|
|||||||
return account_map.hash();
|
return account_map.hash();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// see rippled Ledger::updateHash()
|
||||||
|
Ledger.calculateLedgerHash =
|
||||||
|
Ledger.prototype.calculateLedgerHash = function(ledgerHeader) {
|
||||||
|
const so = new SerializedObject();
|
||||||
|
const prefix = 0x4C575200;
|
||||||
|
const totalCoins = (new BigNumber(ledgerHeader.total_coins)).toString(16);
|
||||||
|
|
||||||
|
stypes.Int32.serialize(so, Number(ledgerHeader.ledger_index));
|
||||||
|
stypes.Int64.serialize(so, totalCoins);
|
||||||
|
stypes.Hash256.serialize(so, ledgerHeader.parent_hash);
|
||||||
|
stypes.Hash256.serialize(so, ledgerHeader.transaction_hash);
|
||||||
|
stypes.Hash256.serialize(so, ledgerHeader.account_hash);
|
||||||
|
stypes.Int32.serialize(so, ledgerHeader.parent_close_time);
|
||||||
|
stypes.Int32.serialize(so, ledgerHeader.close_time);
|
||||||
|
stypes.Int8.serialize(so, ledgerHeader.close_time_resolution);
|
||||||
|
stypes.Int8.serialize(so, ledgerHeader.close_flags);
|
||||||
|
|
||||||
|
return so.hash(prefix).to_hex();
|
||||||
|
};
|
||||||
|
|
||||||
exports.Ledger = Ledger;
|
exports.Ledger = Ledger;
|
||||||
|
|||||||
107
src/core/meta.js
107
src/core/meta.js
@@ -1,7 +1,10 @@
|
|||||||
var extend = require('extend');
|
'use strict';
|
||||||
var utils = require('./utils');
|
const extend = require('extend');
|
||||||
var UInt160 = require('./uint160').UInt160;
|
const utils = require('./utils');
|
||||||
var Amount = require('./amount').Amount;
|
const UInt160 = require('./uint160').UInt160;
|
||||||
|
const Amount = require('./amount').Amount;
|
||||||
|
const ACCOUNT_ZERO = require('./constants').ACCOUNT_ZERO;
|
||||||
|
const {isValidAddress} = require('ripple-address-codec');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta data processing facility
|
* Meta data processing facility
|
||||||
@@ -11,8 +14,6 @@ var Amount = require('./amount').Amount;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function Meta(data) {
|
function Meta(data) {
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.nodes = [ ];
|
this.nodes = [ ];
|
||||||
|
|
||||||
if (typeof data !== 'object') {
|
if (typeof data !== 'object') {
|
||||||
@@ -24,7 +25,7 @@ function Meta(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.AffectedNodes.forEach(this.addNode, this);
|
data.AffectedNodes.forEach(this.addNode, this);
|
||||||
};
|
}
|
||||||
|
|
||||||
Meta.NODE_TYPES = [
|
Meta.NODE_TYPES = [
|
||||||
'CreatedNode',
|
'CreatedNode',
|
||||||
@@ -53,10 +54,10 @@ Meta.ACCOUNT_FIELDS = [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Meta.prototype.getNodeType = function(node) {
|
Meta.prototype.getNodeType = function(node) {
|
||||||
var result = null;
|
let result = null;
|
||||||
|
|
||||||
for (var i=0; i<Meta.NODE_TYPES.length; i++) {
|
for (let i = 0; i < Meta.NODE_TYPES.length; i++) {
|
||||||
var type = Meta.NODE_TYPES[i];
|
const type = Meta.NODE_TYPES[i];
|
||||||
if (node.hasOwnProperty(type)) {
|
if (node.hasOwnProperty(type)) {
|
||||||
result = type;
|
result = type;
|
||||||
break;
|
break;
|
||||||
@@ -83,20 +84,22 @@ Meta.prototype.isAccountField = function(field) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Meta.prototype.addNode = function(node) {
|
Meta.prototype.addNode = function(node) {
|
||||||
this._affectedAccounts = void(0);
|
this._affectedAccounts = undefined;
|
||||||
this._affectedBooks = void(0);
|
this._affectedBooks = undefined;
|
||||||
|
|
||||||
var result = { };
|
const result = { };
|
||||||
|
|
||||||
if ((result.nodeType = this.getNodeType(node))) {
|
result.nodeType = this.getNodeType(node);
|
||||||
node = node[result.nodeType];
|
if (result.nodeType) {
|
||||||
result.diffType = result.nodeType;
|
const _node = node[result.nodeType];
|
||||||
result.entryType = node.LedgerEntryType;
|
result.diffType = result.nodeType;
|
||||||
result.ledgerIndex = node.LedgerIndex;
|
result.entryType = _node.LedgerEntryType;
|
||||||
result.fields = extend({ }, node.PreviousFields, node.NewFields, node.FinalFields);
|
result.ledgerIndex = _node.LedgerIndex;
|
||||||
result.fieldsPrev = node.PreviousFields || { };
|
result.fields = extend({ }, _node.PreviousFields,
|
||||||
result.fieldsNew = node.NewFields || { };
|
_node.NewFields, _node.FinalFields);
|
||||||
result.fieldsFinal = node.FinalFields || { };
|
result.fieldsPrev = _node.PreviousFields || { };
|
||||||
|
result.fieldsNew = _node.NewFields || { };
|
||||||
|
result.fieldsFinal = _node.FinalFields || { };
|
||||||
|
|
||||||
// getAffectedBooks will set this
|
// getAffectedBooks will set this
|
||||||
// result.bookKey = undefined;
|
// result.bookKey = undefined;
|
||||||
@@ -126,36 +129,36 @@ Meta.prototype.getNodes = function(options) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return this.nodes;
|
|
||||||
}
|
}
|
||||||
|
return this.nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
Meta.prototype.getAffectedAccounts = function(from) {
|
Meta.prototype.getAffectedAccounts = function() {
|
||||||
if (this._affectedAccounts) {
|
if (this._affectedAccounts) {
|
||||||
return this._affectedAccounts;
|
return this._affectedAccounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
var accounts = [ ];
|
const accounts = [ ];
|
||||||
|
|
||||||
// This code should match the behavior of the C++ method:
|
// This code should match the behavior of the C++ method:
|
||||||
// TransactionMetaSet::getAffectedAccounts
|
// TransactionMetaSet::getAffectedAccounts
|
||||||
for (var i=0; i<this.nodes.length; i++) {
|
for (let i = 0; i < this.nodes.length; i++) {
|
||||||
var node = this.nodes[i];
|
const node = this.nodes[i];
|
||||||
var fields = (node.nodeType === 'CreatedNode')
|
const fields = (node.nodeType === 'CreatedNode')
|
||||||
? node.fieldsNew
|
? node.fieldsNew
|
||||||
: node.fieldsFinal;
|
: node.fieldsFinal;
|
||||||
|
|
||||||
for (var fieldName in fields) {
|
for (const fieldName in fields) {
|
||||||
var field = fields[fieldName];
|
const field = fields[fieldName];
|
||||||
|
|
||||||
if (this.isAccountField(fieldName) && UInt160.is_valid(field)) {
|
if (this.isAccountField(fieldName) && UInt160.is_valid(field)) {
|
||||||
accounts.push(field);
|
accounts.push(field);
|
||||||
} else if (~Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName)) {
|
} else if (
|
||||||
var amount = Amount.from_json(field);
|
Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName) !== -1) {
|
||||||
var issuer = amount.issuer();
|
const amount = Amount.from_json(field);
|
||||||
if (issuer.is_valid() && !issuer.is_zero()) {
|
const issuer = amount.issuer();
|
||||||
accounts.push(issuer.to_json());
|
if (isValidAddress(issuer) && issuer !== ACCOUNT_ZERO) {
|
||||||
|
accounts.push(issuer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,29 +174,29 @@ Meta.prototype.getAffectedBooks = function() {
|
|||||||
return this._affectedBooks;
|
return this._affectedBooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
var books = [ ];
|
const books = [ ];
|
||||||
|
|
||||||
for (var i=0; i<this.nodes.length; i++) {
|
for (let i = 0; i < this.nodes.length; i++) {
|
||||||
var node = this.nodes[i];
|
const node = this.nodes[i];
|
||||||
|
|
||||||
if (node.entryType !== 'Offer') {
|
if (node.entryType !== 'Offer') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gets = Amount.from_json(node.fields.TakerGets);
|
const gets = Amount.from_json(node.fields.TakerGets);
|
||||||
var pays = Amount.from_json(node.fields.TakerPays);
|
const pays = Amount.from_json(node.fields.TakerPays);
|
||||||
var getsKey = gets.currency().to_json();
|
let getsKey = gets.currency().to_json();
|
||||||
var paysKey = pays.currency().to_json();
|
let paysKey = pays.currency().to_json();
|
||||||
|
|
||||||
if (getsKey !== 'XRP') {
|
if (getsKey !== 'XRP') {
|
||||||
getsKey += '/' + gets.issuer().to_json();
|
getsKey += '/' + gets.issuer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paysKey !== 'XRP') {
|
if (paysKey !== 'XRP') {
|
||||||
paysKey += '/' + pays.issuer().to_json();
|
paysKey += '/' + pays.issuer();
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = getsKey + ':' + paysKey;
|
const key = getsKey + ':' + paysKey;
|
||||||
|
|
||||||
// Hell of a lot of work, so we are going to cache this. We can use this
|
// Hell of a lot of work, so we are going to cache this. We can use this
|
||||||
// later to good effect in OrderBook.notify to make sure we only process
|
// later to good effect in OrderBook.notify to make sure we only process
|
||||||
@@ -243,12 +246,12 @@ Meta.prototype.getAffectedBooks = function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
[
|
[
|
||||||
'forEach',
|
'forEach',
|
||||||
'map',
|
'map',
|
||||||
'filter',
|
'filter',
|
||||||
'every',
|
'every',
|
||||||
'some',
|
'some',
|
||||||
'reduce'
|
'reduce'
|
||||||
].forEach(function(fn) {
|
].forEach(function(fn) {
|
||||||
Meta.prototype[fn] = function() {
|
Meta.prototype[fn] = function() {
|
||||||
return Array.prototype[fn].apply(this.nodes, arguments);
|
return Array.prototype[fn].apply(this.nodes, arguments);
|
||||||
|
|||||||
@@ -22,10 +22,17 @@ const Currency = require('./currency').Currency;
|
|||||||
const AutobridgeCalculator = require('./autobridgecalculator');
|
const AutobridgeCalculator = require('./autobridgecalculator');
|
||||||
const OrderBookUtils = require('./orderbookutils');
|
const OrderBookUtils = require('./orderbookutils');
|
||||||
const log = require('./log').internal.sub('orderbook');
|
const log = require('./log').internal.sub('orderbook');
|
||||||
const IOUValue = require('./iouvalue').IOUValue;
|
const {IOUValue} = require('ripple-lib-value');
|
||||||
|
|
||||||
function assertValidNumber(number, message) {
|
function _sortOffers(a, b) {
|
||||||
assert(!_.isNull(number) && !isNaN(number), message);
|
const aQuality = OrderBookUtils.getOfferQuality(a, this._currencyGets);
|
||||||
|
const bQuality = OrderBookUtils.getOfferQuality(b, this._currencyGets);
|
||||||
|
|
||||||
|
return aQuality._value.comparedTo(bQuality._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _sortOffersQuick(a, b) {
|
||||||
|
return a.qualityHex.localeCompare(b.qualityHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,11 +43,13 @@ function assertValidNumber(number, message) {
|
|||||||
* @param {String} bid currency
|
* @param {String} bid currency
|
||||||
* @param {String} bid issuer
|
* @param {String} bid issuer
|
||||||
* @param {String} orderbook key
|
* @param {String} orderbook key
|
||||||
|
* @param {Boolean} fire 'model' event after receiving transaction
|
||||||
|
only once in 10 seconds
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function OrderBook(remote,
|
function OrderBook(remote,
|
||||||
currencyGets, issuerGets, currencyPays, issuerPays,
|
currencyGets, issuerGets, currencyPays, issuerPays, key
|
||||||
key) {
|
) {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
@@ -61,6 +70,8 @@ function OrderBook(remote,
|
|||||||
this._ownerFundsUnadjusted = {};
|
this._ownerFundsUnadjusted = {};
|
||||||
this._ownerFunds = {};
|
this._ownerFunds = {};
|
||||||
this._ownerOffersTotal = {};
|
this._ownerOffersTotal = {};
|
||||||
|
this._validAccounts = {};
|
||||||
|
this._validAccountsCount = 0;
|
||||||
|
|
||||||
// We consider ourselves synced if we have a current
|
// We consider ourselves synced if we have a current
|
||||||
// copy of the offers, we are online and subscribed to updates
|
// copy of the offers, we are online and subscribed to updates
|
||||||
@@ -73,13 +84,45 @@ function OrderBook(remote,
|
|||||||
// books that we must keep track of to compute autobridged offers
|
// books that we must keep track of to compute autobridged offers
|
||||||
this._legOneBook = null;
|
this._legOneBook = null;
|
||||||
this._legTwoBook = null;
|
this._legTwoBook = null;
|
||||||
|
this._gotOffersFromLegOne = false;
|
||||||
|
this._gotOffersFromLegTwo = false;
|
||||||
|
|
||||||
|
this._waitingForOffers = false;
|
||||||
|
this._lastUpdateLedgerSequence = 0;
|
||||||
|
this._transactionsLeft = 0;
|
||||||
|
this._calculatorRunning = false;
|
||||||
|
|
||||||
|
|
||||||
|
this.sortOffers = this._currencyGets.has_interest() ?
|
||||||
|
_sortOffers.bind(this) : _sortOffersQuick;
|
||||||
|
|
||||||
this._isAutobridgeable = !this._currencyGets.is_native()
|
this._isAutobridgeable = !this._currencyGets.is_native()
|
||||||
&& !this._currencyPays.is_native();
|
&& !this._currencyPays.is_native();
|
||||||
|
|
||||||
function computeAutobridgedOffersWrapper() {
|
function computeAutobridgedOffersWrapperOne() {
|
||||||
self.computeAutobridgedOffers();
|
if (!self._gotOffersFromLegOne) {
|
||||||
self.mergeDirectAndAutobridgedBooks();
|
self._gotOffersFromLegOne = true;
|
||||||
|
self.computeAutobridgedOffersWrapper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeAutobridgedOffersWrapperTwo() {
|
||||||
|
if (!self._gotOffersFromLegTwo) {
|
||||||
|
self._gotOffersFromLegTwo = true;
|
||||||
|
self.computeAutobridgedOffersWrapper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDisconnect() {
|
||||||
|
self.resetCache();
|
||||||
|
self._gotOffersFromLegOne = false;
|
||||||
|
self._gotOffersFromLegTwo = false;
|
||||||
|
if (!self._destroyed) {
|
||||||
|
self._remote.once('disconnect', onDisconnect);
|
||||||
|
self._remote.once('connect', function() {
|
||||||
|
self.subscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._isAutobridgeable) {
|
if (this._isAutobridgeable) {
|
||||||
@@ -89,15 +132,19 @@ function OrderBook(remote,
|
|||||||
issuer_pays: issuerPays
|
issuer_pays: issuerPays
|
||||||
});
|
});
|
||||||
|
|
||||||
this._legOneBook.on('model', computeAutobridgedOffersWrapper);
|
|
||||||
|
|
||||||
this._legTwoBook = remote.createOrderBook({
|
this._legTwoBook = remote.createOrderBook({
|
||||||
currency_gets: currencyGets,
|
currency_gets: currencyGets,
|
||||||
issuer_gets: issuerGets,
|
issuer_gets: issuerGets,
|
||||||
currency_pays: 'XRP'
|
currency_pays: 'XRP'
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this._legTwoBook.on('model', computeAutobridgedOffersWrapper);
|
function onTransactionWrapper(transaction) {
|
||||||
|
self.onTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLedgerClosedWrapper(message) {
|
||||||
|
self.onLedgerClosed(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function listenersModified(action, event) {
|
function listenersModified(action, event) {
|
||||||
@@ -107,7 +154,17 @@ function OrderBook(remote,
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case 'add':
|
case 'add':
|
||||||
if (++self._listeners === 1) {
|
if (++self._listeners === 1) {
|
||||||
|
self._shouldSubscribe = true;
|
||||||
self.subscribe();
|
self.subscribe();
|
||||||
|
|
||||||
|
self._remote.on('transaction', onTransactionWrapper);
|
||||||
|
self._remote.on('ledger_closed', onLedgerClosedWrapper);
|
||||||
|
self._remote.once('disconnect', onDisconnect);
|
||||||
|
|
||||||
|
if (self._isAutobridgeable) {
|
||||||
|
self._legOneBook.on('model', computeAutobridgedOffersWrapperOne);
|
||||||
|
self._legTwoBook.on('model', computeAutobridgedOffersWrapperTwo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'remove':
|
case 'remove':
|
||||||
@@ -119,10 +176,6 @@ function OrderBook(remote,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFundedAmountsWrapper(transaction) {
|
|
||||||
self.updateFundedAmounts(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.on('newListener', function(event) {
|
this.on('newListener', function(event) {
|
||||||
listenersModified('add', event);
|
listenersModified('add', event);
|
||||||
});
|
});
|
||||||
@@ -131,23 +184,22 @@ function OrderBook(remote,
|
|||||||
listenersModified('remove', event);
|
listenersModified('remove', event);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._remote.on('transaction', updateFundedAmountsWrapper);
|
|
||||||
|
|
||||||
this.on('unsubscribe', function() {
|
this.on('unsubscribe', function() {
|
||||||
self.resetCache();
|
self.resetCache();
|
||||||
|
|
||||||
self._remote.removeListener('transaction', updateFundedAmountsWrapper);
|
self._remote.removeListener('transaction', onTransactionWrapper);
|
||||||
});
|
self._remote.removeListener('ledger_closed', onLedgerClosedWrapper);
|
||||||
|
self._remote.removeListener('disconnect', onDisconnect);
|
||||||
|
|
||||||
this._remote.once('prepare_subscribe', function() {
|
self._gotOffersFromLegOne = false;
|
||||||
self.subscribe();
|
self._gotOffersFromLegTwo = false;
|
||||||
});
|
|
||||||
|
|
||||||
this._remote.on('disconnect', function() {
|
if (self._isAutobridgeable) {
|
||||||
self.resetCache();
|
self._legOneBook.removeListener('model',
|
||||||
self._remote.once('prepare_subscribe', function() {
|
computeAutobridgedOffersWrapperOne);
|
||||||
self.subscribe();
|
self._legTwoBook.removeListener('model',
|
||||||
});
|
computeAutobridgedOffersWrapperTwo);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -165,7 +217,11 @@ OrderBook.EVENTS = [
|
|||||||
'offer_changed', 'offer_funds_changed'
|
'offer_changed', 'offer_funds_changed'
|
||||||
];
|
];
|
||||||
|
|
||||||
OrderBook.DEFAULT_TRANSFER_RATE = 1000000000;
|
OrderBook.DEFAULT_TRANSFER_RATE = new IOUValue(1000000000);
|
||||||
|
|
||||||
|
OrderBook.ZERO_NATIVE_AMOUNT = Amount.from_json('0');
|
||||||
|
|
||||||
|
OrderBook.ZERO_NORMALIZED_AMOUNT = OrderBookUtils.normalizeAmount('0');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize offers from book_offers and transaction stream
|
* Normalize offers from book_offers and transaction stream
|
||||||
@@ -192,18 +248,20 @@ OrderBook.offerRewrite = function(offer) {
|
|||||||
result.Flags = result.Flags || 0;
|
result.Flags = result.Flags || 0;
|
||||||
result.OwnerNode = result.OwnerNode || new Array(16 + 1).join('0');
|
result.OwnerNode = result.OwnerNode || new Array(16 + 1).join('0');
|
||||||
result.BookNode = result.BookNode || new Array(16 + 1).join('0');
|
result.BookNode = result.BookNode || new Array(16 + 1).join('0');
|
||||||
|
result.qualityHex = result.BookDirectory.slice(-16);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize orderbook. Get orderbook offers and subscribe to transactions
|
* Initialize orderbook. Get orderbook offers and subscribe to transactions
|
||||||
|
* @api private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.subscribe = function() {
|
OrderBook.prototype.subscribe = function() {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
if (!this._shouldSubscribe) {
|
if (!this._shouldSubscribe || this._destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +274,7 @@ OrderBook.prototype.subscribe = function() {
|
|||||||
self.requestTransferRate(callback);
|
self.requestTransferRate(callback);
|
||||||
},
|
},
|
||||||
function(callback) {
|
function(callback) {
|
||||||
self.requestOffers(callback);
|
self.requestOffers(callback, true);
|
||||||
},
|
},
|
||||||
function(callback) {
|
function(callback) {
|
||||||
self.subscribeTransactions(callback);
|
self.subscribeTransactions(callback);
|
||||||
@@ -229,6 +287,7 @@ OrderBook.prototype.subscribe = function() {
|
|||||||
/**
|
/**
|
||||||
* Unhook event listeners and prevent ripple-lib from further work on this
|
* Unhook event listeners and prevent ripple-lib from further work on this
|
||||||
* orderbook. There is no more orderbook stream, so "unsubscribe" is nominal
|
* orderbook. There is no more orderbook stream, so "unsubscribe" is nominal
|
||||||
|
* @api private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.unsubscribe = function() {
|
OrderBook.prototype.unsubscribe = function() {
|
||||||
@@ -250,35 +309,87 @@ OrderBook.prototype.unsubscribe = function() {
|
|||||||
this.emit('unsubscribe');
|
this.emit('unsubscribe');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After that you can't use this object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
OrderBook.prototype.destroy = function() {
|
||||||
|
this._destroyed = true;
|
||||||
|
if (this._subscribed) {
|
||||||
|
this.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._remote._books.hasOwnProperty(this._key)) {
|
||||||
|
delete this._remote._books[this._key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isAutobridgeable) {
|
||||||
|
this._legOneBook.destroy();
|
||||||
|
this._legTwoBook.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request orderbook entries from server
|
* Request orderbook entries from server
|
||||||
*
|
*
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.requestOffers = function(callback=function() {}) {
|
OrderBook.prototype.requestOffers = function(callback = function() {},
|
||||||
|
internal = false) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
if (!this._remote.isConnected()) {
|
||||||
|
// do not make request if not online.
|
||||||
|
// that requests will be queued and
|
||||||
|
// eventually all of them will fire back
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this._shouldSubscribe) {
|
if (!this._shouldSubscribe) {
|
||||||
return callback(new Error('Should not request offers'));
|
callback(new Error('Should not request offers'));
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._remote.trace) {
|
if (this._remote.trace) {
|
||||||
log.info('requesting offers', this._key);
|
log.info('requesting offers', this._key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._synchronized = false;
|
||||||
|
|
||||||
|
if (this._isAutobridgeable && !internal) {
|
||||||
|
this._gotOffersFromLegOne = false;
|
||||||
|
this._gotOffersFromLegTwo = false;
|
||||||
|
|
||||||
|
this._legOneBook.requestOffers();
|
||||||
|
this._legTwoBook.requestOffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function handleOffers(res) {
|
function handleOffers(res) {
|
||||||
|
if (self._destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self._waitingForOffers = false;
|
||||||
|
|
||||||
if (!Array.isArray(res.offers)) {
|
if (!Array.isArray(res.offers)) {
|
||||||
// XXX What now?
|
// XXX What now?
|
||||||
return callback(new Error('Invalid response'));
|
callback(new Error('Invalid response'));
|
||||||
|
self.emit('model', []);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self._remote.trace) {
|
if (self._remote.trace) {
|
||||||
log.info('requested offers', self._key, 'offers: ' + res.offers.length);
|
log.info('requested offers', self._key, 'offers: ' + res.offers.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setOffers(res.offers);
|
self.setOffers(res.offers);
|
||||||
self.notifyDirectOffersChanged();
|
|
||||||
|
if (self._isAutobridgeable) {
|
||||||
|
self.computeAutobridgedOffersWrapper();
|
||||||
|
} else {
|
||||||
|
self.emit('model', self._offers);
|
||||||
|
}
|
||||||
|
|
||||||
callback(null, self._offers);
|
callback(null, self._offers);
|
||||||
}
|
}
|
||||||
@@ -289,9 +400,12 @@ OrderBook.prototype.requestOffers = function(callback=function() {}) {
|
|||||||
log.info('failed to request offers', self._key, err);
|
log.info('failed to request offers', self._key, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._waitingForOffers = false;
|
||||||
callback(err);
|
callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._waitingForOffers = true;
|
||||||
|
|
||||||
const requestOptions = _.merge({}, this.toJSON(), {ledger: 'validated'});
|
const requestOptions = _.merge({}, this.toJSON(), {ledger: 'validated'});
|
||||||
const request = this._remote.requestBookOffers(requestOptions);
|
const request = this._remote.requestBookOffers(requestOptions);
|
||||||
request.once('success', handleOffers);
|
request.once('success', handleOffers);
|
||||||
@@ -331,8 +445,10 @@ OrderBook.prototype.requestTransferRate = function(callback) {
|
|||||||
|
|
||||||
// When transfer rate is not explicitly set on account, it implies the
|
// When transfer rate is not explicitly set on account, it implies the
|
||||||
// default transfer rate
|
// default transfer rate
|
||||||
self._issuerTransferRate = info.account_data.TransferRate ||
|
self._issuerTransferRate =
|
||||||
OrderBook.DEFAULT_TRANSFER_RATE;
|
info.account_data.TransferRate ?
|
||||||
|
new IOUValue(info.account_data.TransferRate) :
|
||||||
|
OrderBook.DEFAULT_TRANSFER_RATE;
|
||||||
|
|
||||||
callback(null, self._issuerTransferRate);
|
callback(null, self._issuerTransferRate);
|
||||||
}
|
}
|
||||||
@@ -387,18 +503,6 @@ OrderBook.prototype.subscribeTransactions = function(callback) {
|
|||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles notifying listeners that direct offers have changed. For autobridged
|
|
||||||
* books, an additional merge step is also performed
|
|
||||||
*/
|
|
||||||
|
|
||||||
OrderBook.prototype.notifyDirectOffersChanged = function() {
|
|
||||||
if (this._isAutobridgeable) {
|
|
||||||
this.mergeDirectAndAutobridgedBooks();
|
|
||||||
} else {
|
|
||||||
this.emit('model', this._offers);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset cached owner's funds, offer counts, and offer sums
|
* Reset cached owner's funds, offer counts, and offer sums
|
||||||
@@ -409,6 +513,12 @@ OrderBook.prototype.resetCache = function() {
|
|||||||
this._ownerOffersTotal = {};
|
this._ownerOffersTotal = {};
|
||||||
this._offerCounts = {};
|
this._offerCounts = {};
|
||||||
this._synced = false;
|
this._synced = false;
|
||||||
|
this._offers = [];
|
||||||
|
|
||||||
|
if (this._validAccountsCount > 3000) {
|
||||||
|
this._validAccounts = {};
|
||||||
|
this._validAccountsCount = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -418,7 +528,6 @@ OrderBook.prototype.resetCache = function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.hasOwnerFunds = function(account) {
|
OrderBook.prototype.hasOwnerFunds = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
return this._ownerFunds[account] !== undefined;
|
return this._ownerFunds[account] !== undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -430,7 +539,6 @@ OrderBook.prototype.hasOwnerFunds = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.setOwnerFunds = function(account, fundedAmount) {
|
OrderBook.prototype.setOwnerFunds = function(account, fundedAmount) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
assert(!isNaN(fundedAmount), 'Funded amount is invalid');
|
assert(!isNaN(fundedAmount), 'Funded amount is invalid');
|
||||||
|
|
||||||
this._ownerFundsUnadjusted[account] = fundedAmount;
|
this._ownerFundsUnadjusted[account] = fundedAmount;
|
||||||
@@ -447,11 +555,10 @@ OrderBook.prototype.setOwnerFunds = function(account, fundedAmount) {
|
|||||||
|
|
||||||
OrderBook.prototype.applyTransferRate = function(balance) {
|
OrderBook.prototype.applyTransferRate = function(balance) {
|
||||||
assert(!isNaN(balance), 'Balance is invalid');
|
assert(!isNaN(balance), 'Balance is invalid');
|
||||||
assertValidNumber(this._issuerTransferRate, 'Transfer rate is invalid');
|
|
||||||
|
|
||||||
const adjustedBalance = (new IOUValue(balance))
|
const adjustedBalance = (new IOUValue(balance))
|
||||||
.divide(new IOUValue(this._issuerTransferRate))
|
.divide(this._issuerTransferRate)
|
||||||
.multiply(new IOUValue(OrderBook.DEFAULT_TRANSFER_RATE)).toString();
|
.multiply(OrderBook.DEFAULT_TRANSFER_RATE).toString();
|
||||||
|
|
||||||
return adjustedBalance;
|
return adjustedBalance;
|
||||||
};
|
};
|
||||||
@@ -464,7 +571,6 @@ OrderBook.prototype.applyTransferRate = function(balance) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.getOwnerFunds = function(account) {
|
OrderBook.prototype.getOwnerFunds = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
if (this.hasOwnerFunds(account)) {
|
if (this.hasOwnerFunds(account)) {
|
||||||
if (this._currencyGets.is_native()) {
|
if (this._currencyGets.is_native()) {
|
||||||
return Amount.from_json(this._ownerFunds[account]);
|
return Amount.from_json(this._ownerFunds[account]);
|
||||||
@@ -481,7 +587,6 @@ OrderBook.prototype.getOwnerFunds = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.getUnadjustedOwnerFunds = function(account) {
|
OrderBook.prototype.getUnadjustedOwnerFunds = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
return this._ownerFundsUnadjusted[account];
|
return this._ownerFundsUnadjusted[account];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -492,7 +597,6 @@ OrderBook.prototype.getUnadjustedOwnerFunds = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.deleteOwnerFunds = function(account) {
|
OrderBook.prototype.deleteOwnerFunds = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
this._ownerFunds[account] = undefined;
|
this._ownerFunds[account] = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -504,7 +608,6 @@ OrderBook.prototype.deleteOwnerFunds = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.getOwnerOfferCount = function(account) {
|
OrderBook.prototype.getOwnerOfferCount = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
return this._offerCounts[account] || 0;
|
return this._offerCounts[account] || 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -516,7 +619,6 @@ OrderBook.prototype.getOwnerOfferCount = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.incrementOwnerOfferCount = function(account) {
|
OrderBook.prototype.incrementOwnerOfferCount = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
const result = (this._offerCounts[account] || 0) + 1;
|
const result = (this._offerCounts[account] || 0) + 1;
|
||||||
this._offerCounts[account] = result;
|
this._offerCounts[account] = result;
|
||||||
return result;
|
return result;
|
||||||
@@ -531,7 +633,6 @@ OrderBook.prototype.incrementOwnerOfferCount = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.decrementOwnerOfferCount = function(account) {
|
OrderBook.prototype.decrementOwnerOfferCount = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
const result = (this._offerCounts[account] || 1) - 1;
|
const result = (this._offerCounts[account] || 1) - 1;
|
||||||
this._offerCounts[account] = result;
|
this._offerCounts[account] = result;
|
||||||
|
|
||||||
@@ -552,8 +653,6 @@ OrderBook.prototype.decrementOwnerOfferCount = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.addOwnerOfferTotal = function(account, amount) {
|
OrderBook.prototype.addOwnerOfferTotal = function(account, amount) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
|
|
||||||
const previousAmount = this.getOwnerOfferTotal(account);
|
const previousAmount = this.getOwnerOfferTotal(account);
|
||||||
const currentAmount = previousAmount.add(Amount.from_json(amount));
|
const currentAmount = previousAmount.add(Amount.from_json(amount));
|
||||||
|
|
||||||
@@ -572,14 +671,12 @@ OrderBook.prototype.addOwnerOfferTotal = function(account, amount) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.subtractOwnerOfferTotal = function(account, amount) {
|
OrderBook.prototype.subtractOwnerOfferTotal = function(account, amount) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
|
|
||||||
const previousAmount = this.getOwnerOfferTotal(account);
|
const previousAmount = this.getOwnerOfferTotal(account);
|
||||||
const newAmount = previousAmount.subtract(Amount.from_json(amount));
|
const newAmount = previousAmount.subtract(Amount.from_json(amount));
|
||||||
|
|
||||||
this._ownerOffersTotal[account] = newAmount;
|
this._ownerOffersTotal[account] = newAmount;
|
||||||
|
|
||||||
assert(!newAmount.is_negative(), 'Offer total cannot be negative');
|
assert(!newAmount.is_negative(), 'Offer total cannot be negative');
|
||||||
|
|
||||||
return newAmount;
|
return newAmount;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -591,15 +688,14 @@ OrderBook.prototype.subtractOwnerOfferTotal = function(account, amount) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.getOwnerOfferTotal = function(account) {
|
OrderBook.prototype.getOwnerOfferTotal = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
const amount = this._ownerOffersTotal[account];
|
const amount = this._ownerOffersTotal[account];
|
||||||
if (amount) {
|
if (amount) {
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
if (this._currencyGets.is_native()) {
|
if (this._currencyGets.is_native()) {
|
||||||
return Amount.from_json('0');
|
return OrderBook.ZERO_NATIVE_AMOUNT.clone();
|
||||||
}
|
}
|
||||||
return OrderBookUtils.normalizeAmount('0');
|
return OrderBook.ZERO_NORMALIZED_AMOUNT.clone();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -610,11 +706,10 @@ OrderBook.prototype.getOwnerOfferTotal = function(account) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.resetOwnerOfferTotal = function(account) {
|
OrderBook.prototype.resetOwnerOfferTotal = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
|
||||||
if (this._currencyGets.is_native()) {
|
if (this._currencyGets.is_native()) {
|
||||||
this._ownerOffersTotal[account] = Amount.from_json('0');
|
this._ownerOffersTotal[account] = OrderBook.ZERO_NATIVE_AMOUNT.clone();
|
||||||
} else {
|
} else {
|
||||||
this._ownerOffersTotal[account] = OrderBookUtils.normalizeAmount('0');
|
this._ownerOffersTotal[account] = OrderBook.ZERO_NORMALIZED_AMOUNT.clone();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -632,17 +727,18 @@ OrderBook.prototype.resetOwnerOfferTotal = function(account) {
|
|||||||
OrderBook.prototype.setOfferFundedAmount = function(offer) {
|
OrderBook.prototype.setOfferFundedAmount = function(offer) {
|
||||||
assert.strictEqual(typeof offer, 'object', 'Offer is invalid');
|
assert.strictEqual(typeof offer, 'object', 'Offer is invalid');
|
||||||
|
|
||||||
|
const takerGets = Amount.from_json(offer.TakerGets);
|
||||||
const fundedAmount = this.getOwnerFunds(offer.Account);
|
const fundedAmount = this.getOwnerFunds(offer.Account);
|
||||||
const previousOfferSum = this.getOwnerOfferTotal(offer.Account);
|
const previousOfferSum = this.getOwnerOfferTotal(offer.Account);
|
||||||
const currentOfferSum = previousOfferSum.add(
|
const currentOfferSum = previousOfferSum.add(takerGets);
|
||||||
Amount.from_json(offer.TakerGets));
|
|
||||||
|
|
||||||
offer.owner_funds = this.getUnadjustedOwnerFunds(offer.Account);
|
offer.owner_funds = this.getUnadjustedOwnerFunds(offer.Account);
|
||||||
|
|
||||||
offer.is_fully_funded = fundedAmount.compareTo(currentOfferSum) >= 0;
|
offer.is_fully_funded = fundedAmount.is_comparable(currentOfferSum) &&
|
||||||
|
fundedAmount.compareTo(currentOfferSum) >= 0;
|
||||||
|
|
||||||
if (offer.is_fully_funded) {
|
if (offer.is_fully_funded) {
|
||||||
offer.taker_gets_funded = Amount.from_json(offer.TakerGets).to_text();
|
offer.taker_gets_funded = takerGets.to_text();
|
||||||
offer.taker_pays_funded = Amount.from_json(offer.TakerPays).to_text();
|
offer.taker_pays_funded = Amount.from_json(offer.TakerPays).to_text();
|
||||||
} else if (previousOfferSum.compareTo(fundedAmount) < 0) {
|
} else if (previousOfferSum.compareTo(fundedAmount) < 0) {
|
||||||
offer.taker_gets_funded = fundedAmount.subtract(previousOfferSum).to_text();
|
offer.taker_gets_funded = fundedAmount.subtract(previousOfferSum).to_text();
|
||||||
@@ -698,7 +794,11 @@ OrderBook.prototype.parseAccountBalanceFromNode = function(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(!isNaN(result.balance), 'node has an invalid balance');
|
assert(!isNaN(result.balance), 'node has an invalid balance');
|
||||||
assert(UInt160.is_valid(result.account), 'node has an invalid account');
|
if (this._validAccounts[result.Account] === undefined) {
|
||||||
|
assert(UInt160.is_valid(result.account), 'node has an invalid account');
|
||||||
|
this._validAccounts[result.Account] = true;
|
||||||
|
this._validAccountsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@@ -737,6 +837,32 @@ OrderBook.prototype.isBalanceChangeNode = function(node) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OrderBook.prototype._canRunAutobridgeCalc = function(): boolean {
|
||||||
|
return !this._calculatorRunning;
|
||||||
|
};
|
||||||
|
|
||||||
|
OrderBook.prototype.onTransaction = function(transaction) {
|
||||||
|
this.updateFundedAmounts(transaction);
|
||||||
|
|
||||||
|
|
||||||
|
if (--this._transactionsLeft === 0 && !this._waitingForOffers) {
|
||||||
|
const lastClosedLedger = this._remote.getLedgerSequenceSync();
|
||||||
|
if (this._isAutobridgeable) {
|
||||||
|
if (this._canRunAutobridgeCalc()) {
|
||||||
|
if (this._legOneBook._lastUpdateLedgerSequence === lastClosedLedger ||
|
||||||
|
this._legTwoBook._lastUpdateLedgerSequence === lastClosedLedger
|
||||||
|
) {
|
||||||
|
this.computeAutobridgedOffersWrapper();
|
||||||
|
} else if (this._lastUpdateLedgerSequence === lastClosedLedger) {
|
||||||
|
this.mergeDirectAndAutobridgedBooks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (this._lastUpdateLedgerSequence === lastClosedLedger) {
|
||||||
|
this.emit('model', this._offers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates funded amounts/balances using modified balance nodes
|
* Updates funded amounts/balances using modified balance nodes
|
||||||
*
|
*
|
||||||
@@ -786,6 +912,7 @@ OrderBook.prototype.updateFundedAmounts = function(transaction) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update offers' funded amount with their owner's funds
|
* Update offers' funded amount with their owner's funds
|
||||||
*
|
*
|
||||||
@@ -793,10 +920,15 @@ OrderBook.prototype.updateFundedAmounts = function(transaction) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) {
|
OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) {
|
||||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
// assert(UInt160.is_valid(account), 'Account is invalid');
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
if (!this.hasOwnerFunds(account)) {
|
||||||
|
// We are only updating owner funds that are already cached
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._remote.trace) {
|
if (this._remote.trace) {
|
||||||
const ownerFunds = this.getOwnerFunds(account);
|
const ownerFunds = this.getOwnerFunds(account);
|
||||||
log.info('updating offer funds', this._key, account,
|
log.info('updating offer funds', this._key, account,
|
||||||
@@ -838,6 +970,16 @@ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
OrderBook.prototype.onLedgerClosed = function(message) {
|
||||||
|
if (!message || (message && !_.isNumber(message.txn_count)) ||
|
||||||
|
!this._subscribed || this._destroyed || this._waitingForOffers
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._transactionsLeft = message.txn_count;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify orderbook of a relevant transaction
|
* Notify orderbook of a relevant transaction
|
||||||
*
|
*
|
||||||
@@ -848,7 +990,7 @@ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) {
|
|||||||
OrderBook.prototype.notify = function(transaction) {
|
OrderBook.prototype.notify = function(transaction) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
if (!(this._subscribed && this._synced)) {
|
if (!(this._subscribed && this._synced) || this._destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -884,6 +1026,12 @@ OrderBook.prototype.notify = function(transaction) {
|
|||||||
function handleNode(node) {
|
function handleNode(node) {
|
||||||
switch (node.nodeType) {
|
switch (node.nodeType) {
|
||||||
case 'DeletedNode':
|
case 'DeletedNode':
|
||||||
|
if (self._validAccounts[node.fields.Account] === undefined) {
|
||||||
|
assert(UInt160.is_valid(node.fields.Account),
|
||||||
|
'node has an invalid account');
|
||||||
|
self._validAccounts[node.fields.Account] = true;
|
||||||
|
self._validAccountsCount++;
|
||||||
|
}
|
||||||
self.deleteOffer(node, isOfferCancel);
|
self.deleteOffer(node, isOfferCancel);
|
||||||
|
|
||||||
// We don't want to count an OfferCancel as a trade
|
// We don't want to count an OfferCancel as a trade
|
||||||
@@ -894,6 +1042,12 @@ OrderBook.prototype.notify = function(transaction) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'ModifiedNode':
|
case 'ModifiedNode':
|
||||||
|
if (self._validAccounts[node.fields.Account] === undefined) {
|
||||||
|
assert(UInt160.is_valid(node.fields.Account),
|
||||||
|
'node has an invalid account');
|
||||||
|
self._validAccounts[node.fields.Account] = true;
|
||||||
|
self._validAccountsCount++;
|
||||||
|
}
|
||||||
self.modifyOffer(node);
|
self.modifyOffer(node);
|
||||||
|
|
||||||
takerGetsTotal = takerGetsTotal
|
takerGetsTotal = takerGetsTotal
|
||||||
@@ -906,6 +1060,12 @@ OrderBook.prototype.notify = function(transaction) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'CreatedNode':
|
case 'CreatedNode':
|
||||||
|
if (self._validAccounts[node.fields.Account] === undefined) {
|
||||||
|
assert(UInt160.is_valid(node.fields.Account),
|
||||||
|
'node has an invalid account');
|
||||||
|
self._validAccounts[node.fields.Account] = true;
|
||||||
|
self._validAccountsCount++;
|
||||||
|
}
|
||||||
// rippled does not set owner_funds if the order maker is the issuer
|
// rippled does not set owner_funds if the order maker is the issuer
|
||||||
// because the value would be infinite
|
// because the value would be infinite
|
||||||
const fundedAmount = transactionOwnerFunds !== undefined ?
|
const fundedAmount = transactionOwnerFunds !== undefined ?
|
||||||
@@ -919,7 +1079,9 @@ OrderBook.prototype.notify = function(transaction) {
|
|||||||
_.each(affectedNodes, handleNode);
|
_.each(affectedNodes, handleNode);
|
||||||
|
|
||||||
this.emit('transaction', transaction);
|
this.emit('transaction', transaction);
|
||||||
this.notifyDirectOffersChanged();
|
|
||||||
|
this._lastUpdateLedgerSequence = this._remote.getLedgerSequenceSync();
|
||||||
|
|
||||||
if (!takerGetsTotal.is_zero()) {
|
if (!takerGetsTotal.is_zero()) {
|
||||||
this.emit('trade', takerPaysTotal, takerGetsTotal);
|
this.emit('trade', takerPaysTotal, takerGetsTotal);
|
||||||
}
|
}
|
||||||
@@ -951,17 +1113,27 @@ OrderBook.prototype.insertOffer = function(node) {
|
|||||||
|
|
||||||
const originalLength = this._offers.length;
|
const originalLength = this._offers.length;
|
||||||
|
|
||||||
for (let i = 0; i < originalLength; i++) {
|
if (!this._currencyGets.has_interest()) {
|
||||||
const quality = OrderBookUtils.getOfferQuality(offer, this._currencyGets);
|
// use fast path
|
||||||
const existingOfferQuality = OrderBookUtils.getOfferQuality(
|
for (let i = 0; i < originalLength; i++) {
|
||||||
this._offers[i],
|
if (offer.qualityHex <= this._offers[i].qualityHex) {
|
||||||
this._currencyGets
|
this._offers.splice(i, 0, offer);
|
||||||
);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < originalLength; i++) {
|
||||||
|
const quality = OrderBookUtils.getOfferQuality(offer, this._currencyGets);
|
||||||
|
const existingOfferQuality = OrderBookUtils.getOfferQuality(
|
||||||
|
this._offers[i],
|
||||||
|
this._currencyGets
|
||||||
|
);
|
||||||
|
|
||||||
if (quality.compareTo(existingOfferQuality) <= 0) {
|
if (quality.compareTo(existingOfferQuality) <= 0) {
|
||||||
this._offers.splice(i, 0, offer);
|
this._offers.splice(i, 0, offer);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,28 +1239,34 @@ OrderBook.prototype.deleteOffer = function(node, isOfferCancel) {
|
|||||||
OrderBook.prototype.setOffers = function(offers) {
|
OrderBook.prototype.setOffers = function(offers) {
|
||||||
assert(Array.isArray(offers), 'Offers is not an array');
|
assert(Array.isArray(offers), 'Offers is not an array');
|
||||||
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
this.resetCache();
|
this.resetCache();
|
||||||
|
|
||||||
const newOffers = _.map(offers, function(rawOffer) {
|
let i = -1;
|
||||||
const offer = OrderBook.offerRewrite(rawOffer);
|
let offer;
|
||||||
|
const l = offers.length;
|
||||||
|
|
||||||
if (offer.hasOwnProperty('owner_funds')) {
|
while (++i < l) {
|
||||||
|
offer = OrderBook.offerRewrite(offers[i]);
|
||||||
|
|
||||||
|
if (this._validAccounts[offer.Account] === undefined) {
|
||||||
|
assert(UInt160.is_valid(offer.Account), 'Account is invalid');
|
||||||
|
this._validAccounts[offer.Account] = true;
|
||||||
|
this._validAccountsCount++;
|
||||||
|
}
|
||||||
|
if (offer.owner_funds !== undefined) {
|
||||||
// The first offer of each owner from book_offers contains owner balance
|
// The first offer of each owner from book_offers contains owner balance
|
||||||
// of offer's output
|
// of offer's output
|
||||||
self.setOwnerFunds(offer.Account, offer.owner_funds);
|
this.setOwnerFunds(offer.Account, offer.owner_funds);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.incrementOwnerOfferCount(offer.Account);
|
this.incrementOwnerOfferCount(offer.Account);
|
||||||
|
|
||||||
self.setOfferFundedAmount(offer);
|
this.setOfferFundedAmount(offer);
|
||||||
self.addOwnerOfferTotal(offer.Account, offer.TakerGets);
|
this.addOwnerOfferTotal(offer.Account, offer.TakerGets);
|
||||||
|
offers[i] = offer;
|
||||||
|
}
|
||||||
|
|
||||||
return offer;
|
this._offers = offers;
|
||||||
});
|
|
||||||
|
|
||||||
this._offers = newOffers;
|
|
||||||
this._synced = true;
|
this._synced = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1187,10 +1365,16 @@ OrderBook.prototype.is_valid = function() {
|
|||||||
* IOU:XRP and XRP:IOU books
|
* IOU:XRP and XRP:IOU books
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.computeAutobridgedOffers = function() {
|
OrderBook.prototype.computeAutobridgedOffers = function(callback = function() {}
|
||||||
|
) {
|
||||||
assert(!this._currencyGets.is_native() && !this._currencyPays.is_native(),
|
assert(!this._currencyGets.is_native() && !this._currencyPays.is_native(),
|
||||||
'Autobridging is only for IOU:IOU orderbooks');
|
'Autobridging is only for IOU:IOU orderbooks');
|
||||||
|
|
||||||
|
|
||||||
|
if (this._destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const autobridgeCalculator = new AutobridgeCalculator(
|
const autobridgeCalculator = new AutobridgeCalculator(
|
||||||
this._currencyGets,
|
this._currencyGets,
|
||||||
this._currencyPays,
|
this._currencyPays,
|
||||||
@@ -1200,7 +1384,24 @@ OrderBook.prototype.computeAutobridgedOffers = function() {
|
|||||||
this._issuerPays
|
this._issuerPays
|
||||||
);
|
);
|
||||||
|
|
||||||
this._offersAutobridged = autobridgeCalculator.calculate();
|
autobridgeCalculator.calculate((autobridgedOffers) => {
|
||||||
|
this._offersAutobridged = autobridgedOffers;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
OrderBook.prototype.computeAutobridgedOffersWrapper = function() {
|
||||||
|
if (!this._gotOffersFromLegOne || !this._gotOffersFromLegTwo ||
|
||||||
|
!this._synchronized || this._destroyed || this._calculatorRunning
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._calculatorRunning = true;
|
||||||
|
this.computeAutobridgedOffers(() => {
|
||||||
|
this.mergeDirectAndAutobridgedBooks();
|
||||||
|
this._calculatorRunning = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1210,22 +1411,24 @@ OrderBook.prototype.computeAutobridgedOffers = function() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBook.prototype.mergeDirectAndAutobridgedBooks = function() {
|
OrderBook.prototype.mergeDirectAndAutobridgedBooks = function() {
|
||||||
const self = this;
|
|
||||||
|
if (this._destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_.isEmpty(this._offers) && _.isEmpty(this._offersAutobridged)) {
|
if (_.isEmpty(this._offers) && _.isEmpty(this._offersAutobridged)) {
|
||||||
// still emit empty offers list to indicate that load is completed
|
if (this._synced && this._gotOffersFromLegOne &&
|
||||||
this.emit('model', []);
|
this._gotOffersFromLegTwo) {
|
||||||
|
// emit empty model to indicate to listeners that we've got offers,
|
||||||
|
// just there was no one
|
||||||
|
this.emit('model', []);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._mergedOffers = this._offers
|
this._mergedOffers = this._offers
|
||||||
.concat(this._offersAutobridged)
|
.concat(this._offersAutobridged)
|
||||||
.sort(function(a, b) {
|
.sort(this.sortOffers);
|
||||||
const aQuality = OrderBookUtils.getOfferQuality(a, self._currencyGets);
|
|
||||||
const bQuality = OrderBookUtils.getOfferQuality(b, self._currencyGets);
|
|
||||||
|
|
||||||
return aQuality.compareTo(bQuality);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.emit('model', this._mergedOffers);
|
this.emit('model', this._mergedOffers);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ const assert = require('assert');
|
|||||||
const SerializedObject = require('./serializedobject').SerializedObject;
|
const SerializedObject = require('./serializedobject').SerializedObject;
|
||||||
const Types = require('./serializedtypes');
|
const Types = require('./serializedtypes');
|
||||||
const Amount = require('./amount').Amount;
|
const Amount = require('./amount').Amount;
|
||||||
|
const Currency = require('./currency').Currency;
|
||||||
|
const UInt160 = require('./uint160').UInt160;
|
||||||
|
const {IOUValue} = require('ripple-lib-value');
|
||||||
const OrderBookUtils = {};
|
const OrderBookUtils = {};
|
||||||
|
|
||||||
function assertValidNumber(number, message) {
|
function assertValidNumber(number, message) {
|
||||||
@@ -19,10 +22,17 @@ function assertValidNumber(number, message) {
|
|||||||
* @return JSON amount object
|
* @return JSON amount object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function createAmount(value, currency, counterparty) {
|
function createAmount(value, currency_, counterparty_) {
|
||||||
const newJSON =
|
|
||||||
{'value': value, 'currency': currency, 'issuer': counterparty};
|
const currency = currency_ instanceof Currency ?
|
||||||
return Amount.from_json(newJSON);
|
currency_ :
|
||||||
|
Currency.from_json(currency_);
|
||||||
|
|
||||||
|
const counterparty = counterparty_ instanceof UInt160 ?
|
||||||
|
counterparty_.to_json() : counterparty_;
|
||||||
|
|
||||||
|
return Amount.from_components_unsafe(new IOUValue(value),
|
||||||
|
currency, counterparty, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,11 +62,11 @@ function getIssuerFromOffer(offer) {
|
|||||||
* @return {Amount}
|
* @return {Amount}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBookUtils.getOfferTakerGetsFunded = function(offer) {
|
OrderBookUtils.getOfferTakerGetsFunded = function(offer, currency_, issuer_) {
|
||||||
assertValidNumber(offer.taker_gets_funded, 'Taker gets funded is invalid');
|
assertValidNumber(offer.taker_gets_funded, 'Taker gets funded is invalid');
|
||||||
|
|
||||||
const currency = getCurrencyFromOffer(offer);
|
const currency = currency_ || getCurrencyFromOffer(offer);
|
||||||
const issuer = getIssuerFromOffer(offer);
|
const issuer = issuer_ || getIssuerFromOffer(offer);
|
||||||
|
|
||||||
return createAmount(offer.taker_gets_funded, currency, issuer);
|
return createAmount(offer.taker_gets_funded, currency, issuer);
|
||||||
};
|
};
|
||||||
@@ -68,11 +78,11 @@ OrderBookUtils.getOfferTakerGetsFunded = function(offer) {
|
|||||||
* @return {Amount}
|
* @return {Amount}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBookUtils.getOfferTakerPaysFunded = function(offer) {
|
OrderBookUtils.getOfferTakerPaysFunded = function(offer, currency_, issuer_) {
|
||||||
assertValidNumber(offer.taker_pays_funded, 'Taker gets funded is invalid');
|
assertValidNumber(offer.taker_pays_funded, 'Taker gets funded is invalid');
|
||||||
|
|
||||||
const currency = getCurrencyFromOffer(offer);
|
const currency = currency_ || getCurrencyFromOffer(offer);
|
||||||
const issuer = getIssuerFromOffer(offer);
|
const issuer = issuer_ || getIssuerFromOffer(offer);
|
||||||
|
|
||||||
return createAmount(offer.taker_pays_funded, currency, issuer);
|
return createAmount(offer.taker_pays_funded, currency, issuer);
|
||||||
};
|
};
|
||||||
@@ -85,11 +95,11 @@ OrderBookUtils.getOfferTakerPaysFunded = function(offer) {
|
|||||||
* @return {Amount}
|
* @return {Amount}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBookUtils.getOfferTakerGets = function(offer) {
|
OrderBookUtils.getOfferTakerGets = function(offer, currency_, issuer_) {
|
||||||
assert(typeof offer, 'object', 'Offer is invalid');
|
assert(typeof offer, 'object', 'Offer is invalid');
|
||||||
|
|
||||||
const currency = offer.TakerPays.currency;
|
const currency = currency_ || offer.TakerPays.currency;
|
||||||
const issuer = offer.TakerPays.issuer;
|
const issuer = issuer_ || offer.TakerPays.issuer;
|
||||||
|
|
||||||
return createAmount(offer.TakerGets, currency, issuer);
|
return createAmount(offer.TakerGets, currency, issuer);
|
||||||
};
|
};
|
||||||
@@ -101,7 +111,9 @@ OrderBookUtils.getOfferTakerGets = function(offer) {
|
|||||||
* @param {Currency} currencyGets
|
* @param {Currency} currencyGets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBookUtils.getOfferQuality = function(offer, currencyGets) {
|
OrderBookUtils.getOfferQuality = function(offer, currencyGets, currency_,
|
||||||
|
issuer_
|
||||||
|
) {
|
||||||
let amount;
|
let amount;
|
||||||
|
|
||||||
if (currencyGets.has_interest()) {
|
if (currencyGets.has_interest()) {
|
||||||
@@ -113,8 +125,8 @@ OrderBookUtils.getOfferQuality = function(offer, currencyGets) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const currency = getCurrencyFromOffer(offer);
|
const currency = currency_ || getCurrencyFromOffer(offer);
|
||||||
const issuer = getIssuerFromOffer(offer);
|
const issuer = issuer_ || getIssuerFromOffer(offer);
|
||||||
|
|
||||||
amount = createAmount(offer.quality, currency, issuer);
|
amount = createAmount(offer.quality, currency, issuer);
|
||||||
}
|
}
|
||||||
@@ -140,13 +152,35 @@ OrderBookUtils.convertOfferQualityToHex = function(quality) {
|
|||||||
return so.to_hex();
|
return so.to_hex();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats an offer quality amount to a hex that can be parsed by
|
||||||
|
* Amount.parse_quality
|
||||||
|
*
|
||||||
|
* @param {String} quality
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
|
||||||
|
OrderBookUtils.convertOfferQualityToHexFromText = function(quality) {
|
||||||
|
|
||||||
|
const so = new SerializedObject();
|
||||||
|
Types.Quality.serialize(so, quality);
|
||||||
|
|
||||||
|
return so.to_hex();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
OrderBookUtils.CURRENCY_ONE = Currency.from_json(1);
|
||||||
|
|
||||||
|
OrderBookUtils.ISSUER_ONE = UInt160.from_json(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OrderBookUtils.normalizeAmount = function(value) {
|
OrderBookUtils.normalizeAmount = function(value) {
|
||||||
|
return Amount.from_components_unsafe(new IOUValue(value),
|
||||||
return Amount.from_number(value);
|
OrderBookUtils.CURRENCY_ONE, OrderBookUtils.ISSUER_ONE, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = OrderBookUtils;
|
module.exports = OrderBookUtils;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
var EventEmitter = require('events').EventEmitter;
|
'use strict';
|
||||||
var util = require('util');
|
const EventEmitter = require('events').EventEmitter;
|
||||||
var Amount = require('./amount').Amount;
|
const util = require('util');
|
||||||
var extend = require('extend');
|
const Amount = require('./amount').Amount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a persistent path finding request.
|
* Represents a persistent path finding request.
|
||||||
@@ -10,16 +10,20 @@ var extend = require('extend');
|
|||||||
* find request is triggered it will supercede the existing one, making it emit
|
* find request is triggered it will supercede the existing one, making it emit
|
||||||
* the 'end' and 'superceded' events.
|
* the 'end' and 'superceded' events.
|
||||||
*/
|
*/
|
||||||
function PathFind(remote, src_account, dst_account, dst_amount, src_currencies) {
|
|
||||||
|
function PathFind(remote, src_account, dst_account, dst_amount,
|
||||||
|
src_currencies, src_amount
|
||||||
|
) {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
|
|
||||||
this.src_account = src_account;
|
this.src_account = src_account;
|
||||||
this.dst_account = dst_account;
|
this.dst_account = dst_account;
|
||||||
this.dst_amount = dst_amount;
|
this.dst_amount = dst_amount;
|
||||||
this.src_currencies = src_currencies;
|
this.src_currencies = src_currencies;
|
||||||
};
|
this.src_amount = src_amount;
|
||||||
|
}
|
||||||
|
|
||||||
util.inherits(PathFind, EventEmitter);
|
util.inherits(PathFind, EventEmitter);
|
||||||
|
|
||||||
@@ -32,14 +36,17 @@ util.inherits(PathFind, EventEmitter);
|
|||||||
* so you should only have to call it if the path find was closed or superceded
|
* so you should only have to call it if the path find was closed or superceded
|
||||||
* and you wish to restart it.
|
* and you wish to restart it.
|
||||||
*/
|
*/
|
||||||
PathFind.prototype.create = function () {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var req = this.remote.request_path_find_create(
|
PathFind.prototype.create = function() {
|
||||||
this.src_account,
|
const self = this;
|
||||||
this.dst_account,
|
|
||||||
this.dst_amount,
|
const req = this.remote.requestPathFindCreate({
|
||||||
this.src_currencies);
|
source_account: this.src_account,
|
||||||
|
destination_account: this.dst_account,
|
||||||
|
destination_amount: this.dst_amount,
|
||||||
|
source_currencies: this.src_currencies,
|
||||||
|
send_max: this.src_amount
|
||||||
|
});
|
||||||
|
|
||||||
req.once('error', function(err) {
|
req.once('error', function(err) {
|
||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
@@ -54,27 +61,28 @@ PathFind.prototype.create = function () {
|
|||||||
req.broadcast().request();
|
req.broadcast().request();
|
||||||
};
|
};
|
||||||
|
|
||||||
PathFind.prototype.close = function () {
|
PathFind.prototype.close = function() {
|
||||||
this.remote.request_path_find_close().broadcast().request();
|
this.removeAllListeners('update');
|
||||||
|
this.remote.requestPathFindClose().broadcast().request();
|
||||||
this.emit('end');
|
this.emit('end');
|
||||||
this.emit('close');
|
this.emit('close');
|
||||||
};
|
};
|
||||||
|
|
||||||
PathFind.prototype.notify_update = function (message) {
|
PathFind.prototype.notify_update = function(message) {
|
||||||
var src_account = message.source_account;
|
const src_account = message.source_account;
|
||||||
var dst_account = message.destination_account;
|
const dst_account = message.destination_account;
|
||||||
var dst_amount = Amount.from_json(message.destination_amount);
|
const dst_amount = Amount.from_json(message.destination_amount);
|
||||||
|
|
||||||
// Only pass the event along if this path find response matches what we were
|
// Only pass the event along if this path find response matches what we were
|
||||||
// looking for.
|
// looking for.
|
||||||
if (this.src_account === src_account &&
|
if (this.src_account === src_account &&
|
||||||
this.dst_account === dst_account &&
|
this.dst_account === dst_account &&
|
||||||
this.dst_amount.equals(dst_amount)) {
|
dst_amount.equals(this.dst_amount)) {
|
||||||
this.emit('update', message);
|
this.emit('update', message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PathFind.prototype.notify_superceded = function () {
|
PathFind.prototype.notify_superceded = function() {
|
||||||
// XXX If we're set to re-subscribe whenever we connect to a new server, then
|
// XXX If we're set to re-subscribe whenever we connect to a new server, then
|
||||||
// we should cancel that behavior here. See PathFind#create.
|
// we should cancel that behavior here. See PathFind#create.
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class RangeSet {
|
|||||||
const rangeStrings = rangesString.split(',');
|
const rangeStrings = rangesString.split(',');
|
||||||
_.forEach(rangeStrings, rangeString => {
|
_.forEach(rangeStrings, rangeString => {
|
||||||
const range = rangeString.split('-').map(Number);
|
const range = rangeString.split('-').map(Number);
|
||||||
this.addRange(range[0], range[1]);
|
this.addRange(range[0], range.length === 1 ? range[0] : range[1]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const _ = require('lodash');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
@@ -33,35 +34,73 @@ function Request(remote, command) {
|
|||||||
command: command,
|
command: command,
|
||||||
id: undefined
|
id: undefined
|
||||||
};
|
};
|
||||||
|
this._timeout = this.remote.submission_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(Request, EventEmitter);
|
util.inherits(Request, EventEmitter);
|
||||||
|
|
||||||
// Send the request to a remote.
|
// Send the request to a remote.
|
||||||
Request.prototype.request = function(servers, callback) {
|
Request.prototype.request = function(servers, callback_) {
|
||||||
this.emit('before');
|
const callback = typeof servers === 'function' ? servers : callback_;
|
||||||
this.callback(callback);
|
const self = this;
|
||||||
|
|
||||||
|
if (this.requested) {
|
||||||
|
throw new Error('Already requested');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('before');
|
||||||
|
// emit handler can set requested flag
|
||||||
if (this.requested) {
|
if (this.requested) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.requested = true;
|
this.requested = true;
|
||||||
|
this.callback(callback);
|
||||||
|
|
||||||
this.on('error', function() {});
|
this.on('error', function() {});
|
||||||
this.emit('request', this.remote);
|
this.emit('request', this.remote);
|
||||||
|
|
||||||
if (Array.isArray(servers)) {
|
function doRequest() {
|
||||||
servers.forEach(function(server) {
|
if (Array.isArray(servers)) {
|
||||||
this.setServer(server);
|
servers.forEach(function(server) {
|
||||||
this.remote.request(this);
|
self.setServer(server);
|
||||||
}, this);
|
self.remote.request(self);
|
||||||
} else {
|
}, self);
|
||||||
this.remote.request(this);
|
} else {
|
||||||
|
self.remote.request(self);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(new RippleError('tejTimeout'));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('timeout');
|
||||||
|
// just in case
|
||||||
|
this.emit = _.noop;
|
||||||
|
this.cancel();
|
||||||
|
}, this._timeout);
|
||||||
|
|
||||||
|
function onResponse() {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.remote.isConnected()) {
|
||||||
|
this.remote.on('connected', doRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.once('response', onResponse);
|
||||||
|
|
||||||
|
doRequest();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isResponseNotError(res) {
|
||||||
|
return typeof res === 'object' && !res.hasOwnProperty('error');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast request to all servers, filter responses if a function is
|
* Broadcast request to all servers, filter responses if a function is
|
||||||
* provided. Return first response that satisfies the filter. Pre-filter
|
* provided. Return first response that satisfies the filter. Pre-filter
|
||||||
@@ -73,22 +112,23 @@ Request.prototype.request = function(servers, callback) {
|
|||||||
* @param [Function] fn
|
* @param [Function] fn
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
Request.prototype.filter =
|
Request.prototype.filter =
|
||||||
Request.prototype.addFilter =
|
Request.prototype.addFilter =
|
||||||
Request.prototype.broadcast = function(filterFn=Boolean) {
|
Request.prototype.broadcast = function(isResponseSuccess = isResponseNotError) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
if (!this.requested) {
|
if (!this.requested) {
|
||||||
// Defer until requested, and prevent the normal request() from executing
|
// Defer until requested, and prevent the normal request() from executing
|
||||||
this.once('before', function() {
|
this.once('before', function() {
|
||||||
self.requested = true;
|
self.requested = true;
|
||||||
self.broadcast(filterFn);
|
self.broadcast(isResponseSuccess);
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastResponse = new Error('No servers available');
|
let lastResponse = new Error('No servers available');
|
||||||
let connectTimeouts = { };
|
const connectTimeouts = { };
|
||||||
const emit = this.emit;
|
const emit = this.emit;
|
||||||
|
|
||||||
this.emit = function(event, a, b) {
|
this.emit = function(event, a, b) {
|
||||||
@@ -110,7 +150,7 @@ Request.prototype.broadcast = function(filterFn=Boolean) {
|
|||||||
// Listen for proxied success/error event and apply filter
|
// Listen for proxied success/error event and apply filter
|
||||||
self.once('proposed', function(res) {
|
self.once('proposed', function(res) {
|
||||||
lastResponse = res;
|
lastResponse = res;
|
||||||
callback(filterFn(res));
|
callback(isResponseSuccess(res));
|
||||||
});
|
});
|
||||||
|
|
||||||
return server._request(self);
|
return server._request(self);
|
||||||
@@ -201,14 +241,8 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
|||||||
|
|
||||||
let called = false;
|
let called = false;
|
||||||
|
|
||||||
function requestSuccess(message) {
|
|
||||||
if (!called) {
|
|
||||||
called = true;
|
|
||||||
callback.call(self, null, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestError(error) {
|
function requestError(error) {
|
||||||
|
self.remote.removeListener('error', requestError);
|
||||||
if (!called) {
|
if (!called) {
|
||||||
called = true;
|
called = true;
|
||||||
|
|
||||||
@@ -220,45 +254,30 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requestSuccess(message) {
|
||||||
|
self.remote.removeListener('error', requestError);
|
||||||
|
if (!called) {
|
||||||
|
called = true;
|
||||||
|
callback.call(self, null, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.remote.once('error', requestError); // e.g. rate-limiting slowDown error
|
||||||
this.once(this.successEvent, requestSuccess);
|
this.once(this.successEvent, requestSuccess);
|
||||||
this.once(this.errorEvent, requestError);
|
this.once(this.errorEvent, requestError);
|
||||||
this.request();
|
|
||||||
|
if (!this.requested) {
|
||||||
|
this.request();
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
Request.prototype.timeout = function(duration, callback) {
|
Request.prototype.setTimeout = function(delay) {
|
||||||
const self = this;
|
if (!_.isFinite(delay)) {
|
||||||
|
throw new Error('delay must be number');
|
||||||
function requested() {
|
|
||||||
self.timeout(duration, callback);
|
|
||||||
}
|
}
|
||||||
|
this._timeout = delay;
|
||||||
if (!this.requested) {
|
|
||||||
// Defer until requested
|
|
||||||
return this.once('request', requested);
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = this.emit;
|
|
||||||
let timed_out = false;
|
|
||||||
|
|
||||||
const timeout = setTimeout(function() {
|
|
||||||
timed_out = true;
|
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit.call(self, 'timeout');
|
|
||||||
self.cancel();
|
|
||||||
}, duration);
|
|
||||||
|
|
||||||
this.emit = function() {
|
|
||||||
if (!timed_out) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
emit.apply(self, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -266,26 +285,13 @@ Request.prototype.timeout = function(duration, callback) {
|
|||||||
Request.prototype.setServer = function(server) {
|
Request.prototype.setServer = function(server) {
|
||||||
let selected = null;
|
let selected = null;
|
||||||
|
|
||||||
switch (typeof server) {
|
if (_.isString(server)) {
|
||||||
case 'object':
|
selected = _.find(this.remote._servers, s => s._url === server) || null;
|
||||||
selected = server;
|
} else if (_.isObject(server)) {
|
||||||
break;
|
selected = server;
|
||||||
|
|
||||||
case 'string':
|
|
||||||
// Find server by URL
|
|
||||||
const servers = this.remote._servers;
|
|
||||||
|
|
||||||
for (let i = 0, s; (s = servers[i]); i++) {
|
|
||||||
if (s._url === server) {
|
|
||||||
selected = s;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.server = selected;
|
this.server = selected;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -336,26 +342,30 @@ Request.prototype.ledgerIndex = function(ledger_index) {
|
|||||||
/**
|
/**
|
||||||
* Set either ledger_index or ledger_hash based on heuristic
|
* Set either ledger_index or ledger_hash based on heuristic
|
||||||
*
|
*
|
||||||
* @param {Number|String} ledger identifier
|
* @param {Number|String} ledger - identifier
|
||||||
|
* @param {Object} options -
|
||||||
|
* @param {Number|String} defaultValue - default if `ledger` unspecifed
|
||||||
*/
|
*/
|
||||||
|
Request.prototype.ledgerSelect =
|
||||||
|
Request.prototype.selectLedger = function(ledger, defaultValue) {
|
||||||
|
const selected = ledger || defaultValue;
|
||||||
|
|
||||||
Request.prototype.selectLedger =
|
switch (selected) {
|
||||||
Request.prototype.ledgerSelect = function(ledger) {
|
|
||||||
switch (ledger) {
|
|
||||||
case 'current':
|
case 'current':
|
||||||
case 'closed':
|
case 'closed':
|
||||||
case 'validated':
|
case 'validated':
|
||||||
this.message.ledger_index = ledger;
|
this.message.ledger_index = selected;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (Number(ledger) && isFinite(Number(ledger))) {
|
if (Number(selected) && isFinite(Number(selected))) {
|
||||||
this.message.ledger_index = Number(ledger);
|
this.message.ledger_index = Number(selected);
|
||||||
} else if (/^[A-F0-9]{64}$/.test(ledger)) {
|
} else if (/^[A-F0-9]{64}$/.test(selected)) {
|
||||||
this.message.ledger_hash = ledger;
|
this.message.ledger_hash = selected;
|
||||||
|
} else if (selected !== undefined) {
|
||||||
|
throw new Error('unknown ledger format: ' + selected);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -535,7 +545,7 @@ Request.prototype.addStream = function(stream, values) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (arguments.length > 1) {
|
} else if (arguments.length > 1) {
|
||||||
for (let arg in arguments) {
|
for (const arg in arguments) {
|
||||||
this.addStream(arguments[arg]);
|
this.addStream(arguments[arg]);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -1,30 +1,42 @@
|
|||||||
var util = require('util');
|
'use strict';
|
||||||
var extend = require('extend');
|
|
||||||
|
|
||||||
function RippleError(code, message) {
|
const util = require('util');
|
||||||
switch (typeof code) {
|
const _ = require('lodash');
|
||||||
case 'object':
|
|
||||||
extend(this, code);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'string':
|
function RippleError(code?: any, message?: string) {
|
||||||
this.result = code;
|
if (code instanceof Error) {
|
||||||
this.result_message = message;
|
this.result = code;
|
||||||
break;
|
this.result_message = code.message;
|
||||||
|
} else {
|
||||||
|
switch (typeof code) {
|
||||||
|
case 'object':
|
||||||
|
_.extend(this, code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'string':
|
||||||
|
this.result = code;
|
||||||
|
this.result_message = message;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.engine_result = this.result = (this.result || this.engine_result || this.error || 'Error');
|
this.engine_result = this.result = (this.result || this.engine_result ||
|
||||||
this.engine_result_message = this.result_message = (this.result_message || this.engine_result_message || this.error_message || 'Error');
|
this.error || 'Error');
|
||||||
this.result_message = this.message = (this.result_message);
|
this.engine_result_message = this.result_message = (this.result_message ||
|
||||||
|
this.engine_result_message || this.error_message || 'Error');
|
||||||
|
this.message = this.result_message;
|
||||||
|
|
||||||
var stack;
|
let stack;
|
||||||
|
|
||||||
if (!!Error.captureStackTrace) {
|
if (Boolean(Error.captureStackTrace)) {
|
||||||
Error.captureStackTrace(this, code || this);
|
Error.captureStackTrace(this, code || this);
|
||||||
} else if ((stack = new Error().stack)) {
|
} else {
|
||||||
this.stack = stack;
|
stack = new Error().stack;
|
||||||
|
if (Boolean(stack)) {
|
||||||
|
this.stack = stack;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
util.inherits(RippleError, Error);
|
util.inherits(RippleError, Error);
|
||||||
|
|
||||||
|
|||||||
174
src/core/seed.js
174
src/core/seed.js
@@ -1,174 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
//
|
|
||||||
// Seed support
|
|
||||||
//
|
|
||||||
|
|
||||||
const extend = require('extend');
|
|
||||||
const utils = require('./utils');
|
|
||||||
const sjcl = utils.sjcl;
|
|
||||||
|
|
||||||
const Base = require('./base').Base;
|
|
||||||
const UInt = require('./uint').UInt;
|
|
||||||
const UInt160 = require('./uint160').UInt160;
|
|
||||||
const KeyPair = require('./keypair').KeyPair;
|
|
||||||
|
|
||||||
const Seed = extend(function() {
|
|
||||||
this._curve = sjcl.ecc.curves.k256;
|
|
||||||
this._value = NaN;
|
|
||||||
}, UInt);
|
|
||||||
|
|
||||||
Seed.width = 16;
|
|
||||||
Seed.prototype = extend({}, UInt.prototype);
|
|
||||||
Seed.prototype.constructor = Seed;
|
|
||||||
|
|
||||||
// value = NaN on error.
|
|
||||||
// One day this will support rfc1751 too.
|
|
||||||
Seed.prototype.parse_json = function(j) {
|
|
||||||
if (typeof j === 'string') {
|
|
||||||
if (!j.length) {
|
|
||||||
this._value = NaN;
|
|
||||||
} else {
|
|
||||||
this.parse_base58(j);
|
|
||||||
if (!this.is_valid()) {
|
|
||||||
this.parse_hex(j);
|
|
||||||
// XXX Should also try 1751
|
|
||||||
}
|
|
||||||
if (!this.is_valid()) {
|
|
||||||
this.parse_passphrase(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this._value = NaN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Seed.prototype.parse_base58 = function(j) {
|
|
||||||
if (typeof j !== 'string') {
|
|
||||||
throw new Error('Value must be a string');
|
|
||||||
}
|
|
||||||
if (!j.length || j[0] !== 's') {
|
|
||||||
this._value = NaN;
|
|
||||||
} else {
|
|
||||||
this._value = Base.decode_check(Base.VER_FAMILY_SEED, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Seed.prototype.parse_passphrase = function(j) {
|
|
||||||
if (typeof j !== 'string') {
|
|
||||||
throw new Error('Passphrase must be a string');
|
|
||||||
}
|
|
||||||
|
|
||||||
const hash = sjcl.hash.sha512.hash(sjcl.codec.utf8String.toBits(j));
|
|
||||||
const bits = sjcl.bitArray.bitSlice(hash, 0, 128);
|
|
||||||
|
|
||||||
this.parse_bits(bits);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Seed.prototype.to_json = function() {
|
|
||||||
if (!(this.is_valid())) {
|
|
||||||
return NaN;
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = Base.encode_check(Base.VER_FAMILY_SEED, this.to_bytes());
|
|
||||||
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
function append_int(a, i) {
|
|
||||||
return [].concat(a, i >> 24, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
function firstHalfOfSHA512(bytes) {
|
|
||||||
return sjcl.bitArray.bitSlice(
|
|
||||||
sjcl.hash.sha512.hash(sjcl.codec.bytes.toBits(bytes)),
|
|
||||||
0, 256
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed a `*` so this JSDoc-ish syntax is ignored.
|
|
||||||
// This will soon all change anyway.
|
|
||||||
/*
|
|
||||||
* @param account
|
|
||||||
* {undefined} take first, default, KeyPair
|
|
||||||
*
|
|
||||||
* {Number} specifies the account number of the KeyPair
|
|
||||||
* desired.
|
|
||||||
*
|
|
||||||
* {Uint160} (from_json able), specifies the address matching the KeyPair
|
|
||||||
* that is desired.
|
|
||||||
*
|
|
||||||
* @param maxLoops (optional)
|
|
||||||
* {Number} specifies the amount of attempts taken
|
|
||||||
* to generate a matching KeyPair
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Seed.prototype.get_key = function(account, maxLoops) {
|
|
||||||
let account_number = 0, address;
|
|
||||||
let max_loops = maxLoops || 1;
|
|
||||||
|
|
||||||
if (!this.is_valid()) {
|
|
||||||
throw new Error('Cannot generate keys from invalid seed!');
|
|
||||||
}
|
|
||||||
if (account) {
|
|
||||||
if (typeof account === 'number') {
|
|
||||||
account_number = account;
|
|
||||||
max_loops = account_number + 1;
|
|
||||||
} else {
|
|
||||||
address = UInt160.from_json(account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let private_gen, public_gen;
|
|
||||||
const curve = this._curve;
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
private_gen = sjcl.bn.fromBits(
|
|
||||||
firstHalfOfSHA512(append_int(this.to_bytes(), i)));
|
|
||||||
i++;
|
|
||||||
} while (!curve.r.greaterEquals(private_gen));
|
|
||||||
|
|
||||||
public_gen = curve.G.mult(private_gen);
|
|
||||||
|
|
||||||
let sec;
|
|
||||||
let key_pair;
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sec = sjcl.bn.fromBits(
|
|
||||||
firstHalfOfSHA512(
|
|
||||||
append_int(
|
|
||||||
append_int(public_gen.toBytesCompressed(), account_number)
|
|
||||||
,
|
|
||||||
i
|
|
||||||
)));
|
|
||||||
i++;
|
|
||||||
} while (!curve.r.greaterEquals(sec));
|
|
||||||
|
|
||||||
account_number++;
|
|
||||||
sec = sec.add(private_gen).mod(curve.r);
|
|
||||||
key_pair = KeyPair.from_bn_secret(sec);
|
|
||||||
|
|
||||||
if (max_loops-- <= 0) {
|
|
||||||
// We are almost certainly looking for an account that would take same
|
|
||||||
// value of $too_long {forever, ...}
|
|
||||||
throw new Error('Too many loops looking for KeyPair yielding ' +
|
|
||||||
address.to_json() + ' from ' + this.to_json());
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (address && !key_pair.get_address().equals(address));
|
|
||||||
|
|
||||||
return key_pair;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.Seed = Seed;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user