mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-14 17:45:48 +00:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
949a1ca4ae | ||
|
|
e667536a5b | ||
|
|
dde000a4bb | ||
|
|
aa1f5a8e7d | ||
|
|
bfbfcc2894 | ||
|
|
6abfa759aa | ||
|
|
7cbac2e757 | ||
|
|
1012381d3d | ||
|
|
6de96f62df | ||
|
|
e2ed2bdbf6 | ||
|
|
e248c54aa5 | ||
|
|
1c9635edad | ||
|
|
25cf6c52e4 | ||
|
|
7859ef6145 | ||
|
|
6efaa4ac7e | ||
|
|
19e17a8431 | ||
|
|
c865ae9734 | ||
|
|
6959f74073 | ||
|
|
9f4d21e976 | ||
|
|
719f39c01c | ||
|
|
25bb9c7320 | ||
|
|
a160e16abd | ||
|
|
ec31841aa5 | ||
|
|
3e249902c4 | ||
|
|
21bb766f06 | ||
|
|
a883151400 | ||
|
|
3c7fe82cbd | ||
|
|
899fc09704 | ||
|
|
daa45a44b9 | ||
|
|
52494628c3 | ||
|
|
dbf5d21b72 | ||
|
|
441bd4dfbf | ||
|
|
8452f05dda | ||
|
|
0d2325e646 | ||
|
|
90329d3d73 | ||
|
|
ca83a142f8 | ||
|
|
d3b2d3d5c5 | ||
|
|
255177487c | ||
|
|
ed0b75bcde | ||
|
|
06500a7909 | ||
|
|
6e16bf68ae | ||
|
|
ad22480117 | ||
|
|
2fcd09072f | ||
|
|
f0c785b196 | ||
|
|
84fe76bada | ||
|
|
b5ed8f59a7 | ||
|
|
52526f90d7 | ||
|
|
99e6e81e65 | ||
|
|
5af824f5cf | ||
|
|
2166bb2e88 | ||
|
|
ae884c0200 | ||
|
|
423ec7d08a | ||
|
|
914cd6ecb2 | ||
|
|
f221c82859 | ||
|
|
d57be723e6 | ||
|
|
777554809a | ||
|
|
f2b63fa4a8 | ||
|
|
4d06ce7454 | ||
|
|
8da6ec5fa3 | ||
|
|
2a5a8b498d | ||
|
|
a9b7d7d793 | ||
|
|
6578cf5dd7 | ||
|
|
2e21e8a43c | ||
|
|
176e1fd9d4 | ||
|
|
c3b274b18f | ||
|
|
8e134918fb | ||
|
|
2b531d2a1f | ||
|
|
87317dd54a | ||
|
|
618548c88d | ||
|
|
b62f42006c | ||
|
|
c275174f27 | ||
|
|
af4ed295e0 | ||
|
|
7614a03ea8 | ||
|
|
d9527726b6 | ||
|
|
05f4099709 | ||
|
|
a20a649013 | ||
|
|
0e3e64105c | ||
|
|
b2cdb1a6ae | ||
|
|
812432db96 | ||
|
|
5b2c4aef2d | ||
|
|
b7ccf424f4 | ||
|
|
77d5db168b | ||
|
|
e80cd1ff55 | ||
|
|
4ff25a21f6 | ||
|
|
f184a71360 | ||
|
|
fc38a9853d | ||
|
|
6023efed41 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -59,3 +59,5 @@ out/
|
||||
|
||||
# Ignore perf test cache
|
||||
scripts/cache
|
||||
|
||||
eslintrc
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
before_script:
|
||||
- npm install -g eslint
|
||||
- curl 'https://raw.githubusercontent.com/ripple/javascript-style-guide/master/eslintrc' > ./eslintrc
|
||||
- eslint --reset -c ./eslintrc $(git --no-pager diff --name-only --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD | grep "\.js$")
|
||||
script: MOCHA_REPORTER=tap npm test --coverage
|
||||
after_success:
|
||||
- npm run coveralls
|
||||
|
||||
28
Gulpfile.js
28
Gulpfile.js
@@ -1,3 +1,4 @@
|
||||
'use strict';
|
||||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var watch = require('gulp-watch');
|
||||
@@ -8,7 +9,6 @@ var concat = require('gulp-concat');
|
||||
var uglify = require('gulp-uglify');
|
||||
var rename = require('gulp-rename');
|
||||
var webpack = require('webpack');
|
||||
var map = require('map-stream');
|
||||
var bump = require('gulp-bump');
|
||||
var react = require('gulp-react');
|
||||
var flow = require('gulp-flowtype');
|
||||
@@ -17,12 +17,6 @@ var argv = require('yargs').argv;
|
||||
|
||||
var pkg = require('./package.json');
|
||||
|
||||
var banner = '/*! <%= pkg.name %> - v<%= pkg.version %> - '
|
||||
+ '<%= new Date().toISOString() %>\n'
|
||||
+ '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>'
|
||||
+ '* Copyright (c) <%= new Date().getFullYear() %> <%= pkg.author.name %>;'
|
||||
+ ' Licensed <%= pkg.license %> */'
|
||||
|
||||
var sjclSrc = [
|
||||
'src/js/sjcl/core/sjcl.js',
|
||||
'src/js/sjcl/core/aes.js',
|
||||
@@ -74,11 +68,11 @@ gulp.task('build', [ 'concat-sjcl' ], function(callback) {
|
||||
library: 'ripple',
|
||||
path: './build/',
|
||||
filename: ['ripple-', '.js'].join(pkg.version)
|
||||
},
|
||||
}
|
||||
}, callback);
|
||||
});
|
||||
|
||||
gulp.task('build-min', [ 'build' ], function(callback) {
|
||||
gulp.task('build-min', ['build'], function() {
|
||||
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
||||
.pipe(uglify())
|
||||
.pipe(rename(['ripple-', '-min.js'].join(pkg.version)))
|
||||
@@ -105,9 +99,10 @@ gulp.task('build-debug', [ 'concat-sjcl' ], function(callback) {
|
||||
*/
|
||||
|
||||
function buildUseError(cons) {
|
||||
return 'var {<CONS>:function(){throw new Error("Class is unavailable in this build: <CONS>")}}'
|
||||
return ('var {<CONS>:function(){throw new Error('
|
||||
+ '"Class is unavailable in this build: <CONS>")}}')
|
||||
.replace(new RegExp('<CONS>', 'g'), cons);
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('build-core', ['concat-sjcl'], function(callback) {
|
||||
webpack({
|
||||
@@ -133,19 +128,19 @@ gulp.task('build-core', [ 'concat-sjcl' ], function(callback) {
|
||||
}, callback);
|
||||
});
|
||||
|
||||
gulp.task('bower-build', [ 'build' ], function(callback) {
|
||||
gulp.task('bower-build', ['build'], function() {
|
||||
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
||||
.pipe(rename('ripple.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
});
|
||||
|
||||
gulp.task('bower-build-min', [ 'build-min' ], function(callback) {
|
||||
gulp.task('bower-build-min', ['build-min'], function() {
|
||||
return gulp.src(['./build/ripple-', '-min.js'].join(pkg.version))
|
||||
.pipe(rename('ripple-min.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
});
|
||||
|
||||
gulp.task('bower-build-debug', [ 'build-debug' ], function(callback) {
|
||||
gulp.task('bower-build-debug', ['build-debug'], function() {
|
||||
return gulp.src(['./build/ripple-', '-debug.js'].join(pkg.version))
|
||||
.pipe(rename('ripple-debug.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
@@ -157,7 +152,8 @@ gulp.task('bower-version', function() {
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
});
|
||||
|
||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug', 'bower-version']);
|
||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug',
|
||||
'bower-version']);
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('src/js/ripple/*', ['build-debug']);
|
||||
@@ -184,7 +180,7 @@ gulp.task('strip', function() {
|
||||
|
||||
gulp.task('version-bump', function() {
|
||||
if (!argv.type) {
|
||||
throw new Error("No type found, pass it in using the --type argument");
|
||||
throw new Error('No type found, pass it in using the --type argument');
|
||||
}
|
||||
|
||||
gulp.src('./package.json')
|
||||
|
||||
42
HISTORY.md
42
HISTORY.md
@@ -1,3 +1,45 @@
|
||||
##0.12.1
|
||||
|
||||
**Breaking Changes**
|
||||
|
||||
+ [Removed support for parsing native amounts in floating point format](https://github.com/ripple/ripple-lib/commit/e80cd1ff55deae9cd5b0ae85be957f86856b887e)
|
||||
|
||||
|
||||
**Changes**
|
||||
|
||||
+ [Fix taker pays funded calculation](https://github.com/ripple/ripple-lib/commit/5af824f5cf46c7b9caa58ee0a757bf854d26c8dc)
|
||||
|
||||
+ [Fix order funded amount calculation](https://github.com/ripple/ripple-lib/commit/b2cdb1a6aed968b1f306e8dadbd4b7ca37e5aa03)
|
||||
|
||||
+ [Fix handling of quality in order book](https://github.com/ripple/ripple-lib/commit/2a5a8b498da60df738ba18d5c265f34771e8a1af)
|
||||
|
||||
+ [Fix currency parsing of non-alphanumeric and no-currency currencies](https://github.com/ripple/ripple-lib/commit/2166bb2e88eae8d5f1aba77338f69e8a9edf6a6f)
|
||||
|
||||
+ [Add Amount.strict_mode for toggling range validation](https://github.com/ripple/ripple-lib/commit/b5ed8f59a7dab1a17491618b8d9193646c314fb4)
|
||||
|
||||
+ [Add filename and line number to log, use log.warn() for deprecations](https://github.com/ripple/ripple-lib/commit/90329d3d73f1a76675063655b407513e32dc048b)
|
||||
|
||||
+ [Add GlobalFreeze and NoFreeze flags](https://github.com/ripple/ripple-lib/commit/e2ed2bdbf6f01c7d4d690c2cf0b83fba94558dd7)
|
||||
|
||||
+ [Fix handling of falsy parameters in requestLedger](https://github.com/ripple/ripple-lib/commit/6023efed41b7812b3bab660a1c0dc9f0a21000b9)
|
||||
|
||||
+ [Fix Base:decode](https://github.com/ripple/ripple-lib/commit/719f39c01c6941d9a650aa94f95617793dd53ea0)
|
||||
|
||||
+ [Fix Amount: clone in ratio_human, product_human](https://github.com/ripple/ripple-lib/commit/19e17a8431550cf156b1ad669a19dedfe4e28e4a)
|
||||
|
||||
+ [Fix Amount.to_human for very small numbers](https://github.com/ripple/ripple-lib/commit/6abfa759aa09d68074ac558d96c4b126a7cd1719)
|
||||
|
||||
+ [Refactor base conversion](https://github.com/ripple/ripple-lib/commit/f2b63fa4a80663eb29472bc6bb1aea8159f1f205)
|
||||
|
||||
+ [Update binary transaction format](https://github.com/ripple/ripple-lib/commit/8e134918fb4c22983320a3102f955e4568bb1dfb)
|
||||
|
||||
+ [Add DefaultRipple account flag](https://github.com/ripple/ripple-lib/commit/3e249902c4cf25b4da5e75048c84ae391be83b10)
|
||||
|
||||
+ [Remove `Features` field requirement in `SetFee` transaction format](https://github.com/ripple/ripple-lib/commit/a20a649013646710c078d4ce1e210f87c7fe74fe)
|
||||
|
||||
+ [Remove `RegularKey` field requirement in `SetRegularKey` transaction format](https://github.com/ripple/ripple-lib/commit/c275174f27877ba8f389eb4efe969feb514d6e46)
|
||||
|
||||
|
||||
##0.12.0
|
||||
|
||||
**Breaking Changes**
|
||||
|
||||
@@ -18,7 +18,7 @@ This file provides step-by-step walkthroughs for some of the most common usages
|
||||
|
||||
##Connecting to the Ripple network
|
||||
|
||||
1. [Get ripple-lib](README.md#getting-ripple-lib)
|
||||
1. [Get ripple-lib](../README.md#installation)
|
||||
2. Load the ripple-lib module into a Node.js file or webpage:
|
||||
```js
|
||||
/* Loading ripple-lib with Node.js */
|
||||
|
||||
72
eslint.json
72
eslint.json
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"no-use-before-define": 1,
|
||||
"no-undef": 1,
|
||||
"no-unused-expressions": 1,
|
||||
"no-unused-vars": 1,
|
||||
"no-extend-native": 1,
|
||||
"no-native-reassign": 1,
|
||||
"no-trailing-spaces": 1,
|
||||
"no-empty": 1,
|
||||
"no-inner-declarations": 1,
|
||||
"no-irregular-whitespace": 1,
|
||||
"no-negated-in-lhs": 1,
|
||||
"no-obj-calls": 1,
|
||||
"no-reserved-keys": 1,
|
||||
"no-sparse-arrays": 1,
|
||||
"no-unreachable": 1,
|
||||
"use-isnan": 1,
|
||||
"valid-jsdoc": 1,
|
||||
"valid-typeof": 1,
|
||||
"block-scoped-var": 1,
|
||||
"dot-notation": 1,
|
||||
"semi": 1,
|
||||
"curly": 1,
|
||||
"eqeqeq": 1,
|
||||
"no-else-return": 1,
|
||||
"new-cap": 1,
|
||||
"new-parens": 1,
|
||||
"no-comma-dangle": 1,
|
||||
"no-empty-label": 1,
|
||||
"no-eval": 1,
|
||||
"no-extra-bind": 1,
|
||||
"no-fallthrough": 1,
|
||||
"no-lone-blocks": 1,
|
||||
"no-loop-func": 1,
|
||||
"no-multi-spaces": 1,
|
||||
"no-return-assign": 1,
|
||||
"no-sequences": 1,
|
||||
"no-with": 1,
|
||||
"radix": 1,
|
||||
"yoda": [ 1, "never" ],
|
||||
"no-catch-shadow": 1,
|
||||
"no-shadow-restricted-names": 1,
|
||||
"no-delete-var": 1,
|
||||
"no-undefined": 1,
|
||||
"handle-callback-err": 1,
|
||||
"brace-style": [ 1, "1tbs", { "allowSingleLine": false } ],
|
||||
"comma-spacing": [ 1, { "before": false, "after": true } ],
|
||||
"comma-style": [ 1, "last" ],
|
||||
"consistent-this": [ 1, "self" ],
|
||||
"func-style": [ 1, "declaration" ],
|
||||
"key-spacing": [ 1, { "beforeColon": false, "afterColon": true } ],
|
||||
"max-nested-callbacks": [ 1, 2 ],
|
||||
"no-lonely-if": 1,
|
||||
"no-mixed-spaces-and-tabs": 1,
|
||||
"no-multiple-empty-lines": 1,
|
||||
"no-space-before-semi": 1,
|
||||
"no-spaced-func": 1,
|
||||
"space-after-keywords": [ 1, "always" ],
|
||||
"space-infix-ops": 1,
|
||||
"space-return-throw-case": 1,
|
||||
"spaced-line-comment": 1,
|
||||
"max-params": [ 1, 4 ],
|
||||
"max-depth": [1, 3 ],
|
||||
"max-len": [ 1, 80 ],
|
||||
"quotes": [ 1, "single" ]
|
||||
}
|
||||
}
|
||||
26
npm-shrinkwrap.json
generated
26
npm-shrinkwrap.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.12.0",
|
||||
"version": "0.12.1",
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "0.9.0",
|
||||
@@ -8,9 +8,9 @@
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
|
||||
},
|
||||
"bignumber.js": {
|
||||
"version": "2.0.0",
|
||||
"from": "bignumber.js@>=2.0.0 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.0.tgz"
|
||||
"version": "2.0.3",
|
||||
"from": "bignumber.js@>=2.0.3 <3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.3.tgz"
|
||||
},
|
||||
"extend": {
|
||||
"version": "1.2.1",
|
||||
@@ -18,9 +18,9 @@
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
||||
},
|
||||
"lodash": {
|
||||
"version": "3.1.0",
|
||||
"version": "3.5.0",
|
||||
"from": "lodash@>=3.1.0 <4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.1.0.tgz"
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz"
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "2.5.0",
|
||||
@@ -28,9 +28,9 @@
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz"
|
||||
},
|
||||
"ripple-wallet-generator": {
|
||||
"version": "1.0.1",
|
||||
"from": "ripple-wallet-generator@1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.1.tgz"
|
||||
"version": "1.0.2",
|
||||
"from": "ripple-wallet-generator@1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.2.tgz"
|
||||
},
|
||||
"superagent": {
|
||||
"version": "0.18.2",
|
||||
@@ -157,9 +157,9 @@
|
||||
"from": "bindings@>=1.2.0 <1.3.0"
|
||||
},
|
||||
"nan": {
|
||||
"version": "1.6.1",
|
||||
"version": "1.6.2",
|
||||
"from": "nan@>=1.6.0 <1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.1.tgz"
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.2.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -173,9 +173,9 @@
|
||||
"from": "bindings@>=1.2.0 <1.3.0"
|
||||
},
|
||||
"nan": {
|
||||
"version": "1.6.1",
|
||||
"version": "1.6.2",
|
||||
"from": "nan@>=1.6.0 <1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.1.tgz"
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.2.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.12.0",
|
||||
"version": "0.12.1",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
"src/js/*",
|
||||
@@ -16,16 +16,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.9.0",
|
||||
"bignumber.js": "^2.0.0",
|
||||
"bignumber.js": "^2.0.3",
|
||||
"extend": "~1.2.1",
|
||||
"lodash": "^3.1.0",
|
||||
"lru-cache": "~2.5.0",
|
||||
"ripple-wallet-generator": "1.0.1",
|
||||
"ripple-wallet-generator": "1.0.2",
|
||||
"ws": "~0.7.1",
|
||||
"superagent": "^0.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"assert-diff": "0.0.4",
|
||||
"assert-diff": "^1.0.1",
|
||||
"coveralls": "~2.10.0",
|
||||
"eslint": "^0.13.0",
|
||||
"gulp": "~3.8.10",
|
||||
@@ -50,9 +50,9 @@
|
||||
"scripts": {
|
||||
"build": "node_modules/.bin/gulp",
|
||||
"pretest": "node_modules/.bin/gulp concat-sjcl",
|
||||
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter ${MOCHA_REPORTER:=spec} test/*-test.js",
|
||||
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter ${MOCHA_REPORTER:=spec} --timeout 10000 --slow 500 test/*-test.js",
|
||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
|
||||
"lint": "eslint --reset -c eslint.json src/js/ripple/*.js",
|
||||
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/master/eslintrc'; fi; eslint --reset -c eslintrc src/js/ripple/*.js",
|
||||
"perf": "./scripts/perf_test.sh"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// Represent Ripple amounts and currencies.
|
||||
// - Numbers in hex are big-endian.
|
||||
|
||||
@@ -7,16 +9,13 @@ var utils = require('./utils');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Seed = require('./seed').Seed;
|
||||
var Currency = require('./currency').Currency;
|
||||
var BigNumber = require('./bignumber');
|
||||
var GlobalBigNumber = require('bignumber.js');
|
||||
|
||||
var BigNumber = GlobalBigNumber.another({
|
||||
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
||||
DECIMAL_PLACES: 40
|
||||
});
|
||||
|
||||
function isInteger(number) {
|
||||
return parseInt(number) === number;
|
||||
}
|
||||
|
||||
function ensureDecimalPoint(value) {
|
||||
return isInteger(value) ? String(value) + '.0' : value;
|
||||
}
|
||||
|
||||
function inverse(number) {
|
||||
return (new BigNumber(number)).toPower(-1);
|
||||
@@ -33,6 +32,12 @@ function Amount() {
|
||||
this._issuer = new UInt160();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set strict_mode = false to disable amount range checking
|
||||
*/
|
||||
|
||||
Amount.strict_mode = true;
|
||||
|
||||
var consts = {
|
||||
currency_xns: 0,
|
||||
currency_one: 1,
|
||||
@@ -130,7 +135,7 @@ Amount.prototype.add = function(addend) {
|
||||
var addendAmount = Amount.from_json(addend);
|
||||
|
||||
if (!this.is_comparable(addendAmount)) {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
|
||||
return this._copy(this._value.plus(addendAmount._value));
|
||||
@@ -183,24 +188,26 @@ Amount.prototype.divide = function(divisor) {
|
||||
* @this {Amount} The numerator (top half) of the fraction.
|
||||
* @param {Amount} denominator The denominator (bottom half) of the fraction.
|
||||
* @param opts Options for the calculation.
|
||||
* @param opts.reference_date {Date|Number} Date based on which demurrage/interest
|
||||
* should be applied. Can be given as JavaScript Date or int for Ripple epoch.
|
||||
* @param opts.reference_date {Date|Number} Date based on which
|
||||
* demurrage/interest should be applied. Can be given as JavaScript Date or int
|
||||
* for Ripple epoch.
|
||||
* @return {Amount} The resulting ratio. Unit will be the same as numerator.
|
||||
*/
|
||||
|
||||
Amount.prototype.ratio_human = function(denominator, opts) {
|
||||
opts = extend({ }, opts);
|
||||
|
||||
var numerator = this;
|
||||
denominator = Amount.from_json(ensureDecimalPoint(denominator));
|
||||
var numerator = this.clone();
|
||||
|
||||
denominator = Amount.from_json(denominator);
|
||||
|
||||
// If either operand is NaN, the result is NaN.
|
||||
if (!numerator.is_valid() || !denominator.is_valid()) {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
|
||||
if (denominator.is_zero()) {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
|
||||
// Apply interest/demurrage
|
||||
@@ -242,21 +249,21 @@ Amount.prototype.ratio_human = function(denominator, opts) {
|
||||
*
|
||||
* @see Amount#ratio_human
|
||||
*
|
||||
* @this {Amount} The first factor of the product.
|
||||
* @param {Amount} factor The second factor of the product.
|
||||
* @param opts Options for the calculation.
|
||||
* @param opts.reference_date {Date|Number} Date based on which demurrage/interest
|
||||
* should be applied. Can be given as JavaScript Date or int for Ripple epoch.
|
||||
* @param {Object} opts Options for the calculation.
|
||||
* @param {Date|Number} opts.reference_date Date based on which
|
||||
* demurrage/interest should be applied. Can be given as JavaScript Date or int
|
||||
* for Ripple epoch.
|
||||
* @return {Amount} The product. Unit will be the same as the first factor.
|
||||
*/
|
||||
Amount.prototype.product_human = function(factor, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
factor = Amount.from_json(ensureDecimalPoint(factor));
|
||||
factor = Amount.from_json(factor);
|
||||
|
||||
// If either operand is NaN, the result is NaN.
|
||||
if (!this.is_valid() || !factor.is_valid()) {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
|
||||
// Apply interest/demurrage
|
||||
@@ -283,6 +290,7 @@ Amount.prototype.product_human = function(factor, opts) {
|
||||
/**
|
||||
* Turn this amount into its inverse.
|
||||
*
|
||||
* @return {Amount} self
|
||||
* @private
|
||||
*/
|
||||
Amount.prototype._invert = function() {
|
||||
@@ -304,7 +312,8 @@ Amount.prototype.invert = function() {
|
||||
* Canonicalize amount value
|
||||
*
|
||||
* Mirrors rippled's internal Amount representation
|
||||
* From https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol/STAmount.h#L31-L40
|
||||
* From https://github.com/ripple/rippled/blob/develop/src/ripple/data
|
||||
* /protocol/STAmount.h#L31-L40
|
||||
*
|
||||
* Internal form:
|
||||
* 1: If amount is zero, then value is zero and offset is -100
|
||||
@@ -325,25 +334,24 @@ Amount.prototype.invert = function() {
|
||||
* - maximum: (10^16)-1 x 10^80 -> 9999999999999999e80
|
||||
*
|
||||
* @returns {Amount}
|
||||
* @throws {Error} if offset exceeds legal ranges, meaning the amount value is bigger than supported
|
||||
* @throws {Error} if offset exceeds legal ranges, meaning the amount value is
|
||||
* bigger than supported
|
||||
*/
|
||||
|
||||
Amount.prototype.canonicalize = function(roundingMode) {
|
||||
if (this._is_native) {
|
||||
this._value = this._value.round(6, BigNumber.ROUND_DOWN);
|
||||
} else {
|
||||
if (roundingMode) {
|
||||
var value = this._value;
|
||||
this._value = BigNumber.withRoundingMode(roundingMode, function() {
|
||||
return new BigNumber(value.toPrecision(16));
|
||||
});
|
||||
} else if (roundingMode) {
|
||||
this._value = new BigNumber(this._value.toPrecision(16, roundingMode));
|
||||
} else {
|
||||
this._value = new BigNumber(this._value.toPrecision(16));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Amount.prototype._check_limits = function() {
|
||||
if (!Amount.strict_mode) {
|
||||
return this;
|
||||
}
|
||||
if (this._value.isNaN() || this._value.isZero()) {
|
||||
return this;
|
||||
}
|
||||
@@ -376,7 +384,7 @@ Amount.prototype._copy = function(value) {
|
||||
Amount.prototype.compareTo = function(to) {
|
||||
var toAmount = Amount.from_json(to);
|
||||
if (!this.is_comparable(toAmount)) {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
return this._value.comparedTo(toAmount._value);
|
||||
};
|
||||
@@ -430,7 +438,9 @@ Amount.prototype.is_valid = function() {
|
||||
};
|
||||
|
||||
Amount.prototype.is_valid_full = function() {
|
||||
return this.is_valid() && this._currency.is_valid() && this._issuer.is_valid();
|
||||
return this.is_valid()
|
||||
&& this._currency.is_valid()
|
||||
&& this._issuer.is_valid();
|
||||
};
|
||||
|
||||
Amount.prototype.is_zero = function() {
|
||||
@@ -457,11 +467,15 @@ Amount.prototype.negate = function() {
|
||||
* 100 => 100000000/XRP
|
||||
*
|
||||
*
|
||||
* The regular expression below matches above cases, broken down for better understanding:
|
||||
* The regular expression below matches above cases, broken down for better
|
||||
* understanding:
|
||||
*
|
||||
* ([A-z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
|
||||
* $ // end of string
|
||||
* // either 3 letter alphabetic currency-code or 3 digit numeric currency-code.
|
||||
* // See ISO 4217
|
||||
* ([A-z]{3}|[0-9]{3})
|
||||
*
|
||||
* // end of string
|
||||
* $
|
||||
*/
|
||||
|
||||
Amount.prototype.parse_human = function(j, opts) {
|
||||
@@ -473,7 +487,9 @@ Amount.prototype.parse_human = function(j, opts) {
|
||||
var value;
|
||||
var currency;
|
||||
|
||||
var words = j.split(' ').filter(function(word) { return word !== ''; });
|
||||
var words = j.split(' ').filter(function(word) {
|
||||
return word !== '';
|
||||
});
|
||||
|
||||
function isNumber(s) {
|
||||
return isFinite(s) && s !== '' && s !== null;
|
||||
@@ -487,7 +503,7 @@ Amount.prototype.parse_human = function(j, opts) {
|
||||
value = words[0].slice(0, -3);
|
||||
currency = words[0].slice(-3);
|
||||
if (!(isNumber(value) && currency.match(currency_RE))) {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
}
|
||||
} else if (words.length === 2) {
|
||||
@@ -501,10 +517,10 @@ Amount.prototype.parse_human = function(j, opts) {
|
||||
value = words[0];
|
||||
currency = words[1];
|
||||
} else {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
} else {
|
||||
return Amount.NaN();
|
||||
return new Amount(NaN);
|
||||
}
|
||||
|
||||
currency = currency.toUpperCase();
|
||||
@@ -539,27 +555,29 @@ Amount.prototype.parse_issuer = function(issuer) {
|
||||
* Prices involving demurraging currencies are tricky, since they depend on the
|
||||
* base and counter currencies.
|
||||
*
|
||||
* @param quality {String} 8 hex bytes quality or 32 hex bytes BookDirectory
|
||||
* @param {String} quality 8 hex bytes quality or 32 hex bytes BookDirectory
|
||||
* index.
|
||||
* @param counterCurrency {Currency|String} Currency of the resulting Amount
|
||||
* @param {Currency|String} counterCurrency currency of the resulting Amount
|
||||
* object.
|
||||
* @param counterIssuer {Issuer|String} Issuer of the resulting Amount object.
|
||||
* @param opts Additional options
|
||||
* @param opts.inverse {Boolean} If true, return the inverse of the price
|
||||
* @param {Issuer|String} counterIssuer Issuer of the resulting Amount object.
|
||||
* @param {Object} opts Additional options
|
||||
* @param {Boolean} opts.inverse If true, return the inverse of the price
|
||||
* encoded in the quality.
|
||||
* @param opts.base_currency {Currency|String} The other currency. This plays a
|
||||
* @param {Currency|String} opts.base_currency The other currency. This plays a
|
||||
* role with interest-bearing or demurrage currencies. In that case the
|
||||
* demurrage has to be applied when the quality is decoded, otherwise the
|
||||
* price will be false.
|
||||
* @param opts.reference_date {Date|Number} Date based on which demurrage/interest
|
||||
* should be applied. Can be given as JavaScript Date or int for Ripple epoch.
|
||||
* @param opts.xrp_as_drops {Boolean} Whether XRP amount should be treated as
|
||||
* @param {Date|Number} opts.reference_date Date based on which
|
||||
* demurrage/interest should be applied. Can be given as JavaScript Date or int
|
||||
* for Ripple epoch.
|
||||
* @param {Boolean} opts.xrp_as_drops Whether XRP amount should be treated as
|
||||
* drops. When the base currency is XRP, the quality is calculated in drops.
|
||||
* For human use however, we want to think of 1000000 drops as 1 XRP and
|
||||
* prices as per-XRP instead of per-drop.
|
||||
* @return {Amount} self
|
||||
*/
|
||||
Amount.prototype.parse_quality = function(quality, counterCurrency, counterIssuer, opts)
|
||||
{
|
||||
Amount.prototype.parse_quality =
|
||||
function(quality, counterCurrency, counterIssuer, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
var baseCurrency = Currency.from_json(opts.base_currency);
|
||||
@@ -614,7 +632,8 @@ Amount.prototype.parse_quality = function(quality, counterCurrency, counterIssue
|
||||
|
||||
this._set_value(nativeAdjusted);
|
||||
|
||||
if (opts.reference_date && baseCurrency.is_valid() && baseCurrency.has_interest()) {
|
||||
if (opts.reference_date && baseCurrency.is_valid()
|
||||
&& baseCurrency.has_interest()) {
|
||||
var interest = baseCurrency.get_interest_at(opts.reference_date);
|
||||
this._set_value(this._value.dividedBy(interest.toString()));
|
||||
}
|
||||
@@ -634,7 +653,8 @@ Amount.prototype.parse_number = function(n) {
|
||||
Amount.prototype.parse_json = function(j) {
|
||||
switch (typeof j) {
|
||||
case 'string':
|
||||
// .../.../... notation is not a wire format. But allowed for easier testing.
|
||||
// .../.../... notation is not a wire format. But allowed for easier
|
||||
// testing.
|
||||
var m = j.match(/^([^/]+)\/([^/]+)(?:\/(.+))?$/);
|
||||
|
||||
if (m) {
|
||||
@@ -687,14 +707,13 @@ Amount.prototype.parse_json = function(j) {
|
||||
// - float = with precision 6
|
||||
// XXX Improvements: disallow leading zeros.
|
||||
Amount.prototype.parse_native = function(j) {
|
||||
if (typeof j === 'string' && j.match(/^-?\d*(\.\d{0,6})?$/)) {
|
||||
if (j && typeof j === 'string' && !isNaN(j)) {
|
||||
if (j.indexOf('.') >= 0) {
|
||||
throw new Error('Native amounts must be specified in integer drops');
|
||||
}
|
||||
var value = new BigNumber(j);
|
||||
this._is_native = true;
|
||||
if (j.indexOf('.') >= 0) {
|
||||
this._set_value(value);
|
||||
} else {
|
||||
this._set_value(value.dividedBy(Amount.bi_xns_unit));
|
||||
}
|
||||
} else {
|
||||
this._set_value(new BigNumber(NaN));
|
||||
}
|
||||
@@ -748,8 +767,10 @@ Amount.prototype.to_text = function() {
|
||||
// Use e notation.
|
||||
// XXX Clamp output.
|
||||
return sign + mantissa.toString() + 'e' + offset.toString();
|
||||
} else {
|
||||
var val = '000000000000000000000000000' + mantissa.toString()
|
||||
}
|
||||
|
||||
var val = '000000000000000000000000000'
|
||||
+ mantissa.toString()
|
||||
+ '00000000000000000000000';
|
||||
var pre = val.substring(0, offset + 43);
|
||||
var post = val.substring(offset + 43);
|
||||
@@ -758,8 +779,6 @@ Amount.prototype.to_text = function() {
|
||||
|
||||
return sign + (s_pre ? s_pre[0] : '0')
|
||||
+ (s_post ? '.' + post.substring(0, 1 + post.length - s_post[0].length) : '');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -770,7 +789,7 @@ Amount.prototype.to_text = function() {
|
||||
* User should not store amount objects after the interest is applied. This is
|
||||
* intended by display functions such as toHuman().
|
||||
*
|
||||
* @param referenceDate {Date|Number} Date based on which demurrage/interest
|
||||
* @param {Date|Number} referenceDate Date based on which demurrage/interest
|
||||
* should be applied. Can be given as JavaScript Date or int for Ripple epoch.
|
||||
* @return {Amount} The amount with interest applied.
|
||||
*/
|
||||
@@ -788,21 +807,23 @@ Amount.prototype.applyInterest = function(referenceDate) {
|
||||
* @example
|
||||
* var pretty = amount.to_human({precision: 2});
|
||||
*
|
||||
* @param opts Options for formatter.
|
||||
* @param opts.precision {Number} Max. number of digits after decimal point.
|
||||
* @param opts.min_precision {Number} Min. number of digits after dec. point.
|
||||
* @param opts.skip_empty_fraction {Boolean} Don't show fraction if it is zero,
|
||||
* @param {Object} opts Options for formatter.
|
||||
* @param {Number} opts.precision Max. number of digits after decimal point.
|
||||
* @param {Number} opts.min_precision Min. number of digits after dec. point.
|
||||
* @param {Boolean} opts.skip_empty_fraction Don't show fraction if it is zero,
|
||||
* even if min_precision is set.
|
||||
* @param opts.max_sig_digits {Number} Maximum number of significant digits.
|
||||
* @param {Number} opts.max_sig_digits Maximum number of significant digits.
|
||||
* Will cut fractional part, but never integer part.
|
||||
* @param opts.group_sep {Boolean|String} Whether to show a separator every n
|
||||
* @param {Boolean|String} opts.group_sep Whether to show a separator every n
|
||||
* digits, if a string, that value will be used as the separator. Default: ','
|
||||
* @param opts.group_width {Number} How many numbers will be grouped together,
|
||||
* @param {Number} opts.group_width How many numbers will be grouped together,
|
||||
* default: 3.
|
||||
* @param opts.signed {Boolean|String} Whether negative numbers will have a
|
||||
* @param {Boolean|String} opts.signed Whether negative numbers will have a
|
||||
* prefix. If String, that string will be used as the prefix. Default: '-'
|
||||
* @param opts.reference_date {Date|Number} Date based on which demurrage/interest
|
||||
* should be applied. Can be given as JavaScript Date or int for Ripple epoch.
|
||||
* @param {Date|Number} opts.reference_date Date based on which
|
||||
* demurrage/interest should be applied. Can be given as JavaScript Date or int
|
||||
* for Ripple epoch.
|
||||
* @return {String} amount string
|
||||
*/
|
||||
Amount.prototype.to_human = function(opts) {
|
||||
opts = opts || {};
|
||||
@@ -811,14 +832,17 @@ Amount.prototype.to_human = function(opts) {
|
||||
return 'NaN';
|
||||
}
|
||||
|
||||
/* eslint-disable consistent-this */
|
||||
// Apply demurrage/interest
|
||||
var ref = this;
|
||||
/* eslint-enable consistent-this */
|
||||
|
||||
if (opts.reference_date) {
|
||||
ref = this.applyInterest(opts.reference_date);
|
||||
}
|
||||
|
||||
var isNegative = ref._value.isNegative();
|
||||
var valueString = ref._value.abs().toString();
|
||||
var valueString = ref._value.abs().toFixed();
|
||||
var parts = valueString.split('.');
|
||||
var int_part = parts[0];
|
||||
var fraction_part = parts.length === 2 ? parts[1] : '';
|
||||
@@ -854,7 +878,9 @@ Amount.prototype.to_human = function(opts) {
|
||||
|
||||
// Don't count leading zeros in the fractional part if the integer part is
|
||||
// zero.
|
||||
var sig_frac = int_is_zero ? fraction_part.replace(/^0*/, '') : fraction_part;
|
||||
var sig_frac = int_is_zero
|
||||
? fraction_part.replace(/^0*/, '')
|
||||
: fraction_part;
|
||||
digits += sig_frac.length;
|
||||
|
||||
// Now we calculate where we are compared to the maximum
|
||||
@@ -911,17 +937,19 @@ Amount.prototype.to_human_full = function(opts) {
|
||||
Amount.prototype.to_json = function() {
|
||||
if (this._is_native) {
|
||||
return this.to_text();
|
||||
} else {
|
||||
}
|
||||
|
||||
var amount_json = {
|
||||
value: this.to_text(),
|
||||
currency: this._currency.has_interest() ?
|
||||
this._currency.to_hex() : this._currency.to_json()
|
||||
};
|
||||
|
||||
if (this._issuer.is_valid()) {
|
||||
amount_json.issuer = this._issuer.to_json();
|
||||
}
|
||||
|
||||
return amount_json;
|
||||
}
|
||||
};
|
||||
|
||||
Amount.prototype.to_text_full = function(opts) {
|
||||
@@ -961,7 +989,10 @@ Amount.prototype.not_equals_why = function(d, ignore_issuer) {
|
||||
return 'Non-XRP currency differs.';
|
||||
}
|
||||
if (!ignore_issuer && !this._issuer.equals(d._issuer)) {
|
||||
return 'Non-XRP issuer differs: ' + d._issuer.to_json() + '/' + this._issuer.to_json();
|
||||
return 'Non-XRP issuer differs: '
|
||||
+ d._issuer.to_json()
|
||||
+ '/'
|
||||
+ this._issuer.to_json();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
'use strict';
|
||||
var _ = require('lodash');
|
||||
var sjcl = require('./utils').sjcl;
|
||||
var utils = require('./utils');
|
||||
var extend = require('extend');
|
||||
var convertBase = require('./baseconverter');
|
||||
|
||||
var Base = {};
|
||||
|
||||
@@ -22,121 +25,47 @@ extend(Base, {
|
||||
});
|
||||
|
||||
function sha256(bytes) {
|
||||
return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
||||
}
|
||||
|
||||
function sha256hash(bytes) {
|
||||
return sha256(sha256(bytes));
|
||||
}
|
||||
|
||||
function divmod58(number, startAt) {
|
||||
var remainder = 0;
|
||||
for (var i = startAt; i < number.length; i++) {
|
||||
var digit256 = number[i] & 0xFF;
|
||||
var temp = remainder * 256 + digit256;
|
||||
number[i] = (temp / 58);
|
||||
remainder = temp % 58;
|
||||
}
|
||||
return remainder;
|
||||
}
|
||||
|
||||
function divmod256(number58, startAt) {
|
||||
var remainder = 0;
|
||||
for (var i = startAt; i < number58.length; i++) {
|
||||
var digit58 = number58[i] & 0xFF;
|
||||
var temp = remainder * 58 + digit58;
|
||||
number58[i] = (temp / 256);
|
||||
remainder = temp % 256;
|
||||
}
|
||||
return remainder;
|
||||
return sjcl.codec.bytes.fromBits(
|
||||
sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
||||
}
|
||||
|
||||
function encodeString(alphabet, input) {
|
||||
if (input.length == 0) {
|
||||
return [];
|
||||
if (input.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// we need to copy the buffer for calc
|
||||
scratch = input.slice();
|
||||
|
||||
// Count leading zeroes.
|
||||
var zeroCount = 0;
|
||||
while (zeroCount < scratch.length &&
|
||||
scratch[zeroCount] == 0)
|
||||
++zeroCount;
|
||||
|
||||
// The actual encoding.
|
||||
var out = new Array(scratch.length * 2);
|
||||
var j = out.length;
|
||||
var startAt = zeroCount;
|
||||
|
||||
while (startAt < scratch.length) {
|
||||
var mod = divmod58(scratch, startAt);
|
||||
if (scratch[startAt] == 0) {
|
||||
++startAt;
|
||||
var leadingZeros = _.takeWhile(input, function(d) {
|
||||
return d === 0;
|
||||
});
|
||||
var 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');
|
||||
}
|
||||
out[--j] = alphabet[mod];
|
||||
}
|
||||
|
||||
// Strip extra 'r' if there are some after decoding.
|
||||
while (j < out.length && out[j] == alphabet[0]) ++j;
|
||||
// Add as many leading 'r' as there were leading zeros.
|
||||
while (--zeroCount >= 0) out[--j] = alphabet[0];
|
||||
while(j--) out.shift();
|
||||
|
||||
return out.join('');
|
||||
return alphabet[digit];
|
||||
});
|
||||
var prefix = leadingZeros.map(function() {
|
||||
return alphabet[0];
|
||||
});
|
||||
return prefix.concat(out).join('');
|
||||
}
|
||||
|
||||
function decodeString(indexes, input) {
|
||||
var isString = typeof input === 'string';
|
||||
|
||||
if (input.length == 0) {
|
||||
if (input.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
input58 = new Array(input.length);
|
||||
|
||||
// Transform the String to a base58 byte sequence
|
||||
for (var i = 0; i < input.length; ++i) {
|
||||
if (isString) {
|
||||
var c = input.charCodeAt(i);
|
||||
var input58 = input.split('').map(function(c) {
|
||||
var charCode = c.charCodeAt(0);
|
||||
if (charCode >= indexes.length || indexes[charCode] === -1) {
|
||||
throw new Error('Character ' + c + ' is not valid for encoding');
|
||||
}
|
||||
|
||||
var digit58 = -1;
|
||||
if (c >= 0 && c < 128) {
|
||||
digit58 = indexes[c];
|
||||
}
|
||||
if (digit58 < 0) {
|
||||
throw new Error("Illegal character " + c + " at " + i);
|
||||
}
|
||||
|
||||
input58[i] = digit58;
|
||||
}
|
||||
// Count leading zeroes
|
||||
var zeroCount = 0;
|
||||
while (zeroCount < input58.length && input58[zeroCount] == 0) {
|
||||
++zeroCount;
|
||||
}
|
||||
// The encoding
|
||||
out = utils.arraySet(input.length, 0);
|
||||
var j = out.length;
|
||||
|
||||
var startAt = zeroCount;
|
||||
while (startAt < input58.length) {
|
||||
var mod = divmod256(input58, startAt);
|
||||
if (input58[startAt] == 0) {
|
||||
++startAt;
|
||||
}
|
||||
out[--j] = mod;
|
||||
}
|
||||
|
||||
// Do no add extra leading zeroes, move j to first non null byte.
|
||||
while (j < out.length && (out[j] == 0)) ++j;
|
||||
|
||||
j -= zeroCount;
|
||||
while(j--) out.shift();
|
||||
|
||||
return out;
|
||||
return indexes[charCode];
|
||||
});
|
||||
var leadingZeros = _.takeWhile(input58, function(d) {
|
||||
return d === 0;
|
||||
});
|
||||
var out = convertBase(input58, 58, 256);
|
||||
return leadingZeros.concat(out);
|
||||
}
|
||||
|
||||
function Base58(alphabet) {
|
||||
@@ -152,7 +81,7 @@ function Base58(alphabet) {
|
||||
|
||||
Base.encoders = {};
|
||||
Object.keys(alphabets).forEach(function(alphabet) {
|
||||
Base.encoders[alphabet] = Base58(alphabets[alphabet]);
|
||||
Base.encoders[alphabet] = new Base58(alphabets[alphabet]);
|
||||
});
|
||||
|
||||
// --> input: big-endian array of bytes.
|
||||
@@ -165,29 +94,19 @@ Base.encode = function(input, alpha) {
|
||||
// <-- array of bytes or undefined.
|
||||
Base.decode = function(input, alpha) {
|
||||
if (typeof input !== 'string') {
|
||||
return void(0);
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return this.encoders[alpha || 'ripple'].decode(input);
|
||||
}
|
||||
catch(e) {
|
||||
return (void 0);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
Base.verify_checksum = function(bytes) {
|
||||
var computed = sha256hash(bytes.slice(0, -4)).slice(0, 4);
|
||||
var computed = sha256(sha256(bytes.slice(0, -4))).slice(0, 4);
|
||||
var checksum = bytes.slice(-4);
|
||||
var result = true;
|
||||
|
||||
for (var i=0; i<4; i++) {
|
||||
if (computed[i] !== checksum[i]) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return _.isEqual(computed, checksum);
|
||||
};
|
||||
|
||||
// --> input: Array
|
||||
@@ -214,17 +133,11 @@ Base.decode_check = function(version, input, alphabet) {
|
||||
}
|
||||
|
||||
// Multiple allowed versions
|
||||
if (Array.isArray(version)) {
|
||||
var match = false;
|
||||
|
||||
for (var i=0, l=version.length; i<l; i++) {
|
||||
match |= version[i] === buffer[0];
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
if (Array.isArray(version) && _.every(version, function(v) {
|
||||
return v !== buffer[0];
|
||||
})) {
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Base.verify_checksum(buffer)) {
|
||||
return NaN;
|
||||
|
||||
32
src/js/ripple/baseconverter.js
Normal file
32
src/js/ripple/baseconverter.js
Normal file
@@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
function normalize(digitArray) {
|
||||
while (digitArray[0] === 0) {
|
||||
digitArray.shift();
|
||||
}
|
||||
return digitArray;
|
||||
}
|
||||
|
||||
function divmod(digitArray, base, divisor) {
|
||||
var remainder = 0;
|
||||
var quotient = [];
|
||||
for (var j = 0; j < digitArray.length; j++) {
|
||||
var temp = remainder * base + parseInt(digitArray[j], 10);
|
||||
quotient.push(Math.floor(temp / divisor));
|
||||
remainder = temp % divisor;
|
||||
}
|
||||
return {quotient: normalize(quotient), remainder: remainder};
|
||||
}
|
||||
|
||||
function convertBase(digitArray, fromBase, toBase) {
|
||||
var result = [];
|
||||
var dividend = digitArray;
|
||||
while (dividend.length > 0) {
|
||||
var qr = divmod(dividend, fromBase, toBase);
|
||||
result.unshift(qr.remainder);
|
||||
dividend = qr.quotient;
|
||||
}
|
||||
return normalize(result);
|
||||
}
|
||||
|
||||
module.exports = convertBase;
|
||||
@@ -1,33 +0,0 @@
|
||||
var BigNumber = require('bignumber.js');
|
||||
var extend = require('extend');
|
||||
|
||||
function BigNumberWrapper(value, base) {
|
||||
// reset config every time a BigNumber is instantiated so that
|
||||
// these global settings won't be overridden if another file tries
|
||||
// to set them at require-time.
|
||||
BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_HALF_UP,
|
||||
DECIMAL_PLACES: 40 });
|
||||
BigNumber.call(this, value, base);
|
||||
}
|
||||
|
||||
extend(BigNumberWrapper, BigNumber); // copy class static properties
|
||||
BigNumberWrapper.prototype = BigNumber.prototype;
|
||||
|
||||
BigNumberWrapper.config = function() {
|
||||
throw new Error('BigNumber.config may only be called from bignumber.js');
|
||||
};
|
||||
|
||||
BigNumberWrapper.withRoundingMode = function(roundingMode, func) {
|
||||
var config = BigNumber.config();
|
||||
var oldRoundingMode = config.ROUNDING_MODE;
|
||||
config.ROUNDING_MODE = roundingMode;
|
||||
BigNumber.config(config);
|
||||
try {
|
||||
return func();
|
||||
} finally {
|
||||
config.ROUNDING_MODE = oldRoundingMode;
|
||||
BigNumber.config(config);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = BigNumberWrapper;
|
||||
@@ -1,13 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
/*eslint no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/
|
||||
|
||||
/**
|
||||
* Data type map.
|
||||
*
|
||||
* Mapping of type ids to data types. The type id is specified by the high
|
||||
*
|
||||
* For reference, see rippled's definition:
|
||||
* https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol/SField.cpp
|
||||
* https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol
|
||||
* /SField.cpp
|
||||
*/
|
||||
var TYPES_MAP = exports.types = [
|
||||
void(0),
|
||||
|
||||
exports.types = [
|
||||
undefined,
|
||||
|
||||
// Common
|
||||
'Int16', // 1
|
||||
@@ -20,11 +26,11 @@ var TYPES_MAP = exports.types = [
|
||||
'Account', // 8
|
||||
|
||||
// 9-13 reserved
|
||||
void(0), // 9
|
||||
void(0), // 10
|
||||
void(0), // 11
|
||||
void(0), // 12
|
||||
void(0), // 13
|
||||
undefined, // 9
|
||||
undefined, // 10
|
||||
undefined, // 11
|
||||
undefined, // 12
|
||||
undefined, // 13
|
||||
|
||||
'Object', // 14
|
||||
'Array', // 15
|
||||
@@ -151,7 +157,7 @@ var FIELDS_MAP = exports.fields = {
|
||||
8: 'RegularKey'
|
||||
},
|
||||
14: { // Object
|
||||
1: void(0), //end of Object
|
||||
1: undefined, // end of Object
|
||||
2: 'TransactionMetaData',
|
||||
3: 'CreatedNode',
|
||||
4: 'DeletedNode',
|
||||
@@ -163,7 +169,7 @@ var FIELDS_MAP = exports.fields = {
|
||||
10: 'Memo'
|
||||
},
|
||||
15: { // Array
|
||||
1: void(0), //end of Array
|
||||
1: undefined, // end of Array
|
||||
2: 'SigningAccounts',
|
||||
3: 'TxnSignatures',
|
||||
4: 'Signatures',
|
||||
@@ -204,7 +210,6 @@ Object.keys(FIELDS_MAP).forEach(function(k1) {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var REQUIRED = exports.REQUIRED = 0,
|
||||
OPTIONAL = exports.OPTIONAL = 1,
|
||||
DEFAULT = exports.DEFAULT = 2;
|
||||
@@ -229,7 +234,9 @@ exports.tx = {
|
||||
[ 'WalletSize' , OPTIONAL ],
|
||||
[ 'MessageKey' , OPTIONAL ],
|
||||
[ 'Domain' , OPTIONAL ],
|
||||
[ 'TransferRate' , OPTIONAL ]
|
||||
[ 'TransferRate' , OPTIONAL ],
|
||||
[ 'SetFlag' , OPTIONAL ],
|
||||
[ 'ClearFlag' , OPTIONAL ]
|
||||
]),
|
||||
TrustSet: [20].concat(base, [
|
||||
[ 'LimitAmount' , OPTIONAL ],
|
||||
@@ -239,13 +246,14 @@ exports.tx = {
|
||||
OfferCreate: [7].concat(base, [
|
||||
[ 'TakerPays' , REQUIRED ],
|
||||
[ 'TakerGets' , REQUIRED ],
|
||||
[ 'Expiration' , OPTIONAL ]
|
||||
[ 'Expiration' , OPTIONAL ],
|
||||
[ 'OfferSequence' , OPTIONAL ]
|
||||
]),
|
||||
OfferCancel: [8].concat(base, [
|
||||
[ 'OfferSequence' , REQUIRED ]
|
||||
]),
|
||||
SetRegularKey: [5].concat(base, [
|
||||
[ 'RegularKey' , REQUIRED ]
|
||||
[ 'RegularKey' , OPTIONAL ]
|
||||
]),
|
||||
Payment: [0].concat(base, [
|
||||
[ 'Destination' , REQUIRED ],
|
||||
@@ -271,12 +279,21 @@ exports.tx = {
|
||||
EnableFeature: [100].concat(base, [
|
||||
[ 'Feature' , REQUIRED ]
|
||||
]),
|
||||
EnableAmendment: [100].concat(base, [
|
||||
[ 'Amendment' , REQUIRED ]
|
||||
]),
|
||||
SetFee: [101].concat(base, [
|
||||
[ 'Features' , REQUIRED ],
|
||||
[ 'BaseFee' , REQUIRED ],
|
||||
[ 'ReferenceFeeUnits' , REQUIRED ],
|
||||
[ 'ReserveBase' , REQUIRED ],
|
||||
[ 'ReserveIncrement' , REQUIRED ]
|
||||
]),
|
||||
TicketCreate: [10].concat(base, [
|
||||
[ 'Target' , OPTIONAL ],
|
||||
[ 'Expiration' , OPTIONAL ]
|
||||
]),
|
||||
TicketCancel: [11].concat(base, [
|
||||
[ 'TicketID' , REQUIRED ]
|
||||
])
|
||||
};
|
||||
|
||||
@@ -414,5 +431,8 @@ exports.ter = {
|
||||
tecNO_TARGET : 138,
|
||||
tecNO_PERMISSION : 139,
|
||||
tecNO_ENTRY : 140,
|
||||
tecINSUFFICIENT_RESERVE : 141
|
||||
tecINSUFFICIENT_RESERVE : 141,
|
||||
tecNEED_MASTER_KEY : 142,
|
||||
tecDST_TAG_NEEDED : 143,
|
||||
tecINTERNAL : 144
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var extend = require('extend');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var utils = require('./utils');
|
||||
@@ -17,7 +19,6 @@ var Currency = extend(function() {
|
||||
// XXX Should support hex, C++ doesn't currently allow it.
|
||||
|
||||
this._value = NaN;
|
||||
|
||||
this._update();
|
||||
}, UInt160);
|
||||
|
||||
@@ -32,25 +33,37 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
|
||||
* Examples:
|
||||
*
|
||||
* USD => currency
|
||||
* USD - Dollar => currency with optional full currency name
|
||||
* XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate per year
|
||||
* USD - Dollar => currency with optional full currency
|
||||
* name
|
||||
* XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate
|
||||
* per year
|
||||
* XAU - Gold (-0.5%pa) => Optionally allowed full currency name
|
||||
* USD (1%pa) => US dollars with 1% effective interest per year
|
||||
* USD (1%pa) => US dollars with 1% effective interest
|
||||
* per year
|
||||
* INR - Indian Rupees => Optional full currency name with spaces
|
||||
* TYX - 30-Year Treasuries => Optional full currency with numbers and a dash
|
||||
* TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers, dash and interest rate
|
||||
* TYX - 30-Year Treasuries => Optional full currency with numbers
|
||||
* and a dash
|
||||
* TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers,
|
||||
* dash and interest rate
|
||||
*
|
||||
* The regular expression below matches above cases, broken down for better understanding:
|
||||
* The regular expression below matches above cases, broken down for better
|
||||
* understanding:
|
||||
*
|
||||
* ^\s* // start with any amount of whitespace
|
||||
* ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
|
||||
* (\s*-\s*[- \w]+) // optional full currency name following the dash after currency code,
|
||||
* full currency code can contain letters, numbers and dashes
|
||||
* (\s*\(-?\d+\.?\d*%pa\))? // optional demurrage rate, has optional - and . notation (-0.5%pa)
|
||||
* ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3
|
||||
* digit numeric currency-code. See ISO 4217
|
||||
* (\s*-\s*[- \w]+) // optional full currency name following the dash
|
||||
* after currency code, full currency code can
|
||||
* contain letters, numbers and dashes
|
||||
* (\s*\(-?\d+\.?\d*%pa\))? // optional demurrage rate, has optional - and
|
||||
* . notation (-0.5%pa)
|
||||
* \s*$ // end with any amount of whitespace
|
||||
*
|
||||
*/
|
||||
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
|
||||
|
||||
/*eslint-disable max-len*/
|
||||
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9\<\>\(\)\{\}\[\]\|\?\!\@\#\$\%\^\&]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
|
||||
/*eslint-enable max-len*/
|
||||
|
||||
Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
||||
return (new Currency()).parse_json(j, shouldInterpretXrpAsIou);
|
||||
@@ -58,39 +71,65 @@ Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
||||
|
||||
Currency.from_human = function(j, opts) {
|
||||
return (new Currency().parse_human(j, opts));
|
||||
}
|
||||
};
|
||||
|
||||
// this._value = NaN on error.
|
||||
Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
||||
this._value = NaN;
|
||||
|
||||
switch (typeof j) {
|
||||
case 'string':
|
||||
if (j instanceof Currency) {
|
||||
this._value = j.copyTo({})._value;
|
||||
this._update();
|
||||
return this;
|
||||
}
|
||||
|
||||
// if an empty string is given, fall back to XRP
|
||||
switch (typeof j) {
|
||||
case 'number':
|
||||
if (!isNaN(j)) {
|
||||
this.parse_number(j);
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
if (!j || j === '0') {
|
||||
this.parse_hex(shouldInterpretXrpAsIou ? Currency.HEX_CURRENCY_BAD : Currency.HEX_ZERO);
|
||||
// Empty string or XRP
|
||||
this.parse_hex(shouldInterpretXrpAsIou
|
||||
? Currency.HEX_CURRENCY_BAD
|
||||
: Currency.HEX_ZERO);
|
||||
break;
|
||||
}
|
||||
|
||||
if (j === '1') {
|
||||
// 'no currency'
|
||||
this.parse_hex(Currency.HEX_ONE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (/^[A-F0-9]{40}$/.test(j)) {
|
||||
// Hex format
|
||||
this.parse_hex(j);
|
||||
break;
|
||||
}
|
||||
|
||||
// match the given string to see if it's in an allowed format
|
||||
var matches = String(j).match(this.human_RE);
|
||||
var matches = j.match(this.human_RE);
|
||||
|
||||
if (matches) {
|
||||
|
||||
var currencyCode = matches[1];
|
||||
|
||||
// for the currency 'XRP' case
|
||||
// we drop everything else that could have been provided
|
||||
// e.g. 'XRP - Ripple'
|
||||
if (!currencyCode || /^(0|XRP)$/.test(currencyCode)) {
|
||||
this.parse_hex(shouldInterpretXrpAsIou ? Currency.HEX_CURRENCY_BAD : Currency.HEX_ZERO);
|
||||
this.parse_hex(shouldInterpretXrpAsIou
|
||||
? Currency.HEX_CURRENCY_BAD
|
||||
: Currency.HEX_ZERO);
|
||||
|
||||
// early break, we can't have interest on XRP
|
||||
break;
|
||||
}
|
||||
|
||||
// the full currency is matched as it is part of the valid currency format, but not stored
|
||||
// the full currency is matched as it is part of the valid currency
|
||||
// format, but not stored
|
||||
// var full_currency = matches[2] || '';
|
||||
var interest = matches[3] || '';
|
||||
|
||||
@@ -117,12 +156,14 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
||||
currencyData[2] = currencyCode.charCodeAt(1) & 0xff;
|
||||
currencyData[3] = currencyCode.charCodeAt(2) & 0xff;
|
||||
|
||||
// byte 5-8 are for reference date, but should always be 0 so we won't fill it
|
||||
// byte 5-8 are for reference date, but should always be 0 so we
|
||||
// won't fill it
|
||||
|
||||
// byte 9-16 are for the interest
|
||||
percentage = parseFloat(percentage[0]);
|
||||
|
||||
// the interest or demurrage is expressed as a yearly (per annum) value
|
||||
// the interest or demurrage is expressed as a yearly (per annum)
|
||||
// value
|
||||
var secondsPerYear = 31536000; // 60 * 60 * 24 * 365
|
||||
|
||||
// Calculating the interest e-fold
|
||||
@@ -135,7 +176,8 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
||||
currencyData[8 + i] = bytes[i] & 0xff;
|
||||
}
|
||||
|
||||
// the last 4 bytes are reserved for future use, so we won't fill those
|
||||
// the last 4 bytes are reserved for future use, so we won't fill
|
||||
// those
|
||||
|
||||
} else {
|
||||
currencyData[12] = currencyCode.charCodeAt(0) & 0xff;
|
||||
@@ -144,21 +186,6 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
||||
}
|
||||
|
||||
this.parse_bytes(currencyData);
|
||||
} else {
|
||||
this.parse_hex(j);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
if (!isNaN(j)) {
|
||||
this.parse_number(j);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if (j instanceof Currency) {
|
||||
this._value = j.copyTo({})._value;
|
||||
this._update();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -166,7 +193,6 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Currency.prototype.parse_human = function(j) {
|
||||
return this.parse_json(j);
|
||||
};
|
||||
@@ -176,6 +202,7 @@ Currency.prototype.parse_human = function(j) {
|
||||
*
|
||||
* You should never need to call this.
|
||||
*/
|
||||
|
||||
Currency.prototype._update = function() {
|
||||
var bytes = this.to_bytes();
|
||||
|
||||
@@ -183,7 +210,7 @@ Currency.prototype._update = function() {
|
||||
var isZeroExceptInStandardPositions = true;
|
||||
|
||||
if (!bytes) {
|
||||
return 'XRP';
|
||||
return;
|
||||
}
|
||||
|
||||
this._native = false;
|
||||
@@ -193,7 +220,8 @@ Currency.prototype._update = function() {
|
||||
this._iso_code = '';
|
||||
|
||||
for (var i = 0; i < 20; i++) {
|
||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || bytes[i]===0);
|
||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
|
||||
&& (i === 12 || i === 13 || i === 14 || bytes[i] === 0);
|
||||
}
|
||||
|
||||
if (isZeroExceptInStandardPositions) {
|
||||
@@ -201,7 +229,7 @@ Currency.prototype._update = function() {
|
||||
+ String.fromCharCode(bytes[13])
|
||||
+ String.fromCharCode(bytes[14]);
|
||||
|
||||
if (this._iso_code === '\0\0\0') {
|
||||
if (this._iso_code === '\u0000\u0000\u0000') {
|
||||
this._native = true;
|
||||
this._iso_code = 'XRP';
|
||||
}
|
||||
@@ -230,7 +258,8 @@ Currency.prototype.parse_bytes = function(byte_array) {
|
||||
var isZeroExceptInStandardPositions = true;
|
||||
|
||||
for (var i=0; i<20; i++) {
|
||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || byte_array[0]===0)
|
||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
|
||||
&& (i===12 || i===13 || i===14 || byte_array[0]===0)
|
||||
}
|
||||
|
||||
if (isZeroExceptInStandardPositions) {
|
||||
@@ -260,20 +289,25 @@ Currency.prototype.is_native = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether this currency is an interest-bearing/demurring currency.
|
||||
* @return {Boolean} whether this currency is an interest-bearing currency
|
||||
*/
|
||||
|
||||
Currency.prototype.has_interest = function() {
|
||||
return this._type === 1 && !isNaN(this._interest_start) && !isNaN(this._interest_period);
|
||||
return this._type === 1
|
||||
&& !isNaN(this._interest_start)
|
||||
&& !isNaN(this._interest_period);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param referenceDate - number of seconds since the Ripple Epoch (0:00 on January 1, 2000 UTC)
|
||||
* used to calculate the interest over provided interval
|
||||
* pass in one years worth of seconds to ge the yearly interest
|
||||
* @returns {number} - interest for provided interval, can be negative for demurred currencies
|
||||
* @param {number} referenceDate number of seconds since the Ripple Epoch
|
||||
* (0:00 on January 1, 2000 UTC) used to calculate the
|
||||
* interest over provided interval pass in one years
|
||||
* worth of seconds to ge the yearly interest
|
||||
* @returns {number} interest for provided interval, can be negative for
|
||||
* demurred currencies
|
||||
*/
|
||||
Currency.prototype.get_interest_at = function(referenceDate, decimals) {
|
||||
Currency.prototype.get_interest_at = function(referenceDate) {
|
||||
if (!this.has_interest()) {
|
||||
return 0;
|
||||
}
|
||||
@@ -288,14 +322,16 @@ Currency.prototype.get_interest_at = function(referenceDate, decimals) {
|
||||
}
|
||||
|
||||
// calculate interest by e-fold number
|
||||
return Math.exp((referenceDate - this._interest_start) / this._interest_period);
|
||||
return Math.exp((referenceDate - this._interest_start)
|
||||
/ this._interest_period);
|
||||
};
|
||||
|
||||
Currency.prototype.get_interest_percentage_at = function(referenceDate, decimals) {
|
||||
Currency.prototype.get_interest_percentage_at
|
||||
= function(referenceDate, decimals) {
|
||||
var interest = this.get_interest_at(referenceDate, decimals);
|
||||
|
||||
// convert to percentage
|
||||
var interest = (interest*100)-100;
|
||||
interest = (interest * 100) - 100;
|
||||
var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
|
||||
|
||||
// round to two decimals behind the dot
|
||||
@@ -317,27 +353,34 @@ Currency.prototype.to_json = function(opts) {
|
||||
return 'XRP';
|
||||
}
|
||||
|
||||
var opts = opts || {};
|
||||
if (!opts) {
|
||||
opts = {};
|
||||
}
|
||||
|
||||
var currency;
|
||||
var fullName = opts && opts.full_name ? ' - ' + opts.full_name : '';
|
||||
opts.show_interest = opts.show_interest !== void(0) ? opts.show_interest : this.has_interest();
|
||||
opts.show_interest = opts.show_interest !== undefined
|
||||
? opts.show_interest
|
||||
: this.has_interest();
|
||||
|
||||
if (!opts.force_hex && /^[A-Z0-9]{3}$/.test(this._iso_code)) {
|
||||
currency = this._iso_code + fullName;
|
||||
if (opts.show_interest) {
|
||||
var decimals = !isNaN(opts.decimals) ? opts.decimals : void(0);
|
||||
var interestPercentage = this.has_interest() ? this.get_interest_percentage_at(this._interest_start + 3600 * 24 * 365, decimals) : 0;
|
||||
var decimals = !isNaN(opts.decimals) ? opts.decimals : undefined;
|
||||
var interestPercentage = this.has_interest()
|
||||
? this.get_interest_percentage_at(
|
||||
this._interest_start + 3600 * 24 * 365, decimals
|
||||
)
|
||||
: 0;
|
||||
currency += ' (' + interestPercentage + '%pa)';
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Fallback to returning the raw currency hex
|
||||
currency = this.to_hex();
|
||||
|
||||
// XXX This is to maintain backwards compatibility, but it is very, very odd
|
||||
// behavior, so we should deprecate it and get rid of it as soon as
|
||||
// XXX This is to maintain backwards compatibility, but it is very, very
|
||||
// odd behavior, so we should deprecate it and get rid of it as soon as
|
||||
// possible.
|
||||
if (currency === Currency.HEX_ONE) {
|
||||
currency = 1;
|
||||
@@ -357,5 +400,3 @@ Currency.prototype.get_iso = function() {
|
||||
};
|
||||
|
||||
exports.Currency = Currency;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use strict';
|
||||
exports.Remote = require('./remote').Remote;
|
||||
exports.Request = require('./request').Request;
|
||||
exports.Amount = require('./amount').Amount;
|
||||
@@ -20,6 +21,7 @@ exports.Wallet = require('./wallet');
|
||||
exports.Ledger = require('./ledger').Ledger;
|
||||
exports.TransactionQueue = require('./transactionqueue').TransactionQueue;
|
||||
exports.RangeSet = require('./rangeset').RangeSet;
|
||||
exports.convertBase = require('./baseconverter');
|
||||
|
||||
// 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
|
||||
@@ -34,8 +36,8 @@ exports.types = require('./serializedtypes');
|
||||
exports.config = require('./config');
|
||||
|
||||
// camelCase to under_scored API conversion
|
||||
function attachUnderscored(c) {
|
||||
var o = exports[c];
|
||||
function attachUnderscored(name) {
|
||||
var o = exports[name];
|
||||
|
||||
Object.keys(o.prototype).forEach(function(key) {
|
||||
var UPPERCASE = /([A-Z]{1})[a-z]+/g;
|
||||
@@ -50,7 +52,7 @@ function attachUnderscored(c) {
|
||||
|
||||
o.prototype[underscored] = o.prototype[key];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
['Remote',
|
||||
'Request',
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Logging functionality for ripple-lib and any applications built on it.
|
||||
*
|
||||
* @param {String} namespace logging prefix
|
||||
* @return {Void} this function does not return...
|
||||
*/
|
||||
function Log(namespace) {
|
||||
if (!namespace) {
|
||||
@@ -7,11 +12,11 @@ function Log(namespace) {
|
||||
} else if (Array.isArray(namespace)) {
|
||||
this._namespace = namespace;
|
||||
} else {
|
||||
this._namespace = [''+namespace];
|
||||
this._namespace = [String(namespace)];
|
||||
}
|
||||
|
||||
this._prefix = this._namespace.concat(['']).join(': ');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sub-logger.
|
||||
@@ -24,6 +29,9 @@ function Log(namespace) {
|
||||
*
|
||||
* log.info('connection successful');
|
||||
* // prints: 'server: connection successful'
|
||||
*
|
||||
* @param {String} namespace logging prefix
|
||||
* @return {Log} sub logger
|
||||
*/
|
||||
Log.prototype.sub = function(namespace) {
|
||||
var subNamespace = this._namespace.slice();
|
||||
@@ -43,9 +51,9 @@ Log.prototype._setParent = function(parentLogger) {
|
||||
|
||||
Log.makeLevel = function(level) {
|
||||
return function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
args[0] = this._prefix + args[0];
|
||||
Log.engine.logObject.apply(Log, args);
|
||||
Log.engine.logObject.apply(Log, [level].concat(args[0], [args.slice(2)]));
|
||||
};
|
||||
};
|
||||
|
||||
@@ -54,6 +62,44 @@ Log.prototype.info = Log.makeLevel(2);
|
||||
Log.prototype.warn = Log.makeLevel(3);
|
||||
Log.prototype.error = Log.makeLevel(4);
|
||||
|
||||
/**
|
||||
* @param {String} message
|
||||
* @param {Array} details
|
||||
* @return {Array} prepared log info
|
||||
*/
|
||||
|
||||
function getLogInfo(message, args) {
|
||||
return [
|
||||
// Timestamp
|
||||
'[' + new Date().toISOString() + ']',
|
||||
message,
|
||||
'--',
|
||||
// Location
|
||||
(new Error()).stack.split('\n')[4].replace(/^\s+/, ''),
|
||||
'\n'
|
||||
].concat(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} log level
|
||||
* @param {Array} log info
|
||||
*/
|
||||
|
||||
function logMessage(logLevel, args) {
|
||||
switch (logLevel) {
|
||||
case 1:
|
||||
case 2:
|
||||
console.log.apply(console, args);
|
||||
break;
|
||||
case 3:
|
||||
console.warn.apply(console, args);
|
||||
break;
|
||||
case 4:
|
||||
console.error.apply(console, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic logging connector.
|
||||
*
|
||||
@@ -61,20 +107,33 @@ Log.prototype.error = Log.makeLevel(4);
|
||||
* implementations. This is the logging engine used in Node.js.
|
||||
*/
|
||||
var BasicLogEngine = {
|
||||
logObject: function logObject(msg) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
logObject: function logObject(level, message, args) {
|
||||
args = args.map(function(arg) {
|
||||
return JSON.stringify(arg, null, 2);
|
||||
});
|
||||
|
||||
args.unshift(msg);
|
||||
args.unshift('[' + new Date().toISOString() + ']');
|
||||
|
||||
console.log.apply(console, args);
|
||||
logMessage(level, getLogInfo(message, args));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Log engine for browser consoles.
|
||||
*
|
||||
* Browsers tend to have better consoles that support nicely formatted
|
||||
* JavaScript objects. This connector passes objects through to the logging
|
||||
* function without any stringification.
|
||||
*/
|
||||
var InteractiveLogEngine = {
|
||||
logObject: function(level, message, args) {
|
||||
args = args.map(function(arg) {
|
||||
return /MSIE/.test(navigator.userAgent)
|
||||
? JSON.stringify(arg, null, 2)
|
||||
: arg;
|
||||
});
|
||||
|
||||
logMessage(level, getLogInfo(message, args));
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Null logging connector.
|
||||
*
|
||||
@@ -85,10 +144,12 @@ var NullLogEngine = {
|
||||
logObject: function() {}
|
||||
};
|
||||
|
||||
Log.engine = NullLogEngine;
|
||||
|
||||
if (console && console.log) {
|
||||
if (typeof window !== 'undefined' && typeof console !== 'undefined') {
|
||||
Log.engine = InteractiveLogEngine;
|
||||
} else if (typeof console !== 'undefined' && console.log) {
|
||||
Log.engine = BasicLogEngine;
|
||||
} else {
|
||||
Log.engine = NullLogEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
var exports = module.exports = require('./log.js');
|
||||
|
||||
/**
|
||||
* Log engine for browser consoles.
|
||||
*
|
||||
* Browsers tend to have better consoles that support nicely formatted
|
||||
* JavaScript objects. This connector passes objects through to the logging
|
||||
* function without any stringification.
|
||||
*/
|
||||
var InteractiveLogEngine = {
|
||||
logObject: function (msg, obj) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
args = args.map(function(arg) {
|
||||
if (/MSIE/.test(navigator.userAgent)) {
|
||||
return JSON.stringify(arg, null, 2);
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
});
|
||||
|
||||
args.unshift(msg);
|
||||
args.unshift('[' + new Date().toISOString() + ']');
|
||||
|
||||
console.log.apply(console, args);
|
||||
}
|
||||
};
|
||||
|
||||
if (window.console && window.console.log) {
|
||||
exports.Log.engine = InteractiveLogEngine;
|
||||
}
|
||||
@@ -131,7 +131,6 @@ Meta.prototype.getNodes = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Meta.prototype.getAffectedAccounts = function(from) {
|
||||
if (this._affectedAccounts) {
|
||||
return this._affectedAccounts;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// Interface to manage connections to rippled servers
|
||||
//
|
||||
// - We never send binary data.
|
||||
@@ -19,7 +21,6 @@ var async = require('async');
|
||||
var lodash = require('lodash');
|
||||
var Server = require('./server').Server;
|
||||
var Request = require('./request').Request;
|
||||
var Server = require('./server').Server;
|
||||
var Amount = require('./amount').Amount;
|
||||
var Currency = require('./currency').Currency;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
@@ -47,24 +48,24 @@ function Remote(opts) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
var opts = opts || { };
|
||||
opts = opts || { };
|
||||
|
||||
Object.keys(Remote.DEFAULTS).forEach(function(config) {
|
||||
if (opts.hasOwnProperty(config)) {
|
||||
this[config] = opts[config];
|
||||
Object.keys(Remote.DEFAULTS).forEach(function(option) {
|
||||
if (opts.hasOwnProperty(option)) {
|
||||
this[option] = opts[option];
|
||||
} else {
|
||||
this[config] = Remote.DEFAULTS[config];
|
||||
this[option] = Remote.DEFAULTS[option];
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.state = 'offline'; // 'online', 'offline'
|
||||
this._server_fatal = false; // server exited
|
||||
this._stand_alone = void(0);
|
||||
this._testnet = void(0);
|
||||
this._stand_alone = undefined;
|
||||
this._testnet = undefined;
|
||||
|
||||
this._ledger_current_index = void(0);
|
||||
this._ledger_hash = void(0);
|
||||
this._ledger_time = void(0);
|
||||
this._ledger_current_index = undefined;
|
||||
this._ledger_hash = undefined;
|
||||
this._ledger_time = undefined;
|
||||
|
||||
this._connection_count = 0;
|
||||
this._connected = false;
|
||||
@@ -81,7 +82,7 @@ function Remote(opts) {
|
||||
}
|
||||
|
||||
this._servers = [ ];
|
||||
this._primary_server = void(0);
|
||||
this._primary_server = undefined;
|
||||
|
||||
// Cache information for accounts.
|
||||
// DEPRECATED, will be removed
|
||||
@@ -174,7 +175,7 @@ function Remote(opts) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this.on('newListener', function(event) {
|
||||
listenersModified('add', event);
|
||||
@@ -183,7 +184,7 @@ function Remote(opts) {
|
||||
this.on('removeListener', function(event) {
|
||||
listenersModified('remove', event);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
util.inherits(Remote, EventEmitter);
|
||||
|
||||
@@ -217,7 +218,10 @@ Remote.flags = {
|
||||
RequireDestTag: 0x00020000, // require a DestinationTag for payments
|
||||
RequireAuth: 0x00040000, // require a authorization to hold IOUs
|
||||
DisallowXRP: 0x00080000, // disallow sending XRP
|
||||
DisableMaster: 0x00100000 // force regular key
|
||||
DisableMaster: 0x00100000, // force regular key
|
||||
DefaultRipple: 0x00800000,
|
||||
NoFreeze: 0x00200000, // permanently disallowed freezing trustlines
|
||||
GlobalFreeze: 0x00400000 // trustlines globally frozen
|
||||
},
|
||||
// Offer
|
||||
offer: {
|
||||
@@ -249,7 +253,7 @@ Remote.from_config = function(obj, trace) {
|
||||
remote.setSecret(accountInfo.account, accountInfo.secret);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (config.accounts) {
|
||||
Object.keys(config.accounts).forEach(initializeAccount);
|
||||
@@ -361,7 +365,7 @@ Remote.prototype.setServerFatal = function() {
|
||||
*/
|
||||
|
||||
Remote.prototype.setTrace = function(trace) {
|
||||
this.trace = (trace === void(0) || trace);
|
||||
this.trace = (trace === undefined || trace);
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -390,7 +394,7 @@ Remote.prototype.addServer = function(opts) {
|
||||
|
||||
function serverMessage(data) {
|
||||
self._handleMessage(data, server);
|
||||
};
|
||||
}
|
||||
|
||||
server.on('message', serverMessage);
|
||||
|
||||
@@ -406,7 +410,7 @@ Remote.prototype.addServer = function(opts) {
|
||||
if (self._connection_count === self._servers.length) {
|
||||
self.emit('ready');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
server.on('connect', serverConnect);
|
||||
|
||||
@@ -415,7 +419,7 @@ Remote.prototype.addServer = function(opts) {
|
||||
if (self._connection_count === 0) {
|
||||
self._setState('offline');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
server.on('disconnect', serverDisconnect);
|
||||
|
||||
@@ -438,8 +442,6 @@ Remote.prototype.reconnect = function() {
|
||||
this._servers.forEach(function(server) {
|
||||
server.reconnect();
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -479,7 +481,9 @@ Remote.prototype.disconnect = function(callback) {
|
||||
throw new Error('No servers available, not disconnecting');
|
||||
}
|
||||
|
||||
var callback = (typeof callback === 'function') ? callback : function(){};
|
||||
if (typeof callback !== 'function') {
|
||||
callback = function() {};
|
||||
}
|
||||
|
||||
this._should_connect = false;
|
||||
|
||||
@@ -633,6 +637,7 @@ Remote.prototype._handleTransaction = function(message, server) {
|
||||
}, this);
|
||||
} else {
|
||||
// Transaction could be from proposed transaction stream
|
||||
// XX
|
||||
['Account', 'Destination'].forEach(function(prop) {
|
||||
if (this._accounts[message.transaction[prop]]) {
|
||||
this._accounts[message.transaction[prop]].notify(message);
|
||||
@@ -862,7 +867,7 @@ Remote.prototype.requestLedger = function(options, callback) {
|
||||
case 'expand':
|
||||
case 'transactions':
|
||||
case 'accounts':
|
||||
request.message[o] = true;
|
||||
request.message[o] = options[o] ? true : false;
|
||||
break;
|
||||
case 'ledger':
|
||||
request.selectLedger(options.ledger);
|
||||
@@ -936,9 +941,12 @@ Remote.prototype.requestLedgerCurrent = function(callback) {
|
||||
* Get the contents of a specified ledger
|
||||
*
|
||||
* @param {Object} options
|
||||
* @property {Boolean} [options.binary] - Flag which determines if rippled returns binary or parsed JSON
|
||||
* @property {String|Number} [options.ledger] - Hash or sequence of a ledger to get contents for
|
||||
* @property {Number} [options.limit] - Number of contents to retrieve from the ledger
|
||||
* @property {Boolean} [options.binary]- Flag which determines if rippled
|
||||
* returns binary or parsed JSON
|
||||
* @property {String|Number} [options.ledger] - Hash or sequence of a ledger
|
||||
* to get contents for
|
||||
* @property {Number} [options.limit] - Number of contents to retrieve
|
||||
* from the ledger
|
||||
* @property {Function} callback
|
||||
*
|
||||
* @callback
|
||||
@@ -965,7 +973,7 @@ Remote.prototype.requestLedgerData = function(options, callback) {
|
||||
async.setImmediate(function() {
|
||||
next(null, Remote.parseBinaryLedgerData(ledgerData));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function complete(err, state) {
|
||||
if (err) {
|
||||
@@ -974,7 +982,7 @@ Remote.prototype.requestLedgerData = function(options, callback) {
|
||||
res.state = state;
|
||||
request.emit('state', res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async.mapSeries(res.state, iterator, complete);
|
||||
});
|
||||
@@ -1110,7 +1118,8 @@ Remote.prototype.requestUnsubscribe = function(streams, callback) {
|
||||
* @return {Request} request
|
||||
*/
|
||||
|
||||
Remote.prototype.requestTransactionEntry = function(hash, ledgerHash, callback) {
|
||||
Remote.prototype.requestTransactionEntry =
|
||||
function(hash, ledgerHash, callback) {
|
||||
// If not trusted, need to check proof, maybe talk packet protocol.
|
||||
// utils.assert(this.trusted);
|
||||
var request = new Request(this, 'transaction_entry');
|
||||
@@ -1119,7 +1128,7 @@ Remote.prototype.requestTransactionEntry = function(hash, ledgerHash, callback)
|
||||
ledgerHash = hash.ledger || hash.ledger_hash || hash.ledger_index;
|
||||
hash = hash.hash || hash.tx || hash.transaction;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1151,7 +1160,8 @@ Remote.prototype.requestTransactionEntry = function(hash, ledgerHash, callback)
|
||||
*
|
||||
* @param {Object|String} hash
|
||||
* @property {String} hash.hash - Transaction hash
|
||||
* @property {Boolean} [hash.binary=true] - Flag which determines if rippled returns binary or parsed JSON
|
||||
* @property {Boolean} [hash.binary=true] - Flag which determines if rippled
|
||||
* returns binary or parsed JSON
|
||||
* @param [Function] callback
|
||||
* @return {Request} request
|
||||
*/
|
||||
@@ -1162,7 +1172,7 @@ Remote.prototype.requestTx = function(hash, callback) {
|
||||
|
||||
if (typeof hash === 'string') {
|
||||
options = {hash: hash};
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
} else {
|
||||
options = hash;
|
||||
@@ -1219,7 +1229,7 @@ Remote.accountRequest = function(type, options, callback) {
|
||||
limit = options.limit;
|
||||
marker = options.marker;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1387,15 +1397,15 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
||||
|
||||
options.binary = options.binary !== false;
|
||||
|
||||
if (options.min_ledger !== void(0)) {
|
||||
if (options.min_ledger !== undefined) {
|
||||
options.ledger_index_min = options.min_ledger;
|
||||
}
|
||||
|
||||
if (options.max_ledger !== void(0)) {
|
||||
if (options.max_ledger !== undefined) {
|
||||
options.ledger_index_max = options.max_ledger;
|
||||
}
|
||||
|
||||
if (options.binary && options.parseBinary === void(0)) {
|
||||
if (options.binary && options.parseBinary === undefined) {
|
||||
options.parseBinary = true;
|
||||
}
|
||||
|
||||
@@ -1428,7 +1438,7 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
||||
async.setImmediate(function() {
|
||||
next(null, Remote.parseBinaryAccountTransaction(transaction));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function complete(err, transactions) {
|
||||
if (err) {
|
||||
@@ -1437,7 +1447,7 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
||||
res.transactions = transactions;
|
||||
request.emit('transactions', res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async.mapSeries(res.transactions, iterator, complete);
|
||||
});
|
||||
@@ -1494,9 +1504,12 @@ Remote.parseBinaryTransaction = function(transaction) {
|
||||
tx_result.meta = meta;
|
||||
tx_result.validated = transaction.validated;
|
||||
|
||||
if (typeof meta.DeliveredAmount === 'string' || typeof meta.DeliveredAmount === 'object') {
|
||||
switch (typeof meta.DeliveredAmount) {
|
||||
case 'string':
|
||||
case 'object':
|
||||
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
switch (typeof tx_obj.Amount) {
|
||||
case 'string':
|
||||
case 'object':
|
||||
@@ -1548,7 +1561,7 @@ Remote.prototype.requestTxHistory = function(start, callback) {
|
||||
if (typeof start === 'object') {
|
||||
start = start.start;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1588,7 +1601,7 @@ Remote.prototype.requestBookOffers = function(gets, pays, taker, callback) {
|
||||
ledger = options.ledger;
|
||||
limit = options.limit;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1654,7 +1667,7 @@ Remote.prototype.requestWalletAccounts = function(seed, callback) {
|
||||
if (typeof seed === 'object') {
|
||||
seed = seed.seed;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1682,7 +1695,7 @@ Remote.prototype.requestSign = function(secret, tx_json, callback) {
|
||||
tx_json = secret.tx_json;
|
||||
secret = secret.secret;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1747,7 +1760,7 @@ Remote.prototype._serverPrepareSubscribe = function(server, callback) {
|
||||
self._handleLedgerClosed(message, server);
|
||||
|
||||
self.emit('subscribed');
|
||||
};
|
||||
}
|
||||
|
||||
request.on('error', function(err) {
|
||||
if (self.trace) {
|
||||
@@ -1775,13 +1788,15 @@ Remote.prototype._serverPrepareSubscribe = function(server, callback) {
|
||||
|
||||
Remote.prototype.ledgerAccept =
|
||||
Remote.prototype.requestLedgerAccept = function(callback) {
|
||||
/* eslint-disable consistent-return */
|
||||
var request = new Request(this, 'ledger_accept');
|
||||
|
||||
if (!this._stand_alone) {
|
||||
// XXX This should emit error on the request
|
||||
this.emit('error', new RippleError('notStandAlone'));
|
||||
return;
|
||||
}
|
||||
|
||||
var request = new Request(this, 'ledger_accept');
|
||||
|
||||
this.once('ledger_closed', function(ledger) {
|
||||
request.emit('ledger_closed', ledger);
|
||||
});
|
||||
@@ -1790,6 +1805,7 @@ Remote.prototype.requestLedgerAccept = function(callback) {
|
||||
request.request();
|
||||
|
||||
return request;
|
||||
/* eslint-enable consistent-return */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1799,13 +1815,14 @@ Remote.prototype.requestLedgerAccept = function(callback) {
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Remote.accountRootRequest = function(type, responseFilter, account, ledger, callback) {
|
||||
Remote.accountRootRequest =
|
||||
function(type, responseFilter, account, ledger, callback) {
|
||||
if (typeof account === 'object') {
|
||||
callback = ledger;
|
||||
ledger = account.ledger;
|
||||
account = account.account;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1841,7 +1858,7 @@ Remote.accountRootRequest = function(type, responseFilter, account, ledger, call
|
||||
Remote.prototype.requestAccountBalance = function() {
|
||||
function responseFilter(message) {
|
||||
return Amount.from_json(message.node.Balance);
|
||||
};
|
||||
}
|
||||
|
||||
var args = Array.prototype.concat.apply(
|
||||
['account_balance', responseFilter],
|
||||
@@ -1864,7 +1881,7 @@ Remote.prototype.requestAccountBalance = function() {
|
||||
Remote.prototype.requestAccountFlags = function() {
|
||||
function responseFilter(message) {
|
||||
return message.node.Flags;
|
||||
};
|
||||
}
|
||||
|
||||
var args = Array.prototype.concat.apply(
|
||||
['account_flags', responseFilter],
|
||||
@@ -1887,7 +1904,7 @@ Remote.prototype.requestAccountFlags = function() {
|
||||
Remote.prototype.requestOwnerCount = function() {
|
||||
function responseFilter(message) {
|
||||
return message.node.OwnerCount;
|
||||
};
|
||||
}
|
||||
|
||||
var args = Array.prototype.concat.apply(
|
||||
['owner_count', responseFilter],
|
||||
@@ -1949,7 +1966,8 @@ Remote.prototype.findAccount = function(accountID) {
|
||||
*/
|
||||
|
||||
Remote.prototype.pathFind =
|
||||
Remote.prototype.createPathFind = function(src_account, dst_account, dst_amount, src_currencies) {
|
||||
Remote.prototype.createPathFind =
|
||||
function(src_account, dst_account, dst_amount, src_currencies) {
|
||||
if (typeof src_account === 'object') {
|
||||
var options = src_account;
|
||||
src_currencies = options.src_currencies;
|
||||
@@ -1957,7 +1975,7 @@ Remote.prototype.createPathFind = function(src_account, dst_account, dst_amount,
|
||||
dst_account = options.dst_account;
|
||||
src_account = options.src_account;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -1990,7 +2008,8 @@ Remote.prepareTrade = function(currency, issuer) {
|
||||
*/
|
||||
|
||||
Remote.prototype.book =
|
||||
Remote.prototype.createOrderBook = function(currency_gets, issuer_gets, currency_pays, issuer_pays) {
|
||||
Remote.prototype.createOrderBook =
|
||||
function(currency_gets, issuer_gets, currency_pays, issuer_pays) {
|
||||
if (typeof currency_gets === 'object') {
|
||||
var options = currency_gets;
|
||||
issuer_pays = options.issuer_pays;
|
||||
@@ -1998,7 +2017,7 @@ Remote.prototype.createOrderBook = function(currency_gets, issuer_gets, currency
|
||||
issuer_gets = options.issuer_gets;
|
||||
currency_gets = options.currency_gets;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -2032,11 +2051,11 @@ Remote.prototype.createOrderBook = function(currency_gets, issuer_gets, currency
|
||||
|
||||
Remote.prototype.accountSeq =
|
||||
Remote.prototype.getAccountSequence = function(account, advance) {
|
||||
var account = UInt160.json_rewrite(account);
|
||||
account = UInt160.json_rewrite(account);
|
||||
var accountInfo = this.accounts[account];
|
||||
|
||||
if (!accountInfo) {
|
||||
return;
|
||||
return NaN;
|
||||
}
|
||||
|
||||
var seq = accountInfo.seq;
|
||||
@@ -2056,7 +2075,7 @@ Remote.prototype.getAccountSequence = function(account, advance) {
|
||||
|
||||
Remote.prototype.setAccountSequence =
|
||||
Remote.prototype.setAccountSeq = function(account, sequence) {
|
||||
var account = UInt160.json_rewrite(account);
|
||||
account = UInt160.json_rewrite(account);
|
||||
|
||||
if (!this.accounts.hasOwnProperty(account)) {
|
||||
this.accounts[account] = { };
|
||||
@@ -2081,7 +2100,7 @@ Remote.prototype.accountSeqCache = function(account, ledger, callback) {
|
||||
ledger = options.ledger;
|
||||
account = options.account;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -2099,13 +2118,13 @@ Remote.prototype.accountSeqCache = function(account, ledger, callback) {
|
||||
account_info.seq = seq;
|
||||
|
||||
request.emit('success_cache', message);
|
||||
};
|
||||
}
|
||||
|
||||
function accountRootError(message) {
|
||||
delete account_info.caching_seq_request;
|
||||
|
||||
request.emit('error_cache', message);
|
||||
};
|
||||
}
|
||||
|
||||
if (!request) {
|
||||
request = this.requestLedgerEntry('account_root');
|
||||
@@ -2129,7 +2148,7 @@ Remote.prototype.accountSeqCache = function(account, ledger, callback) {
|
||||
*/
|
||||
|
||||
Remote.prototype.dirtyAccountRoot = function(account) {
|
||||
var account = UInt160.json_rewrite(account);
|
||||
account = UInt160.json_rewrite(account);
|
||||
delete this.ledgers.current.account_root[account];
|
||||
};
|
||||
|
||||
@@ -2140,7 +2159,8 @@ Remote.prototype.dirtyAccountRoot = function(account) {
|
||||
* @param {String|Number} options.ledger
|
||||
* @param {String} [options.account] - Required unless using options.index
|
||||
* @param {Number} [options.sequence] - Required unless using options.index
|
||||
* @param {String} [options.index] - Required only if options.account and options.sequence not provided
|
||||
* @param {String} [options.index] - Required only if options.account and
|
||||
* options.sequence not provided
|
||||
*
|
||||
* @callback
|
||||
* @param {Error} error
|
||||
@@ -2181,7 +2201,8 @@ Remote.prototype.requestOffer = function(options, callback) {
|
||||
* @return {Request}
|
||||
*/
|
||||
|
||||
Remote.prototype.requestRippleBalance = function(account, issuer, currency, ledger, callback) {
|
||||
Remote.prototype.requestRippleBalance =
|
||||
function(account, issuer, currency, ledger, callback) {
|
||||
if (typeof account === 'object') {
|
||||
var options = account;
|
||||
callback = issuer;
|
||||
@@ -2190,7 +2211,7 @@ Remote.prototype.requestRippleBalance = function(account, issuer, currency, ledg
|
||||
issuer = options.issuer;
|
||||
account = options.account;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -2238,7 +2259,7 @@ Remote.prototype.requestRippleBalance = function(account, issuer, currency, ledg
|
||||
? node.HighQualityOut
|
||||
: node.LowQualityOut)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
request.once('success', rippleState);
|
||||
request.callback(callback, 'ripple_state');
|
||||
@@ -2270,7 +2291,8 @@ Remote.prepareCurrencies = function(currency) {
|
||||
* @return {Request}
|
||||
*/
|
||||
|
||||
Remote.prototype.requestRipplePathFind = function(src_account, dst_account, dst_amount, src_currencies, callback) {
|
||||
Remote.prototype.requestRipplePathFind =
|
||||
function(src_account, dst_account, dst_amount, src_currencies, callback) {
|
||||
if (typeof src_account === 'object') {
|
||||
var options = src_account;
|
||||
callback = dst_account;
|
||||
@@ -2279,7 +2301,7 @@ Remote.prototype.requestRipplePathFind = function(src_account, dst_account, dst_
|
||||
dst_account = options.dst_account;
|
||||
src_account = options.src_account;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -2307,7 +2329,8 @@ Remote.prototype.requestRipplePathFind = function(src_account, dst_account, dst_
|
||||
* @return {Request}
|
||||
*/
|
||||
|
||||
Remote.prototype.requestPathFindCreate = function(src_account, dst_account, dst_amount, src_currencies, callback) {
|
||||
Remote.prototype.requestPathFindCreate =
|
||||
function(src_account, dst_account, dst_amount, src_currencies, callback) {
|
||||
if (typeof src_account === 'object') {
|
||||
var options = src_account;
|
||||
callback = dst_account;
|
||||
@@ -2316,7 +2339,7 @@ Remote.prototype.requestPathFindCreate = function(src_account, dst_account, dst_
|
||||
dst_account = options.dst_account;
|
||||
src_account = options.src_account;
|
||||
} else {
|
||||
console.error('DEPRECATED: First argument to request constructor should be'
|
||||
log.warn('DEPRECATED: First argument to request constructor should be'
|
||||
+ ' an object containing request properties');
|
||||
}
|
||||
|
||||
@@ -2380,7 +2403,7 @@ Remote.prototype.requestUnlAdd = function(address, comment, callback) {
|
||||
|
||||
if (comment) {
|
||||
// note is not specified anywhere, should remove?
|
||||
request.message.comment = void(0);
|
||||
request.message.comment = undefined;
|
||||
}
|
||||
|
||||
request.callback(callback);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Type definitions for binary format.
|
||||
*
|
||||
@@ -8,23 +10,27 @@
|
||||
|
||||
var assert = require('assert');
|
||||
var extend = require('extend');
|
||||
var GlobalBigNumber = require('bignumber.js');
|
||||
var Amount = require('./amount').Amount;
|
||||
var Currency = require('./currency').Currency;
|
||||
var binformat = require('./binformat');
|
||||
var utils = require('./utils');
|
||||
var sjcl = utils.sjcl;
|
||||
var BigNumber = require('./bignumber');
|
||||
var SJCL_BN = sjcl.bn;
|
||||
|
||||
var UInt128 = require('./uint128').UInt128;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var UInt256 = require('./uint256').UInt256;
|
||||
var Base = require('./base').Base;
|
||||
|
||||
var amount = require('./amount');
|
||||
var Amount = amount.Amount;
|
||||
var Currency = amount.Currency;
|
||||
var BigNumber = GlobalBigNumber.another({
|
||||
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
||||
DECIMAL_PLACES: 40
|
||||
});
|
||||
|
||||
var SerializedType = function (methods) {
|
||||
function SerializedType(methods) {
|
||||
extend(this, methods);
|
||||
};
|
||||
}
|
||||
|
||||
function isNumber(val) {
|
||||
return typeof val === 'number' && isFinite(val);
|
||||
@@ -52,9 +58,13 @@ function serializeHex(so, hexData, noLength) {
|
||||
|
||||
/**
|
||||
* parses bytes as hex
|
||||
*
|
||||
* @param {Array} byte_array bytes
|
||||
* @return {String} hex string
|
||||
*/
|
||||
function convertByteArrayToHex(byte_array) {
|
||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
|
||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array))
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
function convertHexToString(hexString) {
|
||||
@@ -62,6 +72,24 @@ function convertHexToString(hexString) {
|
||||
return sjcl.codec.utf8String.fromBits(bits);
|
||||
}
|
||||
|
||||
function sort_fields(keys) {
|
||||
function sort_field_compare(a, b) {
|
||||
var a_field_coordinates = binformat.fieldsInverseMap[a];
|
||||
var a_type_bits = a_field_coordinates[0];
|
||||
var a_field_bits = a_field_coordinates[1];
|
||||
var b_field_coordinates = binformat.fieldsInverseMap[b];
|
||||
var b_type_bits = b_field_coordinates[0];
|
||||
var b_field_bits = b_field_coordinates[1];
|
||||
|
||||
// Sort by type id first, then by field id
|
||||
return a_type_bits !== b_type_bits
|
||||
? a_type_bits - b_type_bits
|
||||
: a_field_bits - b_field_bits;
|
||||
}
|
||||
|
||||
return keys.sort(sort_field_compare);
|
||||
}
|
||||
|
||||
SerializedType.serialize_varint = function (so, val) {
|
||||
if (val < 0) {
|
||||
throw new Error('Variable integers are unsigned.');
|
||||
@@ -102,13 +130,18 @@ SerializedType.prototype.parse_varint = function (so) {
|
||||
return result;
|
||||
};
|
||||
|
||||
// In the following, we assume that the inputs are in the proper range. Is this correct?
|
||||
// In the following, we assume that the inputs are in the proper range. Is this
|
||||
// correct?
|
||||
// Helper functions for 1-, 2-, and 4-byte integers.
|
||||
|
||||
/**
|
||||
* Convert an integer value into an array of bytes.
|
||||
*
|
||||
* The result is appended to the serialized object ('so').
|
||||
*
|
||||
* @param {Number} val value
|
||||
* @param {Number} bytes byte size
|
||||
* @return {Array} byte array
|
||||
*/
|
||||
function convertIntegerToByteArray(val, bytes) {
|
||||
if (!isNumber(val)) {
|
||||
@@ -128,7 +161,8 @@ function convertIntegerToByteArray(val, bytes) {
|
||||
return newBytes;
|
||||
}
|
||||
|
||||
// Convert a certain number of bytes from the serialized object ('so') into an integer.
|
||||
// Convert a certain number of bytes from the serialized object ('so') into an
|
||||
// integer.
|
||||
function readAndSum(so, bytes) {
|
||||
var sum = 0;
|
||||
|
||||
@@ -156,6 +190,89 @@ var STInt8 = exports.Int8 = new SerializedType({
|
||||
|
||||
STInt8.id = 16;
|
||||
|
||||
function serialize(so, field_name, value) {
|
||||
// so: a byte-stream to serialize into.
|
||||
// field_name: a string for the field name ('LedgerEntryType' etc.)
|
||||
// value: the value of that field.
|
||||
var field_coordinates = binformat.fieldsInverseMap[field_name];
|
||||
var type_bits = field_coordinates[0];
|
||||
var field_bits = field_coordinates[1];
|
||||
var tag_byte = (type_bits < 16
|
||||
? type_bits << 4
|
||||
: 0) | (field_bits < 16
|
||||
? field_bits
|
||||
: 0);
|
||||
|
||||
if (field_name === 'LedgerEntryType' && typeof value === 'string') {
|
||||
value = binformat.ledger[value][0];
|
||||
}
|
||||
|
||||
if (field_name === 'TransactionResult' && typeof value === 'string') {
|
||||
value = binformat.ter[value];
|
||||
}
|
||||
|
||||
STInt8.serialize(so, tag_byte);
|
||||
|
||||
if (type_bits >= 16) {
|
||||
STInt8.serialize(so, type_bits);
|
||||
}
|
||||
|
||||
if (field_bits >= 16) {
|
||||
STInt8.serialize(so, field_bits);
|
||||
}
|
||||
|
||||
// Get the serializer class (ST...)
|
||||
var serialized_object_type;
|
||||
|
||||
if (field_name === 'Memo' && typeof value === 'object') {
|
||||
// for Memo we override the default behavior with our STMemo serializer
|
||||
serialized_object_type = exports.STMemo;
|
||||
} else {
|
||||
// for a field based on the type bits.
|
||||
serialized_object_type = exports[binformat.types[type_bits]];
|
||||
}
|
||||
|
||||
try {
|
||||
serialized_object_type.serialize(so, value);
|
||||
} catch (e) {
|
||||
e.message += ' (' + field_name + ')';
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
exports.serialize = exports.serialize_whatever = serialize;
|
||||
|
||||
// Take the serialized object, figure out what type/field it is, and return the
|
||||
// parsing of that.
|
||||
|
||||
function parse(so) {
|
||||
var tag_byte = so.read(1)[0];
|
||||
var type_bits = tag_byte >> 4;
|
||||
|
||||
if (type_bits === 0) {
|
||||
type_bits = so.read(1)[0];
|
||||
}
|
||||
|
||||
var field_bits = tag_byte & 0x0f;
|
||||
var field_name = (field_bits === 0)
|
||||
? field_name = binformat.fields[type_bits][so.read(1)[0]]
|
||||
: field_name = binformat.fields[type_bits][field_bits];
|
||||
|
||||
assert(field_name, 'Unknown field - header byte is 0x'
|
||||
+ tag_byte.toString(16));
|
||||
|
||||
// Get the parser class (ST...) for a field based on the type bits.
|
||||
var type = (field_name === 'Memo')
|
||||
? exports.STMemo
|
||||
: exports[binformat.types[type_bits]];
|
||||
|
||||
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
||||
|
||||
return [field_name, type.parse(so)]; // key, value
|
||||
}
|
||||
|
||||
exports.parse = exports.parse_whatever = parse;
|
||||
|
||||
var STInt16 = exports.Int16 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
so.append(convertIntegerToByteArray(val, 2));
|
||||
@@ -187,13 +304,13 @@ var STInt64 = exports.Int64 = new SerializedType({
|
||||
if (val < 0) {
|
||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
||||
}
|
||||
bigNumObject = new sjcl.bn(val, 10);
|
||||
bigNumObject = new SJCL_BN(val, 10);
|
||||
} else if (isString(val)) {
|
||||
if (!isHexInt64String(val)) {
|
||||
throw new Error('Not a valid hex Int64.');
|
||||
}
|
||||
bigNumObject = new sjcl.bn(val, 16);
|
||||
} else if (val instanceof sjcl.bn) {
|
||||
bigNumObject = new SJCL_BN(val, 16);
|
||||
} else if (val instanceof SJCL_BN) {
|
||||
if (!val.greaterEquals(0)) {
|
||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
||||
}
|
||||
@@ -205,7 +322,7 @@ var STInt64 = exports.Int64 = new SerializedType({
|
||||
},
|
||||
parse: function (so) {
|
||||
var bytes = so.read(8);
|
||||
return sjcl.bn.fromBits(sjcl.codec.bytes.toBits(bytes));
|
||||
return SJCL_BN.fromBits(sjcl.codec.bytes.toBits(bytes));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -262,7 +379,8 @@ var STCurrency = new SerializedType({
|
||||
var currencyData = val.to_bytes();
|
||||
|
||||
if (!currencyData) {
|
||||
throw new Error('Tried to serialize invalid/unimplemented currency type.');
|
||||
throw new Error(
|
||||
'Tried to serialize invalid/unimplemented currency type.');
|
||||
}
|
||||
|
||||
so.append(currencyData);
|
||||
@@ -272,7 +390,8 @@ var STCurrency = new SerializedType({
|
||||
var currency = Currency.from_bytes(bytes);
|
||||
// XXX Disabled check. Theoretically, the Currency class should support any
|
||||
// UInt160 value and consider it valid. But it doesn't, so for the
|
||||
// deserialization to be usable, we need to allow invalid results for now.
|
||||
// deserialization to be usable, we need to allow invalid results for
|
||||
// now.
|
||||
// if (!currency.is_valid()) {
|
||||
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
|
||||
// }
|
||||
@@ -283,6 +402,7 @@ var STCurrency = new SerializedType({
|
||||
var STAmount = exports.Amount = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
var amount = Amount.from_json(val);
|
||||
|
||||
if (!amount.is_valid()) {
|
||||
throw new Error('Not a valid Amount object.');
|
||||
}
|
||||
@@ -296,12 +416,12 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
if (amount.is_native()) {
|
||||
var valueHex = value.abs().toString(16);
|
||||
|
||||
if (value.abs().greaterThan(Amount.bi_xns_max)) {
|
||||
if (Amount.strict_mode && value.abs().greaterThan(Amount.bi_xns_max)) {
|
||||
throw new Error('Value out of bounds');
|
||||
}
|
||||
|
||||
// Enforce correct length (64 bits)
|
||||
if (valueHex.length > 16) {
|
||||
if (Amount.strict_mode && valueHex.length > 16) {
|
||||
throw new Error('Value out of bounds');
|
||||
}
|
||||
|
||||
@@ -385,7 +505,8 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
issuer: issuer.to_json(),
|
||||
value: valueString
|
||||
});
|
||||
} else {
|
||||
}
|
||||
|
||||
// native
|
||||
var integer_bytes = value_bytes.slice();
|
||||
integer_bytes[0] &= 0x3f;
|
||||
@@ -393,14 +514,12 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
var value = new BigNumber(integer_hex, 16);
|
||||
return Amount.from_json((is_negative ? '-' : '') + value.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
STAmount.id = 6;
|
||||
|
||||
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
|
||||
if (typeof val === 'string') {
|
||||
serializeHex(so, val);
|
||||
} else {
|
||||
@@ -500,19 +619,22 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
[]
|
||||
]
|
||||
|
||||
each entry has one or more of the following attributes: amount, currency, issuer.
|
||||
each entry has one or more of the following attributes:
|
||||
amount, currency, issuer.
|
||||
*/
|
||||
|
||||
var path_list = [];
|
||||
var current_path = [];
|
||||
var tag_byte;
|
||||
|
||||
/* eslint-disable no-cond-assign */
|
||||
|
||||
while ((tag_byte = so.read(1)[0]) !== this.typeEnd) {
|
||||
//TODO: try/catch this loop, and catch when we run out of data without reaching the end of the data structure.
|
||||
// TODO: try/catch this loop, and catch when we run out of data without
|
||||
// reaching the end of the data structure.
|
||||
// Now determine: is this an end, boundary, or entry-begin-tag?
|
||||
// console.log('Tag byte:', tag_byte);
|
||||
if (tag_byte === this.typeBoundary) {
|
||||
//console.log('Boundary');
|
||||
if (current_path) { // close the current path, if there is one,
|
||||
path_list.push(current_path);
|
||||
}
|
||||
@@ -521,20 +643,15 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
}
|
||||
|
||||
// It's an entry-begin tag.
|
||||
//console.log('It's an entry-begin tag.');
|
||||
var entry = {};
|
||||
var type = 0;
|
||||
|
||||
if (tag_byte & this.typeAccount) {
|
||||
//console.log('entry.account');
|
||||
/*var bta = so.read(20);
|
||||
console.log('BTA:', bta);*/
|
||||
entry.account = STHash160.parse(so);
|
||||
entry.account.set_version(Base.VER_ACCOUNT_ID);
|
||||
type = type | this.typeAccount;
|
||||
}
|
||||
if (tag_byte & this.typeCurrency) {
|
||||
//console.log('entry.currency');
|
||||
entry.currency = STCurrency.parse(so);
|
||||
if (entry.currency.to_json() === 'XRP' && !entry.currency.is_native()) {
|
||||
entry.non_native = true;
|
||||
@@ -542,22 +659,19 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
type = type | this.typeCurrency;
|
||||
}
|
||||
if (tag_byte & this.typeIssuer) {
|
||||
//console.log('entry.issuer');
|
||||
entry.issuer = STHash160.parse(so);
|
||||
// Enable and set correct type of base-58 encoding
|
||||
entry.issuer.set_version(Base.VER_ACCOUNT_ID);
|
||||
//console.log('DONE WITH ISSUER!');
|
||||
|
||||
type = type | this.typeIssuer;
|
||||
}
|
||||
|
||||
if (entry.account || entry.currency || entry.issuer) {
|
||||
entry.type = type;
|
||||
entry.type_hex = ('000000000000000' + type.toString(16)).slice(-16);
|
||||
|
||||
current_path.push(entry);
|
||||
} else {
|
||||
throw new Error('Invalid path entry'); //It must have at least something in it.
|
||||
// It must have at least something in it.
|
||||
throw new Error('Invalid path entry');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,7 +687,8 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
STPathSet.id = 18;
|
||||
|
||||
var STVector256 = exports.Vector256 = new SerializedType({
|
||||
serialize: function (so, val) { //Assume val is an array of STHash256 objects.
|
||||
serialize: function(so, val) {
|
||||
// Assume val is an array of STHash256 objects.
|
||||
SerializedType.serialize_varint(so, val.length * 32);
|
||||
for (var i = 0, l = val.length; i < l; i++) {
|
||||
STHash256.serialize(so, val[i]);
|
||||
@@ -595,7 +710,6 @@ STVector256.id = 19;
|
||||
// Internal
|
||||
exports.STMemo = new SerializedType({
|
||||
serialize: function(so, val, no_marker) {
|
||||
|
||||
var keys = [];
|
||||
|
||||
Object.keys(val).forEach(function (key) {
|
||||
@@ -615,26 +729,24 @@ exports.STMemo = new SerializedType({
|
||||
// Sort fields
|
||||
keys = sort_fields(keys);
|
||||
|
||||
for (var i=0; i<keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var value = val[key];
|
||||
serialize(so, key, value);
|
||||
}
|
||||
keys.forEach(function(key) {
|
||||
serialize(so, key, val[key]);
|
||||
});
|
||||
|
||||
if (!no_marker) {
|
||||
// Object ending marker
|
||||
STInt8.serialize(so, 0xe1);
|
||||
}
|
||||
|
||||
},
|
||||
parse: function(so) {
|
||||
var output = {};
|
||||
|
||||
while (so.peek(1)[0] !== 0xe1) {
|
||||
var keyval = parse(so);
|
||||
output[keyval[0]] = keyval[1];
|
||||
}
|
||||
|
||||
if (output.MemoType !== void(0)) {
|
||||
if (output.MemoType !== undefined) {
|
||||
try {
|
||||
var parsedType = convertHexToString(output.MemoType);
|
||||
|
||||
@@ -642,34 +754,39 @@ exports.STMemo = new SerializedType({
|
||||
output.parsed_memo_type = parsedType;
|
||||
}
|
||||
} catch (e) {
|
||||
// we don't know what's in the binary, apparently it's not a UTF-8 string
|
||||
// we don't know what's in the binary, apparently it's not a UTF-8
|
||||
// string
|
||||
// this is fine, we won't add the parsed_memo_type field
|
||||
}
|
||||
}
|
||||
|
||||
if (output.MemoFormat !== void(0)) {
|
||||
if (output.MemoFormat !== undefined) {
|
||||
try {
|
||||
output.parsed_memo_format = convertHexToString(output.MemoFormat);
|
||||
} catch (e) {
|
||||
// we don't know what's in the binary, apparently it's not a UTF-8 string
|
||||
// we don't know what's in the binary, apparently it's not a UTF-8
|
||||
// string
|
||||
// this is fine, we won't add the parsed_memo_format field
|
||||
}
|
||||
}
|
||||
|
||||
if (output.MemoData !== void(0)) {
|
||||
if (output.MemoData !== undefined) {
|
||||
|
||||
try {
|
||||
if (output.parsed_memo_format === 'json') {
|
||||
// see if we can parse JSON
|
||||
output.parsed_memo_data = JSON.parse(convertHexToString(output.MemoData));
|
||||
output.parsed_memo_data =
|
||||
JSON.parse(convertHexToString(output.MemoData));
|
||||
|
||||
} else if (output.parsed_memo_format === 'text') {
|
||||
// otherwise see if we can parse text
|
||||
output.parsed_memo_data = convertHexToString(output.MemoData);
|
||||
}
|
||||
} catch(e) {
|
||||
// we'll fail in case the content does not match what the MemoFormat described
|
||||
// this is fine, we won't add the parsed_memo_data, the user has to parse themselves
|
||||
// we'll fail in case the content does not match what the MemoFormat
|
||||
// described
|
||||
// this is fine, we won't add the parsed_memo_data, the user has to
|
||||
// parse themselves
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,98 +796,6 @@ exports.STMemo = new SerializedType({
|
||||
|
||||
});
|
||||
|
||||
exports.serialize = exports.serialize_whatever = serialize;
|
||||
|
||||
function serialize(so, field_name, value) {
|
||||
//so: a byte-stream to serialize into.
|
||||
//field_name: a string for the field name ('LedgerEntryType' etc.)
|
||||
//value: the value of that field.
|
||||
var field_coordinates = binformat.fieldsInverseMap[field_name];
|
||||
var type_bits = field_coordinates[0];
|
||||
var field_bits = field_coordinates[1];
|
||||
var tag_byte = (type_bits < 16 ? type_bits << 4 : 0) | (field_bits < 16 ? field_bits : 0);
|
||||
|
||||
if (field_name === 'LedgerEntryType' && 'string' === typeof value) {
|
||||
value = binformat.ledger[value][0];
|
||||
}
|
||||
|
||||
if (field_name === 'TransactionResult' && 'string' === typeof value) {
|
||||
value = binformat.ter[value];
|
||||
}
|
||||
|
||||
STInt8.serialize(so, tag_byte);
|
||||
|
||||
if (type_bits >= 16) {
|
||||
STInt8.serialize(so, type_bits);
|
||||
}
|
||||
|
||||
if (field_bits >= 16) {
|
||||
STInt8.serialize(so, field_bits);
|
||||
}
|
||||
|
||||
// Get the serializer class (ST...)
|
||||
var serialized_object_type;
|
||||
if (field_name === 'Memo' && typeof value === 'object') {
|
||||
// for Memo we override the default behavior with our STMemo serializer
|
||||
serialized_object_type = exports.STMemo;
|
||||
} else {
|
||||
// for a field based on the type bits.
|
||||
serialized_object_type = exports[binformat.types[type_bits]];
|
||||
}
|
||||
|
||||
try {
|
||||
serialized_object_type.serialize(so, value);
|
||||
} catch (e) {
|
||||
e.message += ' (' + field_name + ')';
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
//Take the serialized object, figure out what type/field it is, and return the parsing of that.
|
||||
exports.parse = exports.parse_whatever = parse;
|
||||
|
||||
function parse(so) {
|
||||
var tag_byte = so.read(1)[0];
|
||||
var type_bits = tag_byte >> 4;
|
||||
|
||||
if (type_bits === 0) {
|
||||
type_bits = so.read(1)[0];
|
||||
}
|
||||
|
||||
|
||||
var field_bits = tag_byte & 0x0f;
|
||||
var field_name = (field_bits === 0)
|
||||
? field_name = binformat.fields[type_bits][so.read(1)[0]]
|
||||
: field_name = binformat.fields[type_bits][field_bits];
|
||||
|
||||
assert(field_name, 'Unknown field - header byte is 0x' + tag_byte.toString(16));
|
||||
|
||||
// Get the parser class (ST...) for a field based on the type bits.
|
||||
var type = (field_name === 'Memo')
|
||||
? exports.STMemo
|
||||
: exports[binformat.types[type_bits]];
|
||||
|
||||
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
||||
|
||||
return [ field_name, type.parse(so) ]; //key, value
|
||||
}
|
||||
|
||||
function sort_fields(keys) {
|
||||
function sort_field_compare(a, b) {
|
||||
var a_field_coordinates = binformat.fieldsInverseMap[a];
|
||||
var a_type_bits = a_field_coordinates[0];
|
||||
var a_field_bits = a_field_coordinates[1];
|
||||
var b_field_coordinates = binformat.fieldsInverseMap[b];
|
||||
var b_type_bits = b_field_coordinates[0];
|
||||
var b_field_bits = b_field_coordinates[1];
|
||||
|
||||
// Sort by type id first, then by field id
|
||||
return a_type_bits !== b_type_bits ? a_type_bits - b_type_bits : a_field_bits - b_field_bits;
|
||||
}
|
||||
|
||||
return keys.sort(sort_field_compare);
|
||||
}
|
||||
|
||||
var STObject = exports.Object = new SerializedType({
|
||||
serialize: function (so, val, no_marker) {
|
||||
var keys = [];
|
||||
@@ -821,7 +846,8 @@ var STArray = exports.Array = new SerializedType({
|
||||
var keys = Object.keys(val[i]);
|
||||
|
||||
if (keys.length !== 1) {
|
||||
throw Error('Cannot serialize an array containing non-single-key objects');
|
||||
throw new Error(
|
||||
'Cannot serialize an array containing non-single-key objects');
|
||||
}
|
||||
|
||||
var field_name = keys[0];
|
||||
|
||||
@@ -134,7 +134,8 @@ Transaction.set_clear_flags = {
|
||||
asfDisableMaster: 4,
|
||||
asfAccountTxnID: 5,
|
||||
asfNoFreeze: 6,
|
||||
asfGlobalFreeze: 7
|
||||
asfGlobalFreeze: 7,
|
||||
asfDefaultRipple: 8
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
var async = require('async');
|
||||
@@ -20,7 +22,7 @@ function TransactionManager(account) {
|
||||
this._account = account;
|
||||
this._accountID = account._account_id;
|
||||
this._remote = account._remote;
|
||||
this._nextSequence = void(0);
|
||||
this._nextSequence = undefined;
|
||||
this._maxFee = this._remote.max_fee;
|
||||
this._maxAttempts = this._remote.max_attempts;
|
||||
this._submissionTimeout = this._remote.submission_timeout;
|
||||
@@ -37,7 +39,7 @@ function TransactionManager(account) {
|
||||
|
||||
function updatePendingStatus(ledger) {
|
||||
self._updatePendingStatus(ledger);
|
||||
};
|
||||
}
|
||||
|
||||
this._remote.on('ledger_closed', updatePendingStatus);
|
||||
|
||||
@@ -47,7 +49,7 @@ function TransactionManager(account) {
|
||||
// hooking back into ledger_closed
|
||||
self._remote.on('ledger_closed', updatePendingStatus);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
this._remote.on('disconnect', function() {
|
||||
self._remote.removeListener('ledger_closed', updatePendingStatus);
|
||||
@@ -56,7 +58,7 @@ function TransactionManager(account) {
|
||||
|
||||
// Query server for next account transaction sequence
|
||||
this._loadSequence();
|
||||
};
|
||||
}
|
||||
|
||||
util.inherits(TransactionManager, EventEmitter);
|
||||
|
||||
@@ -162,7 +164,8 @@ TransactionManager.prototype._transactionReceived = function(tx) {
|
||||
|
||||
if (!(submission instanceof Transaction)) {
|
||||
// The received transaction does not correlate to one submitted
|
||||
return this._pending.addReceivedId(hash, transaction);
|
||||
this._pending.addReceivedId(hash, transaction);
|
||||
return;
|
||||
}
|
||||
|
||||
// ND: A `success` handler will `finalize` this later
|
||||
@@ -197,7 +200,7 @@ TransactionManager.prototype._adjustFees = function() {
|
||||
transaction.once('presubmit', function() {
|
||||
transaction.emit('error', 'tejMaxFeeExceeded');
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
this._pending.forEach(function(transaction) {
|
||||
if (transaction._setFixedFee) {
|
||||
@@ -209,7 +212,8 @@ TransactionManager.prototype._adjustFees = function() {
|
||||
|
||||
if (Number(newFee) > self._maxFee) {
|
||||
// Max transaction fee exceeded, abort submission
|
||||
return maxFeeExceeded(transaction);
|
||||
maxFeeExceeded(transaction);
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.tx_json.Fee = newFee;
|
||||
@@ -244,6 +248,10 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
||||
assert.strictEqual(typeof ledger.ledger_index, 'number');
|
||||
|
||||
this._pending.forEach(function(transaction) {
|
||||
if (transaction.finalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ledger.ledger_index - transaction.submitIndex) {
|
||||
case 4:
|
||||
transaction.emit('missing', ledger);
|
||||
@@ -253,10 +261,6 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (transaction.finalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ledger.ledger_index > transaction.tx_json.LastLedgerSequence) {
|
||||
// Transaction must fail
|
||||
transaction.emit('error', new RippleError(
|
||||
@@ -269,42 +273,50 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
||||
TransactionManager.prototype._fillSequence = function(tx, callback) {
|
||||
var self = this;
|
||||
|
||||
function submitFill(sequence, callback) {
|
||||
var fill = self._remote.transaction();
|
||||
fill.account_set(self._accountID);
|
||||
fill.tx_json.Sequence = sequence;
|
||||
fill.once('submitted', callback);
|
||||
function submitFill(sequence, fCallback) {
|
||||
var fillTransaction = self._remote.createTransaction('AccountSet', {
|
||||
account: self._accountID
|
||||
});
|
||||
fillTransaction.tx_json.Sequence = sequence;
|
||||
|
||||
// Secrets may be set on a per-transaction basis
|
||||
if (tx._secret) {
|
||||
fill.secret(tx._secret);
|
||||
fillTransaction.secret(tx._secret);
|
||||
}
|
||||
|
||||
fill.submit();
|
||||
};
|
||||
fillTransaction.once('submitted', fCallback);
|
||||
fillTransaction.submit();
|
||||
}
|
||||
|
||||
function sequenceLoaded(err, sequence) {
|
||||
if (typeof sequence !== 'number') {
|
||||
return callback(new Error('Failed to fetch account transaction sequence'));
|
||||
log.info('fill sequence: failed to fetch account transaction sequence');
|
||||
return callback();
|
||||
}
|
||||
|
||||
var sequenceDif = tx.tx_json.Sequence - sequence;
|
||||
var sequenceDiff = tx.tx_json.Sequence - sequence;
|
||||
var submitted = 0;
|
||||
|
||||
;(function nextFill(sequence) {
|
||||
if (sequence >= tx.tx_json.Sequence) {
|
||||
return;
|
||||
}
|
||||
|
||||
submitFill(sequence, function() {
|
||||
if (++submitted === sequenceDif) {
|
||||
callback();
|
||||
} else {
|
||||
nextFill(sequence + 1);
|
||||
async.whilst(
|
||||
function() {
|
||||
return submitted < sequenceDiff;
|
||||
},
|
||||
function(asyncCallback) {
|
||||
submitFill(sequence, function(res) {
|
||||
++submitted;
|
||||
if (res.engine_result === 'tesSUCCESS') {
|
||||
self.emit('sequence_filled', err);
|
||||
}
|
||||
asyncCallback();
|
||||
});
|
||||
})(sequence);
|
||||
};
|
||||
},
|
||||
function() {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this._loadSequence(sequenceLoaded);
|
||||
};
|
||||
@@ -318,7 +330,7 @@ TransactionManager.prototype._fillSequence = function(tx, callback) {
|
||||
|
||||
TransactionManager.prototype._loadSequence = function(callback) {
|
||||
var self = this;
|
||||
var callback = (typeof callback === 'function') ? callback : function(){};
|
||||
callback = (typeof callback === 'function') ? callback : function() {};
|
||||
|
||||
function sequenceLoaded(err, sequence) {
|
||||
if (err || typeof sequence !== 'number') {
|
||||
@@ -331,7 +343,7 @@ TransactionManager.prototype._loadSequence = function(callback) {
|
||||
self._nextSequence = sequence;
|
||||
self.emit('sequence_loaded', sequence);
|
||||
callback(err, sequence);
|
||||
};
|
||||
}
|
||||
|
||||
this._account.getNextSequence(sequenceLoaded);
|
||||
};
|
||||
@@ -346,10 +358,11 @@ TransactionManager.prototype._loadSequence = function(callback) {
|
||||
|
||||
TransactionManager.prototype._handleReconnect = function(callback) {
|
||||
var self = this;
|
||||
var callback = (typeof callback === 'function') ? callback : function(){};
|
||||
callback = (typeof callback === 'function') ? callback : function() {};
|
||||
|
||||
if (!this._pending.length()) {
|
||||
return callback();
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
function handleTransactions(err, transactions) {
|
||||
@@ -372,7 +385,7 @@ TransactionManager.prototype._handleReconnect = function(callback) {
|
||||
// Resubmit pending transactions after sequence is loaded
|
||||
self._resubmit();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
var options = {
|
||||
account: this._accountID,
|
||||
@@ -410,7 +423,7 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
|
||||
self._remote.removeListener('ledger_closed', ledgerClosed);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this._remote.on('ledger_closed', ledgerClosed);
|
||||
};
|
||||
@@ -426,8 +439,16 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
|
||||
|
||||
TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
||||
var self = this;
|
||||
var ledgers = ledgers || 0;
|
||||
var pending = pending ? [ pending ] : this._pending;
|
||||
|
||||
if (ledgers && typeof ledgers !== 'number') {
|
||||
pending = ledgers;
|
||||
ledgers = 0;
|
||||
}
|
||||
|
||||
ledgers = ledgers || 0;
|
||||
pending = pending instanceof Transaction
|
||||
? [pending]
|
||||
: this.getPending().getQueue();
|
||||
|
||||
function resubmitTransaction(transaction, next) {
|
||||
if (!transaction || transaction.finalized) {
|
||||
@@ -467,7 +488,7 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
||||
});
|
||||
|
||||
self._request(transaction);
|
||||
};
|
||||
}
|
||||
|
||||
this._waitLedgers(ledgers, function() {
|
||||
async.eachSeries(pending, resubmitTransaction);
|
||||
@@ -528,8 +549,8 @@ TransactionManager.prototype._request = function(tx) {
|
||||
}
|
||||
|
||||
if (tx.attempts > 0 && !remote.local_signing) {
|
||||
var message = 'Automatic resubmission requires local signing';
|
||||
tx.emit('error', new RippleError('tejLocalSigningRequired', message));
|
||||
var errMessage = 'Automatic resubmission requires local signing';
|
||||
tx.emit('error', new RippleError('tejLocalSigningRequired', errMessage));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -542,22 +563,22 @@ TransactionManager.prototype._request = function(tx) {
|
||||
// Transaction may succeed after Sequence is updated
|
||||
self._resubmit(1, tx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function transactionRetry(message) {
|
||||
function transactionRetry() {
|
||||
// XXX This may no longer be necessary. Instead, update sequence numbers
|
||||
// after a transaction fails definitively
|
||||
self._fillSequence(tx, function() {
|
||||
self._resubmit(1, tx);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function transactionFailedLocal(message) {
|
||||
if (message.engine_result === 'telINSUF_FEE_P') {
|
||||
// Transaction may succeed after Fee is updated
|
||||
self._resubmit(1, tx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function submissionError(error) {
|
||||
// Either a tem-class error or generic server error such as tooBusy. This
|
||||
@@ -568,7 +589,7 @@ TransactionManager.prototype._request = function(tx) {
|
||||
self._nextSequence--;
|
||||
tx.emit('error', error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function submitted(message) {
|
||||
if (tx.finalized) {
|
||||
@@ -611,7 +632,7 @@ TransactionManager.prototype._request = function(tx) {
|
||||
// tem
|
||||
submissionError(message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function requestTimeout() {
|
||||
// ND: What if the response is just slow and we get a response that
|
||||
@@ -630,7 +651,7 @@ TransactionManager.prototype._request = function(tx) {
|
||||
}
|
||||
self._resubmit(1, tx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tx.submitIndex = this._remote._ledger_current_index;
|
||||
|
||||
@@ -661,10 +682,7 @@ TransactionManager.prototype._request = function(tx) {
|
||||
|
||||
tx.emit('postsubmit');
|
||||
|
||||
//XXX
|
||||
submitRequest.timeout(self._submissionTimeout, requestTimeout);
|
||||
|
||||
return submitRequest;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -675,7 +693,6 @@ TransactionManager.prototype._request = function(tx) {
|
||||
|
||||
TransactionManager.prototype.submit = function(tx) {
|
||||
var self = this;
|
||||
var remote = this._remote;
|
||||
|
||||
if (typeof this._nextSequence !== 'number') {
|
||||
// If sequence number is not yet known, defer until it is.
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var lodash = require('lodash');
|
||||
var LRU = require('lru-cache');
|
||||
var Transaction = require('./transaction').Transaction;
|
||||
|
||||
@@ -7,9 +10,9 @@ var Transaction = require('./transaction').Transaction;
|
||||
|
||||
function TransactionQueue() {
|
||||
this._queue = [ ];
|
||||
this._idCache = LRU({ max: 200 });
|
||||
this._sequenceCache = LRU({ max: 200 });
|
||||
};
|
||||
this._idCache = new LRU({max: 200});
|
||||
this._sequenceCache = new LRU({max: 200});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store received (validated) sequence
|
||||
@@ -64,16 +67,9 @@ TransactionQueue.prototype.getReceived = function(id) {
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getSubmission = function(id) {
|
||||
var result = void(0);
|
||||
|
||||
for (var i=0, tx; (tx=this._queue[i]); i++) {
|
||||
if (~tx.submittedIDs.indexOf(id)) {
|
||||
result = tx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return lodash.find(this._queue, function(tx) {
|
||||
return lodash.contains(tx.submittedIDs, id);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -83,11 +79,15 @@ TransactionQueue.prototype.getSubmission = function(id) {
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getMinLedger = function() {
|
||||
if (this.length() < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var result = Infinity;
|
||||
|
||||
for (var i=0, tx; (tx=this._queue[i]); i++) {
|
||||
if (tx.initialSubmitIndex < result) {
|
||||
result = tx.initialSubmitIndex;
|
||||
for (var i = 0; i < this.length(); i++) {
|
||||
if (this._queue[i].initialSubmitIndex < result) {
|
||||
result = this._queue[i].initialSubmitIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,4 +153,12 @@ TransactionQueue.prototype.getLength = function() {
|
||||
return this._queue.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Array} pending queue
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getQueue = function() {
|
||||
return this._queue;
|
||||
};
|
||||
|
||||
exports.TransactionQueue = TransactionQueue;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable max-len */
|
||||
'use strict';
|
||||
var assert = require('assert');
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var UInt160 = require('ripple-lib').UInt160;
|
||||
@@ -26,97 +28,103 @@ describe('Amount', function() {
|
||||
// also tested extensively in other cases
|
||||
describe('to_human', function() {
|
||||
it('12345.6789 XAU', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 XAU").to_human(), '12,345.6789');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 XAU').to_human(), '12,345.6789');
|
||||
});
|
||||
it('12345.678901234 XAU', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human(), '12,345.678901234');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human(), '12,345.678901234');
|
||||
});
|
||||
it('to human, precision -1, should be ignored, precision needs to be >= 0', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:-1}), '12,346');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: -1}), '12,346');
|
||||
});
|
||||
it('to human, precision 0', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:0}), '12,346');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 0}), '12,346');
|
||||
});
|
||||
it('to human, precision 1', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:1}), '12,345.7');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 1}), '12,345.7');
|
||||
});
|
||||
it('to human, precision 2', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:2}), '12,345.68');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 2}), '12,345.68');
|
||||
});
|
||||
it('to human, precision 3', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:3}), '12,345.679');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 3}), '12,345.679');
|
||||
});
|
||||
it('to human, precision 4', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:4}), '12,345.6789');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 4}), '12,345.6789');
|
||||
});
|
||||
it('to human, precision 5', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:5}), '12,345.67890');
|
||||
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 5}), '12,345.67890');
|
||||
});
|
||||
it('to human, precision -1, should be ignored, precision needs to be >= 0', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:-1}), '0');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: -1}), '0');
|
||||
});
|
||||
it('to human, precision 0', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:0}), '0');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 0}), '0');
|
||||
});
|
||||
it('to human, precision 1', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:1}), '0.0');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 1}), '0.0');
|
||||
});
|
||||
it('to human, precision 2', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:2}), '0.00');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 2}), '0.00');
|
||||
});
|
||||
it('to human, precision 5', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:5}), '0.00012');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 5}), '0.00012');
|
||||
});
|
||||
it('to human, precision 6', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:6}), '0.000123');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 6}), '0.000123');
|
||||
});
|
||||
it('to human, precision 16', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:16}), '0.00012345');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 16}), '0.00012345');
|
||||
});
|
||||
it('to human, precision 16, min_precision 16', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:16, min_precision:16}), '0.0001234500000000');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 16, min_precision: 16}), '0.0001234500000000');
|
||||
});
|
||||
it('to human, precision 16, min_precision 12', function() {
|
||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:16, min_precision:12}), '0.000123450000');
|
||||
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 16, min_precision: 12}), '0.000123450000');
|
||||
});
|
||||
it('to human, precision 0, first decimal 4', function() {
|
||||
assert.strictEqual(Amount.from_human("0.4 XAU").to_human({precision:0}), '0');
|
||||
assert.strictEqual(Amount.from_human('0.4 XAU').to_human({precision: 0}), '0');
|
||||
});
|
||||
it('to human, precision 0, first decimal 5', function() {
|
||||
assert.strictEqual(Amount.from_human("0.5 XAU").to_human({precision:0}), '1');
|
||||
assert.strictEqual(Amount.from_human('0.5 XAU').to_human({precision: 0}), '1');
|
||||
});
|
||||
it('to human, precision 0, first decimal 8', function() {
|
||||
assert.strictEqual(Amount.from_human("0.8 XAU").to_human({precision:0}), '1');
|
||||
assert.strictEqual(Amount.from_human('0.8 XAU').to_human({precision: 0}), '1');
|
||||
});
|
||||
it('to human, precision 0, precision 16', function() {
|
||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision:16}), '0');
|
||||
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 16}), '0');
|
||||
});
|
||||
it('to human, precision 0, precision 8, min_precision 16', function() {
|
||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision:8, min_precision:16}), '0.0000000000000000');
|
||||
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 8, min_precision: 16}), '0.0000000000000000');
|
||||
});
|
||||
it('to human, precision 0, first decimal 8', function() {
|
||||
assert.strictEqual(Amount.from_human("0.8 XAU").to_human({precision:0}), '1');
|
||||
assert.strictEqual(Amount.from_human('0.8 XAU').to_human({precision: 0}), '1');
|
||||
});
|
||||
it('to human, precision 6, min_precision 6, max_sig_digits 20', function() {
|
||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision: 6, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
||||
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 6, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
||||
});
|
||||
it('to human, precision 16, min_precision 6, max_sig_digits 20', function() {
|
||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision: 16, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
||||
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 16, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
||||
});
|
||||
it('to human rounding edge case, precision 2, 1', function() {
|
||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:1}), '1.0');
|
||||
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 1}), '1.0');
|
||||
});
|
||||
it('to human rounding edge case, precision 2, 2', function() {
|
||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:2}), '0.99');
|
||||
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 2}), '0.99');
|
||||
});
|
||||
it('to human rounding edge case, precision 2, 3', function() {
|
||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:3}), '0.99');
|
||||
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 3}), '0.99');
|
||||
});
|
||||
it('to human rounding edge case, precision 2, 3 min precision 3', function() {
|
||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:3, min_precision:3}), '0.990');
|
||||
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 3, min_precision: 3}), '0.990');
|
||||
});
|
||||
it('to human rounding edge case, precision 3, 2', function() {
|
||||
assert.strictEqual(Amount.from_human("0.999 XAU").to_human({precision:2}), '1.00');
|
||||
assert.strictEqual(Amount.from_human('0.999 XAU').to_human({precision: 2}), '1.00');
|
||||
});
|
||||
it('to human very small number', function() {
|
||||
assert.strictEqual(Amount.from_json('12e-20/USD').to_human(), '0.00000000000000000012');
|
||||
});
|
||||
it('to human very small number with precision', function() {
|
||||
assert.strictEqual(Amount.from_json('12e-20/USD').to_human({precision: 20}), '0.00000000000000000012');
|
||||
});
|
||||
});
|
||||
describe('from_human', function() {
|
||||
@@ -127,117 +135,117 @@ describe('Amount', function() {
|
||||
assert.strictEqual(Amount.from_human('USD').to_text_full(), 'NaN');
|
||||
});
|
||||
it('1 XRP', function() {
|
||||
assert.strictEqual(Amount.from_human("1 XRP").to_text_full(), '1/XRP');
|
||||
assert.strictEqual(Amount.from_human('1 XRP').to_text_full(), '1/XRP');
|
||||
});
|
||||
it('1 XRP human', function() {
|
||||
assert.strictEqual(Amount.from_human("1 XRP").to_human_full(), '1/XRP');
|
||||
assert.strictEqual(Amount.from_human('1 XRP').to_human_full(), '1/XRP');
|
||||
});
|
||||
it('1XRP human', function() {
|
||||
assert.strictEqual(Amount.from_human('1XRP').to_human_full(), '1/XRP');
|
||||
});
|
||||
it('0.1 XRP', function() {
|
||||
assert.strictEqual(Amount.from_human("0.1 XRP").to_text_full(), '0.1/XRP');
|
||||
assert.strictEqual(Amount.from_human('0.1 XRP').to_text_full(), '0.1/XRP');
|
||||
});
|
||||
it('0.1 XRP human', function() {
|
||||
assert.strictEqual(Amount.from_human("0.1 XRP").to_human_full(), '0.1/XRP');
|
||||
assert.strictEqual(Amount.from_human('0.1 XRP').to_human_full(), '0.1/XRP');
|
||||
});
|
||||
it('0.1 USD', function() {
|
||||
assert.strictEqual(Amount.from_human("0.1 USD").to_text_full(), '0.1/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('0.1 USD').to_text_full(), '0.1/USD/NaN');
|
||||
});
|
||||
it('0.1 USD human', function() {
|
||||
assert.strictEqual(Amount.from_human("0.1 USD").to_human_full(), '0.1/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('0.1 USD').to_human_full(), '0.1/USD/NaN');
|
||||
});
|
||||
it('10000 USD', function() {
|
||||
assert.strictEqual(Amount.from_human("10000 USD").to_text_full(), '10000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('10000 USD').to_text_full(), '10000/USD/NaN');
|
||||
});
|
||||
it('10000 USD human', function() {
|
||||
assert.strictEqual(Amount.from_human("10000 USD").to_human_full(), '10,000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('10000 USD').to_human_full(), '10,000/USD/NaN');
|
||||
});
|
||||
it('USD 10000', function() {
|
||||
assert.strictEqual(Amount.from_human("USD 10000").to_text_full(), '10000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('USD 10000').to_text_full(), '10000/USD/NaN');
|
||||
});
|
||||
it('USD 10000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("USD 10000").to_human_full(), '10,000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('USD 10000').to_human_full(), '10,000/USD/NaN');
|
||||
});
|
||||
it('12345.6789 XAU', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 XAU").to_text_full(), '12345.6789/XAU/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 XAU').to_text_full(), '12345.6789/XAU/NaN');
|
||||
});
|
||||
it('12345.6789 XAU human', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 XAU").to_human_full(), '12,345.6789/XAU/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 XAU').to_human_full(), '12,345.6789/XAU/NaN');
|
||||
});
|
||||
it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_text_full(), '12345.6789/XAU (-0.5%pa)/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000').to_text_full(), '12345.6789/XAU (-0.5%pa)/NaN');
|
||||
});
|
||||
it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_human_full(), '12,345.6789/XAU (-0.5%pa)/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000').to_human_full(), '12,345.6789/XAU (-0.5%pa)/NaN');
|
||||
});
|
||||
it('12345.6789 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 0000000000000000000000005553440000000000").to_text_full(), '12345.6789/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 0000000000000000000000005553440000000000').to_text_full(), '12345.6789/USD/NaN');
|
||||
});
|
||||
it('12345.6789 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 0000000000000000000000005553440000000000").to_human_full(), '12,345.6789/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 0000000000000000000000005553440000000000').to_human_full(), '12,345.6789/USD/NaN');
|
||||
});
|
||||
it('10 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("10 0000000000000000000000005553440000000000").to_text_full(), '10/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('10 0000000000000000000000005553440000000000').to_text_full(), '10/USD/NaN');
|
||||
});
|
||||
it('10 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("10 0000000000000000000000005553440000000000").to_human_full(), '10/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('10 0000000000000000000000005553440000000000').to_human_full(), '10/USD/NaN');
|
||||
});
|
||||
it('100 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("100 0000000000000000000000005553440000000000").to_text_full(), '100/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('100 0000000000000000000000005553440000000000').to_text_full(), '100/USD/NaN');
|
||||
});
|
||||
it('100 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("100 0000000000000000000000005553440000000000").to_human_full(), '100/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('100 0000000000000000000000005553440000000000').to_human_full(), '100/USD/NaN');
|
||||
});
|
||||
it('1000 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("1000 0000000000000000000000005553440000000000").to_text_full(), '1000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('1000 0000000000000000000000005553440000000000').to_text_full(), '1000/USD/NaN');
|
||||
});
|
||||
it('1000 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("1000 0000000000000000000000005553440000000000").to_human_full(), '1,000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('1000 0000000000000000000000005553440000000000').to_human_full(), '1,000/USD/NaN');
|
||||
});
|
||||
it('-100 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("-100 0000000000000000000000005553440000000000").to_text_full(), '-100/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('-100 0000000000000000000000005553440000000000').to_text_full(), '-100/USD/NaN');
|
||||
});
|
||||
it('-100 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("-100 0000000000000000000000005553440000000000").to_human_full(), '-100/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('-100 0000000000000000000000005553440000000000').to_human_full(), '-100/USD/NaN');
|
||||
});
|
||||
it('-1000 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("-1000 0000000000000000000000005553440000000000").to_text_full(), '-1000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('-1000 0000000000000000000000005553440000000000').to_text_full(), '-1000/USD/NaN');
|
||||
});
|
||||
it('-1000 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("-1000 0000000000000000000000005553440000000000").to_human_full(), '-1,000/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('-1000 0000000000000000000000005553440000000000').to_human_full(), '-1,000/USD/NaN');
|
||||
});
|
||||
it('-1000.001 0000000000000000000000005553440000000000', function() {
|
||||
assert.strictEqual(Amount.from_human("-1000.001 0000000000000000000000005553440000000000").to_text_full(), '-1000.001/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('-1000.001 0000000000000000000000005553440000000000').to_text_full(), '-1000.001/USD/NaN');
|
||||
});
|
||||
it('-1000.001 0000000000000000000000005553440000000000 human', function() {
|
||||
assert.strictEqual(Amount.from_human("-1000.001 0000000000000000000000005553440000000000").to_human_full(), '-1,000.001/USD/NaN');
|
||||
assert.strictEqual(Amount.from_human('-1000.001 0000000000000000000000005553440000000000').to_human_full(), '-1,000.001/USD/NaN');
|
||||
});
|
||||
it('XAU 12345.6789', function() {
|
||||
assert.strictEqual(Amount.from_human("XAU 12345.6789").to_text_full(), '12345.6789/XAU/NaN');
|
||||
assert.strictEqual(Amount.from_human('XAU 12345.6789').to_text_full(), '12345.6789/XAU/NaN');
|
||||
});
|
||||
it('XAU 12345.6789 human', function() {
|
||||
assert.strictEqual(Amount.from_human("XAU 12345.6789").to_human_full(), '12,345.6789/XAU/NaN');
|
||||
assert.strictEqual(Amount.from_human('XAU 12345.6789').to_human_full(), '12,345.6789/XAU/NaN');
|
||||
});
|
||||
it('101 12345.6789', function() {
|
||||
assert.strictEqual(Amount.from_human("101 12345.6789").to_text_full(), '12345.6789/101/NaN');
|
||||
assert.strictEqual(Amount.from_human('101 12345.6789').to_text_full(), '12345.6789/101/NaN');
|
||||
});
|
||||
it('101 12345.6789 human', function() {
|
||||
assert.strictEqual(Amount.from_human("101 12345.6789").to_human_full(), '12,345.6789/101/NaN');
|
||||
assert.strictEqual(Amount.from_human('101 12345.6789').to_human_full(), '12,345.6789/101/NaN');
|
||||
});
|
||||
it('12345.6789 101', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 101").to_text_full(), '12345.6789/101/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 101').to_text_full(), '12345.6789/101/NaN');
|
||||
});
|
||||
it('12345.6789 101 human', function() {
|
||||
assert.strictEqual(Amount.from_human("12345.6789 101").to_human_full(), '12,345.6789/101/NaN');
|
||||
assert.strictEqual(Amount.from_human('12345.6789 101').to_human_full(), '12,345.6789/101/NaN');
|
||||
});
|
||||
});
|
||||
describe('from_json', function() {
|
||||
it('1 XRP', function() {
|
||||
assert.strictEqual(Amount.from_json("1/XRP").to_text_full(), "1/XRP/NaN");
|
||||
assert.strictEqual(Amount.from_json('1/XRP').to_text_full(), '1/XRP/NaN');
|
||||
});
|
||||
it('1 XRP human', function() {
|
||||
assert.strictEqual(Amount.from_json("1/XRP").to_human_full(), "1/XRP/NaN");
|
||||
assert.strictEqual(Amount.from_json('1/XRP').to_human_full(), '1/XRP/NaN');
|
||||
});
|
||||
});
|
||||
describe('from_number', function() {
|
||||
@@ -302,7 +310,7 @@ describe('Amount', function() {
|
||||
assert.strictEqual(UInt160.ACCOUNT_ONE, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrBZbvji').to_json());
|
||||
});
|
||||
it('Parse mtgox export', function () {
|
||||
assert.strictEqual(config.accounts['mtgox'].account, UInt160.from_json('mtgox').to_json());
|
||||
assert.strictEqual(config.accounts.mtgox.account, UInt160.from_json('mtgox').to_json());
|
||||
});
|
||||
it('is_valid rrrrrrrrrrrrrrrrrrrrrhoLvTp', function () {
|
||||
assert(UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvTp'));
|
||||
@@ -353,31 +361,35 @@ describe('Amount', function() {
|
||||
assert.strictEqual(Amount.from_json('10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
it('Parse 800/USD/mtgox', function () {
|
||||
assert.strictEqual('800/USD/'+config.accounts['mtgox'].account, Amount.from_json('800/USD/mtgox').to_text_full());
|
||||
assert.strictEqual('800/USD/' + config.accounts.mtgox.account, Amount.from_json('800/USD/mtgox').to_text_full());
|
||||
});
|
||||
it('Parse 800/USD/mtgox human', function () {
|
||||
assert.strictEqual('800/USD/'+config.accounts['mtgox'].account, Amount.from_json('800/USD/mtgox').to_human_full());
|
||||
assert.strictEqual('800/USD/' + config.accounts.mtgox.account, Amount.from_json('800/USD/mtgox').to_human_full());
|
||||
});
|
||||
it('Parse native 0', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('0').to_text_full());
|
||||
});
|
||||
it('Parse native 0.0', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('0.0').to_text_full());
|
||||
assert.throws(function() {
|
||||
Amount.from_json('0.0');
|
||||
});
|
||||
});
|
||||
it('Parse native -0', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('-0').to_text_full());
|
||||
});
|
||||
it('Parse native -0.0', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('-0.0').to_text_full());
|
||||
assert.throws(function() {
|
||||
Amount.from_json('-0.0');
|
||||
});
|
||||
});
|
||||
it('Parse native 1000', function () {
|
||||
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_text_full());
|
||||
});
|
||||
it('Parse native 12.3', function () {
|
||||
assert.strictEqual('12.3/XRP', Amount.from_json('12.3').to_text_full());
|
||||
it('Parse native 12300000', function () {
|
||||
assert.strictEqual('12.3/XRP', Amount.from_json('12300000').to_text_full());
|
||||
});
|
||||
it('Parse native -12.3', function () {
|
||||
assert.strictEqual('-12.3/XRP', Amount.from_json('-12.3').to_text_full());
|
||||
it('Parse native -12300000', function () {
|
||||
assert.strictEqual('-12.3/XRP', Amount.from_json('-12300000').to_text_full());
|
||||
});
|
||||
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
|
||||
@@ -406,23 +418,17 @@ describe('Amount', function() {
|
||||
it('Parse native 0 human', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('0').to_human_full());
|
||||
});
|
||||
it('Parse native 0.0 human', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('0.0').to_human_full());
|
||||
});
|
||||
it('Parse native -0 human', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('-0').to_human_full());
|
||||
});
|
||||
it('Parse native -0.0 human', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('-0.0').to_human_full());
|
||||
});
|
||||
it('Parse native 1000 human', function () {
|
||||
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_human_full());
|
||||
});
|
||||
it('Parse native 12.3 human', function () {
|
||||
assert.strictEqual('12.3/XRP', Amount.from_json('12.3').to_human_full());
|
||||
it('Parse native 12300000 human', function () {
|
||||
assert.strictEqual('12.3/XRP', Amount.from_json('12300000').to_human_full());
|
||||
});
|
||||
it('Parse native -12.3 human', function () {
|
||||
assert.strictEqual('-12.3/XRP', Amount.from_json('-12.3').to_human_full());
|
||||
it('Parse native -12300000 human', function () {
|
||||
assert.strictEqual('-12.3/XRP', Amount.from_json('-12300000').to_human_full());
|
||||
});
|
||||
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh human', function () {
|
||||
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
|
||||
@@ -451,19 +457,19 @@ describe('Amount', function() {
|
||||
});
|
||||
describe('Amount to_json', function() {
|
||||
it('10 USD', function() {
|
||||
var amount = Amount.from_human("10 USD").to_json();
|
||||
assert.strictEqual("10", amount.value);
|
||||
assert.strictEqual("USD", amount.currency);
|
||||
var amount = Amount.from_human('10 USD').to_json();
|
||||
assert.strictEqual('10', amount.value);
|
||||
assert.strictEqual('USD', amount.currency);
|
||||
});
|
||||
it('10 0000000000000000000000005553440000000000', function() {
|
||||
var amount = Amount.from_human("10 0000000000000000000000005553440000000000").to_json();
|
||||
assert.strictEqual("10", amount.value);
|
||||
assert.strictEqual("USD", amount.currency);
|
||||
var amount = Amount.from_human('10 0000000000000000000000005553440000000000').to_json();
|
||||
assert.strictEqual('10', amount.value);
|
||||
assert.strictEqual('USD', amount.currency);
|
||||
});
|
||||
it('10 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() {
|
||||
var amount = Amount.from_human("10 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_json();
|
||||
assert.strictEqual("10", amount.value);
|
||||
assert.strictEqual("015841551A748AD2C1F76FF6ECB0CCCD00000000", amount.currency);
|
||||
var amount = Amount.from_human('10 015841551A748AD2C1F76FF6ECB0CCCD00000000').to_json();
|
||||
assert.strictEqual('10', amount.value);
|
||||
assert.strictEqual('015841551A748AD2C1F76FF6ECB0CCCD00000000', amount.currency);
|
||||
});
|
||||
});
|
||||
describe('Amount operations', function() {
|
||||
@@ -768,7 +774,7 @@ describe('Amount', function() {
|
||||
assert(isNaN(Amount.from_json('x').copyTo(new Amount())._value));
|
||||
});
|
||||
it('amount.copyTo zero', function() {
|
||||
assert(!(Amount.from_json(0).copyTo(new Amount())._is_negative))
|
||||
assert(!(Amount.from_json(0).copyTo(new Amount())._is_negative));
|
||||
});
|
||||
});
|
||||
describe('Amount comparisons', function() {
|
||||
@@ -790,7 +796,7 @@ describe('Amount', function() {
|
||||
});
|
||||
it('0 XRP == 0 XRP', function () {
|
||||
var a = Amount.from_json('0');
|
||||
var b = Amount.from_json('0.0');
|
||||
var b = Amount.from_json('0');
|
||||
assert(a.equals(b));
|
||||
assert(!a.not_equals_why(b));
|
||||
});
|
||||
@@ -819,8 +825,8 @@ describe('Amount', function() {
|
||||
assert(!a.not_equals_why(b));
|
||||
});
|
||||
it('1.1 XRP == 1.1 XRP', function () {
|
||||
var a = Amount.from_json('1.1');
|
||||
var b = Amount.from_json('11.0').ratio_human(10);
|
||||
var a = Amount.from_json('1100000');
|
||||
var b = Amount.from_json('11000000').ratio_human('10/XRP');
|
||||
assert(a.equals(b));
|
||||
assert(!a.not_equals_why(b));
|
||||
});
|
||||
@@ -1087,7 +1093,7 @@ describe('Amount', function() {
|
||||
describe('from_quality', function() {
|
||||
it('XRP/XRP', function () {
|
||||
assert.throws(function() {
|
||||
Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'XRP'}).to_text_full()
|
||||
Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'XRP'}).to_text_full();
|
||||
});
|
||||
});
|
||||
it('BTC/XRP', function () {
|
||||
@@ -1168,7 +1174,7 @@ describe('Amount', function() {
|
||||
});
|
||||
it('from_human with reference date', function() {
|
||||
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date: 459990264});
|
||||
demAmount.set_issuer("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
||||
demAmount.set_issuer('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(demAmount.to_text_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
it('from_json apply interest 10 XAU human', function() {
|
||||
@@ -1186,7 +1192,7 @@ describe('Amount', function() {
|
||||
});
|
||||
it('from_human with reference date human', function() {
|
||||
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date: 459990264});
|
||||
demAmount.set_issuer("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
||||
demAmount.set_issuer('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(demAmount.to_human_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
});
|
||||
@@ -1238,7 +1244,7 @@ describe('Amount', function() {
|
||||
|
||||
it('from_json exceed minimum IOU', function() {
|
||||
assert.throws(function() {
|
||||
Amount.from_json('-1e-82/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
|
||||
Amount.from_json('-1e-82/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
}, 'Exceeding min value of ' + Amount.min_value);
|
||||
});
|
||||
|
||||
@@ -1249,7 +1255,7 @@ describe('Amount', function() {
|
||||
|
||||
it('from_json exceed maximum IOU', function() {
|
||||
assert.throws(function() {
|
||||
Amount.from_json('9999999999999999e81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
|
||||
Amount.from_json('9999999999999999e81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
}, 'Exceeding max value of ' + Amount.max_value);
|
||||
});
|
||||
|
||||
|
||||
66
test/base-test.js
Normal file
66
test/base-test.js
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
var assert = require('assert');
|
||||
var Base = require('ripple-lib').Base;
|
||||
var fixtures = require('./fixtures/base58.json');
|
||||
|
||||
function digitArray(str) {
|
||||
return str.split('').map(function(d) {
|
||||
return parseInt(d, 10);
|
||||
});
|
||||
}
|
||||
|
||||
function hexToByteArray(hex) {
|
||||
var byteArray = [];
|
||||
for (var i = 0; i < hex.length / 2; i++) {
|
||||
byteArray.push(parseInt(hex.slice(2 * i, 2 * i + 2), 16));
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
describe('Base', function() {
|
||||
describe('encode_check', function() {
|
||||
it('0', function () {
|
||||
var encoded = Base.encode_check(0, digitArray('00000000000000000000'));
|
||||
assert.strictEqual(encoded, 'rrrrrrrrrrrrrrrrrrrrrhoLvTp');
|
||||
});
|
||||
it('1', function () {
|
||||
var encoded = Base.encode_check(0, digitArray('00000000000000000001'));
|
||||
assert.strictEqual(encoded, 'rrrrrrrrrrrrrrrrrrrrBZbvji');
|
||||
});
|
||||
});
|
||||
describe('decode_check', function() {
|
||||
it('rrrrrrrrrrrrrrrrrrrrrhoLvTp', function() {
|
||||
var decoded = Base.decode_check(0, 'rrrrrrrrrrrrrrrrrrrrrhoLvTp');
|
||||
assert(decoded.equals(0));
|
||||
});
|
||||
it('rrrrrrrrrrrrrrrrrrrrBZbvji', function() {
|
||||
var decoded = Base.decode_check(0, 'rrrrrrrrrrrrrrrrrrrrBZbvji');
|
||||
assert(decoded.equals(1));
|
||||
});
|
||||
});
|
||||
describe('decode-encode identity', function() {
|
||||
it('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function() {
|
||||
var decoded = Base.decode('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
var encoded = Base.encode(decoded);
|
||||
assert.strictEqual(encoded, 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
});
|
||||
describe('encode', function() {
|
||||
it('fixtures', function() {
|
||||
for (var i = 0; i < fixtures.ripple.length; i++) {
|
||||
var testCase = fixtures.ripple[i];
|
||||
var encoded = Base.encode(hexToByteArray(testCase.hex));
|
||||
assert.strictEqual(encoded, testCase.string);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('decode', function() {
|
||||
it('fixtures', function() {
|
||||
for (var i = 0; i < fixtures.ripple.length; i++) {
|
||||
var testCase = fixtures.ripple[i];
|
||||
var decoded = Base.decode(testCase.string);
|
||||
assert.deepEqual(decoded, hexToByteArray(testCase.hex));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
var assert = require('assert');
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
describe('Base58', function() {
|
||||
describe('Seed', function() {
|
||||
it('saESc82Vun7Ta5EJRzGJbrXb5HNYk', function () {
|
||||
var seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
|
||||
assert.strictEqual(seed.to_hex(), 'FF1CF838D02B2CF7B45BAC27F5F24F4F');
|
||||
});
|
||||
it('sp6iDHnmiPN7tQFHm5sCW59ax3hfE', function () {
|
||||
var seed = Seed.from_json('sp6iDHnmiPN7tQFHm5sCW59ax3hfE');
|
||||
assert.strictEqual(seed.to_hex(), '00AD8DA764C3C8AF5F9B8D51C94B9E49');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
53
test/baseconverter-test.js
Normal file
53
test/baseconverter-test.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
var assert = require('assert');
|
||||
var convertBase = require('ripple-lib').convertBase;
|
||||
|
||||
// Test cases from RFC-1924 (a joke RFC)
|
||||
var BASE85 = ('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
+ 'abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~');
|
||||
var BASE10 = BASE85.slice(0, 10);
|
||||
var BASE16 = BASE85.slice(0, 16);
|
||||
|
||||
var DATA16 = '108000000000000000080800200C417A';
|
||||
var DATA10 = '21932261930451111902915077091070067066';
|
||||
var DATA85 = '4)+k&C#VzJ4br>0wv%Yp';
|
||||
|
||||
function encode(digitArray, encoding) {
|
||||
return digitArray.map(function(i) {
|
||||
return encoding.charAt(i);
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function decode(encoded, encoding) {
|
||||
return encoded.split('').map(function(c) {
|
||||
return encoding.indexOf(c);
|
||||
});
|
||||
}
|
||||
|
||||
function convertBaseEncoded(value, fromEncoding, toEncoding) {
|
||||
var digitArray = decode(value, fromEncoding);
|
||||
var converted = convertBase(digitArray, fromEncoding.length,
|
||||
toEncoding.length);
|
||||
return encode(converted, toEncoding);
|
||||
}
|
||||
|
||||
describe('convertBase', function() {
|
||||
it('DEC -> HEX', function () {
|
||||
assert.strictEqual(convertBaseEncoded(DATA10, BASE10, BASE16), DATA16);
|
||||
});
|
||||
it('HEX -> DEC', function () {
|
||||
assert.strictEqual(convertBaseEncoded(DATA16, BASE16, BASE10), DATA10);
|
||||
});
|
||||
it('DEC -> B85', function () {
|
||||
assert.strictEqual(convertBaseEncoded(DATA10, BASE10, BASE85), DATA85);
|
||||
});
|
||||
it('HEX -> B85', function () {
|
||||
assert.strictEqual(convertBaseEncoded(DATA16, BASE16, BASE85), DATA85);
|
||||
});
|
||||
it('B85 -> DEC', function () {
|
||||
assert.strictEqual(convertBaseEncoded(DATA85, BASE85, BASE10), DATA10);
|
||||
});
|
||||
it('B85 -> HEX', function () {
|
||||
assert.strictEqual(convertBaseEncoded(DATA85, BASE85, BASE16), DATA16);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
/*eslint-disable */
|
||||
|
||||
var assert = require('assert');
|
||||
var currency = require('ripple-lib').Currency;
|
||||
var timeUtil = require('ripple-lib').utils.time;
|
||||
@@ -54,6 +56,16 @@ describe('Currency', function() {
|
||||
assert(r.is_valid());
|
||||
assert.strictEqual('1D2', r.to_json());
|
||||
});
|
||||
it('from_json("1").to_human()', function() {
|
||||
var r = currency.from_json('1');
|
||||
assert(r.is_valid());
|
||||
assert.strictEqual(1, r.to_json());
|
||||
});
|
||||
it('from_json("#$%").to_human()', function() {
|
||||
var r = currency.from_json('#$%');
|
||||
assert(r.is_valid());
|
||||
assert.strictEqual('0000000000000000000000002324250000000000', r.to_json());
|
||||
});
|
||||
it('from_json("XAU").to_json() hex', function() {
|
||||
var r = currency.from_json("XAU");
|
||||
assert.strictEqual('0000000000000000000000005841550000000000', r.to_json({force_hex: true}));
|
||||
|
||||
5
test/fixtures/addresses.js
vendored
Normal file
5
test/fixtures/addresses.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports.ACCOUNT = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||
module.exports.OTHER_ACCOUNT = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo';
|
||||
module.exports.THIRD_ACCOUNT = 'rwBYyfufTzk77zUSKEu4MvixfarC35av1J';
|
||||
module.exports.FOURTH_ACCOUNT = 'rJnZ4YHCUsHvQu7R6mZohevKJDHFzVD6Zr';
|
||||
module.exports.ISSUER = 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM';
|
||||
141
test/fixtures/base58.json
vendored
Normal file
141
test/fixtures/base58.json
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"ripple": [
|
||||
{
|
||||
"hex": "",
|
||||
"string": ""
|
||||
},
|
||||
{
|
||||
"hex": "61",
|
||||
"string": "pg"
|
||||
},
|
||||
{
|
||||
"hex": "626262",
|
||||
"string": "2sgV"
|
||||
},
|
||||
{
|
||||
"hex": "636363",
|
||||
"string": "2PNi"
|
||||
},
|
||||
{
|
||||
"hex": "73696d706c792061206c6f6e6720737472696e67",
|
||||
"string": "pcEuFj68N1S8n9qHX1tmKpCCFLvp"
|
||||
},
|
||||
{
|
||||
"hex": "00eb15231dfceb60925886b67d065299925915aeb172c06647",
|
||||
"string": "r4Srf52g9jJgTHDrVXjvLUN8ZuQsiJDN9L"
|
||||
},
|
||||
{
|
||||
"hex": "516b6fcd0f",
|
||||
"string": "wB8LTmg"
|
||||
},
|
||||
{
|
||||
"hex": "bf4f89001e670274dd",
|
||||
"string": "sSNosLWLoP8tU"
|
||||
},
|
||||
{
|
||||
"hex": "572e4794",
|
||||
"string": "sNE7fm"
|
||||
},
|
||||
{
|
||||
"hex": "ecac89cad93923c02321",
|
||||
"string": "NJDM3diCXwauyw"
|
||||
},
|
||||
{
|
||||
"hex": "10c8511e",
|
||||
"string": "Rtnzm"
|
||||
},
|
||||
{
|
||||
"hex": "00000000000000000000",
|
||||
"string": "rrrrrrrrrr"
|
||||
},
|
||||
{
|
||||
"hex": "801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e",
|
||||
"string": "nHxrnHEGyeFpUCPx1JKepCXJ1UV8nDN5yoeGGEaJZjGbTR8qC5D"
|
||||
},
|
||||
{
|
||||
"hex": "003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187",
|
||||
"string": "ra7jcY4BG9GTKhuqpCfyYNbu5CqUzoLMGS"
|
||||
}
|
||||
],
|
||||
"bitcoin": [
|
||||
{
|
||||
"hex": "",
|
||||
"string": ""
|
||||
},
|
||||
{
|
||||
"hex": "61",
|
||||
"string": "2g"
|
||||
},
|
||||
{
|
||||
"hex": "626262",
|
||||
"string": "a3gV"
|
||||
},
|
||||
{
|
||||
"hex": "636363",
|
||||
"string": "aPEr"
|
||||
},
|
||||
{
|
||||
"hex": "73696d706c792061206c6f6e6720737472696e67",
|
||||
"string": "2cFupjhnEsSn59qHXstmK2ffpLv2"
|
||||
},
|
||||
{
|
||||
"hex": "00eb15231dfceb60925886b67d065299925915aeb172c06647",
|
||||
"string": "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"
|
||||
},
|
||||
{
|
||||
"hex": "516b6fcd0f",
|
||||
"string": "ABnLTmg"
|
||||
},
|
||||
{
|
||||
"hex": "bf4f89001e670274dd",
|
||||
"string": "3SEo3LWLoPntC"
|
||||
},
|
||||
{
|
||||
"hex": "572e4794",
|
||||
"string": "3EFU7m"
|
||||
},
|
||||
{
|
||||
"hex": "ecac89cad93923c02321",
|
||||
"string": "EJDM8drfXA6uyA"
|
||||
},
|
||||
{
|
||||
"hex": "10c8511e",
|
||||
"string": "Rt5zm"
|
||||
},
|
||||
{
|
||||
"hex": "00000000000000000000",
|
||||
"string": "1111111111"
|
||||
},
|
||||
{
|
||||
"hex": "801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e",
|
||||
"string": "5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD"
|
||||
},
|
||||
{
|
||||
"hex": "003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187",
|
||||
"string": "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS"
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"description": "non-base58 string",
|
||||
"string": "invalid"
|
||||
},
|
||||
{
|
||||
"description": "non-base58 alphabet",
|
||||
"string": "c2F0b3NoaQo="
|
||||
},
|
||||
{
|
||||
"description": "leading whitespace",
|
||||
"string": " 1111111111"
|
||||
},
|
||||
{
|
||||
"description": "trailing whitespace",
|
||||
"string": "1111111111 "
|
||||
},
|
||||
{
|
||||
"description": "unexpected character after whitespace",
|
||||
"string": " \t\n\u000b\f\r skip \r\f\u000b\n\t a"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
857
test/fixtures/orderbook.js
vendored
Normal file
857
test/fixtures/orderbook.js
vendored
Normal file
@@ -0,0 +1,857 @@
|
||||
/*eslint-disable max-len */
|
||||
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var addresses = require('./addresses');
|
||||
var Meta = require('ripple-lib').Meta;
|
||||
|
||||
module.exports.FIAT_BALANCE = '10';
|
||||
module.exports.NATIVE_BALANCE = '55';
|
||||
module.exports.NATIVE_BALANCE_PREVIOUS = '100';
|
||||
|
||||
module.exports.TAKER_GETS = '19.84580331';
|
||||
module.exports.TAKER_GETS_FINAL = '18.84580331';
|
||||
module.exports.TAKER_PAYS = '3878342440';
|
||||
module.exports.TAKER_PAYS_FINAL = '3078342440';
|
||||
module.exports.OTHER_TAKER_GETS = '4.9656112525';
|
||||
module.exports.OTHER_TAKER_GETS_FINAL = '3.9656112525';
|
||||
module.exports.OTHER_TAKER_PAYS = '972251352';
|
||||
module.exports.OTHER_TAKER_PAYS_FINAL = '902251352';
|
||||
|
||||
module.exports.LEDGER_INDEX = '06AFB03237286C1566CD649CFD5388C2C1F5BEFC5C3302A1962682803A9946FA';
|
||||
module.exports.OTHER_LEDGER_INDEX = 'D3338DA77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252';
|
||||
|
||||
module.exports.TRANSFER_RATE = 1002000000;
|
||||
|
||||
module.exports.fiatOffers = function (options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account_funds: '318.3643710638508',
|
||||
other_account_funds: '235.0194163432668'
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F15E821839FB',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000001897',
|
||||
PreviousTxnID: '11BA57676711A42C2FC2191EAEE98023B04627DFA84926B0C8E9D61A9CAF13AD',
|
||||
PreviousTxnLgrSeq: 8265601,
|
||||
Sequence: 531927,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.TAKER_GETS
|
||||
},
|
||||
taker_gets_funded: '100',
|
||||
is_fully_funded: true,
|
||||
TakerPays: module.exports.TAKER_PAYS,
|
||||
index: module.exports.LEDGER_INDEX,
|
||||
owner_funds: options.account_funds,
|
||||
quality: '195423807.2109563'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F4C3362FE1D0',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '00000000000063CC',
|
||||
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||
PreviousTxnLgrSeq: 8265523,
|
||||
Sequence: 1139002,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '4.9656112525'
|
||||
},
|
||||
taker_gets_funded: '100',
|
||||
is_fully_funded: true,
|
||||
TakerPays: '972251352',
|
||||
index: 'X2K98DB77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252',
|
||||
owner_funds: options.account_funds,
|
||||
quality: '195796912.5171664'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F4C3362FE1D0',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '00000000000063CC',
|
||||
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||
PreviousTxnLgrSeq: 8265523,
|
||||
Sequence: 1139002,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.OTHER_TAKER_GETS
|
||||
},
|
||||
taker_gets_funded: '100',
|
||||
is_fully_funded: true,
|
||||
TakerPays: module.exports.OTHER_TAKER_PAYS,
|
||||
index: module.exports.OTHER_LEDGER_INDEX,
|
||||
owner_funds: options.other_account_funds,
|
||||
quality: '195796912.5171664'
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
module.exports.NATIVE_OFFERS = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4C124AF94ED1781B',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '00000000000063CA',
|
||||
PreviousTxnID: '51C64E0B300E9C0E877BA3E79B4ED1DBD5FDDCE58FA1A8FDA5F8DDF139787A24',
|
||||
PreviousTxnLgrSeq: 8265275,
|
||||
Sequence: 1138918,
|
||||
TakerGets: '50',
|
||||
taker_gets_funded: '100',
|
||||
is_fully_funded: true,
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '5'
|
||||
},
|
||||
index: 'DC003E09AD1306FBBD1957C955EE668E429CC85B0EC0EC17297F6676E6108DE7',
|
||||
owner_funds: '162110617177',
|
||||
quality: '0.000000005148984210454555'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4C124B054BAD1D79',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000001896',
|
||||
PreviousTxnID: '9B21C7A4B66DC1CD5FC9D85C821C4CAA8F80E437582BAD11E88A1E9E6C7AA59C',
|
||||
PreviousTxnLgrSeq: 8265118,
|
||||
Sequence: 531856,
|
||||
TakerGets: '10',
|
||||
taker_gets_funded: '100',
|
||||
is_fully_funded: true,
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '20'
|
||||
},
|
||||
index: '7AC0458676A54E99FAA5ED0A56CD0CB814D3DEFE1C7874F0BB39875D60668E41',
|
||||
owner_funds: '430527438338',
|
||||
quality: '0.000000005149035697347961'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F4C3362FE1D0',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '00000000000063CC',
|
||||
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||
PreviousTxnLgrSeq: 8265523,
|
||||
Sequence: 1139002,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '4.9656112525'
|
||||
},
|
||||
TakerPays: '972251352',
|
||||
index: 'D3338DA77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252',
|
||||
owner_funds: '235.0194163432668',
|
||||
quality: '195796912.5171664'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.REQUEST_OFFERS = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000000',
|
||||
PreviousTxnID: '9BB337CC8B34DC8D1A3FFF468556C8BA70977C37F7436439D8DA19610F214AD1',
|
||||
PreviousTxnLgrSeq: 8342933,
|
||||
Sequence: 195,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.1129232560043778'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '56.06639660617357'
|
||||
},
|
||||
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||
owner_funds: '0.1129267125000245',
|
||||
quality: '496.4999999999999'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29354,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.2'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
quality: '498.6116758238228'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29356,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
quality: '498.6116758238228'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29354,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
quality: '199.4446703295291'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.REQUEST_OFFERS_NATIVE = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000000',
|
||||
Sequence: 195,
|
||||
TakerGets: '1000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '56.06639660617357'
|
||||
},
|
||||
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||
owner_funds: '600',
|
||||
quality: '.0560663966061735'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '4000',
|
||||
quality: '0.049861167582382'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29356,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '3900',
|
||||
quality: '0.049861167582382'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29354,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
quality: '0.049861167582382'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.QUALITY_OFFERS = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C1AFE1EE71A605F',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000009',
|
||||
PreviousTxnID: 'BCA728C17DBA10F100C41D4EF8B37318F33BC6156E94DB16703D2A1EE43DCCE6',
|
||||
PreviousTxnLgrSeq: 11929146,
|
||||
Sequence: 668643,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '301.3426005599325'
|
||||
},
|
||||
TakerPays: '22895281765',
|
||||
index: '79B34D7DF703580B86099EFD6B2E419AA39A585A50C82A3F9B446721B7C1490C',
|
||||
owner_funds: '5910.437716613066',
|
||||
quality: '75977580.74216543'
|
||||
}
|
||||
];
|
||||
|
||||
// This fixture is to exercise a bug where taker_pays_funded = taker_gets_funded * quality
|
||||
// has decimal amounts.
|
||||
module.exports.DECIMAL_TAKER_PAYS_FUNDED_OFFERS = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D0689673FA9094A',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000006',
|
||||
PreviousTxnID: 'C1BB04CE39E30BF5982B7660793723E9B3A832F5B458DB1C5938F4737E0E9ABF',
|
||||
PreviousTxnLgrSeq: 11631257,
|
||||
Sequence: 2936,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '9280.04'
|
||||
},
|
||||
TakerPays: '1707459061637',
|
||||
index: '89D85BBE91E0F419953EB89CE62E194922ED930EE57BE0C62FCC3B22DDB20852',
|
||||
owner_funds: '9280.037154029904',
|
||||
quality: '183992640.2943306',
|
||||
taker_gets_funded: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '9261.514125778347'
|
||||
},
|
||||
taker_pays_funded: '1704050437125'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.bookOffersResponse = function (options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account_funds: '2010.027702881682',
|
||||
other_account_funds: '24.06086596039299',
|
||||
third_account_funds: '9071.40090264774',
|
||||
fourth_account_funds: '7244.053477923128'
|
||||
});
|
||||
|
||||
return {
|
||||
offers: [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C188F5B29EE1C14',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000006762',
|
||||
PreviousTxnID: '5F08192C82CD3A598D29B51FCCDE29B6709EBCB454A3CD540C32F7A79EE7CB26',
|
||||
PreviousTxnLgrSeq: 11558364,
|
||||
Sequence: 1689777,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '79.39192374'
|
||||
},
|
||||
TakerPays: '5488380479',
|
||||
index: 'D9F821C8687E0D0EDEFF05EBB53CFDC81C5F9C4C354DAACB11F6676B5E14AEF5',
|
||||
owner_funds: options.account_funds,
|
||||
quality: '69130211.4932226'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18949C72B26C2A',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000001',
|
||||
PreviousTxnID: '038ED9ACC10211A8F6768729F36B74729CECCD33057837E160131675B272E532',
|
||||
PreviousTxnLgrSeq: 11558374,
|
||||
Sequence: 931088,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '24.060765960393'
|
||||
},
|
||||
TakerPays: '1664716059',
|
||||
index: '8845F212A8B53004A14C8C029FAF51B53266C66B49281A72F6A8F41CD92FDE99',
|
||||
owner_funds: options.other_account_funds,
|
||||
quality: '69187991.0116049',
|
||||
taker_gets_funded: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '24.01284027983332'
|
||||
},
|
||||
taker_pays_funded: '1661400177'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18949C764EA14E',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000009',
|
||||
PreviousTxnID: '62B96C0E0D86827BCE59ABDCAD146CC0B09404FE5BC86E712FB6F4E473016C63',
|
||||
PreviousTxnLgrSeq: 11558234,
|
||||
Sequence: 617872,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '712.60995'
|
||||
},
|
||||
TakerPays: '49304051247',
|
||||
index: '9E5C13908F67146AC35A711A17E5EB75771FDDA816C9532891DC90F29A6A4C10',
|
||||
owner_funds: options.third_account_funds,
|
||||
quality: '69187991.61729358'
|
||||
},
|
||||
{
|
||||
Account: addresses.FOURTH_ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18AA2E761B7EE6',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000511',
|
||||
PreviousTxnID: 'F18AED5EC1E7529EF03AF23ADA85F7625AA308278BACE1851F336443AA3DAAEA',
|
||||
PreviousTxnLgrSeq: 11558336,
|
||||
Sequence: 662712,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '288.08'
|
||||
},
|
||||
TakerPays: '20000000000',
|
||||
index: '606B3FC9199D5122F1DCC73EC1629E40C8A838D58AC67315A78D76699D960705',
|
||||
owner_funds: options.fourth_account_funds,
|
||||
quality: '69425159.67786726'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18C3D9EF58005A',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000006762',
|
||||
PreviousTxnID: 'E3A0240001B03E4F16C4BA6C2B0CB00C01413BE331ABE9E782B6A975DC936618',
|
||||
PreviousTxnLgrSeq: 11558318,
|
||||
Sequence: 1689755,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '196.460002'
|
||||
},
|
||||
TakerPays: '13694716399',
|
||||
index: '9A5D0AA37EA0889B876E9A3E552CACDB28BA5A3CD482A528992CD0CCFC09F6E8',
|
||||
quality: '69707402.31897178'
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.MODIFIED_NODES = [
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: 'E2B91A0A170BCC2BEC5C44B492D9B672888D9267A900330F5C08953CAA35D973',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
OwnerNode: '0000000000000001',
|
||||
Sequence: 538,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.TAKER_GETS_FINAL
|
||||
},
|
||||
TakerPays: module.exports.TAKER_PAYS_FINAL
|
||||
},
|
||||
LedgerEntryType: 'Offer',
|
||||
LedgerIndex: module.exports.LEDGER_INDEX,
|
||||
PreviousFields: {
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.TAKER_GETS
|
||||
},
|
||||
TakerPays: module.exports.TAKER_PAYS
|
||||
},
|
||||
PreviousTxnID: '5135DF8678727A70491DE512E5F0FE586E7C1E866492293B8898BF8191CFCAEB',
|
||||
PreviousTxnLgrSeq: 11676651
|
||||
}
|
||||
},
|
||||
{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: 'E2B91A0A170BCC2BEC5C44B492D9B672888D9267A900330F5C08953CAA35D973',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
OwnerNode: '0000000000000001',
|
||||
Sequence: 538,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.OTHER_TAKER_GETS_FINAL
|
||||
},
|
||||
TakerPays: module.exports.OTHER_TAKER_PAYS_FINAL
|
||||
},
|
||||
LedgerEntryType: 'Offer',
|
||||
LedgerIndex: module.exports.OTHER_LEDGER_INDEX,
|
||||
PreviousFields: {
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.OTHER_TAKER_GETS
|
||||
},
|
||||
TakerPays: module.exports.OTHER_TAKER_PAYS
|
||||
},
|
||||
PreviousTxnID: '5135DF8678727A70491DE512E5F0FE586E7C1E866492293B8898BF8191CFCAEB',
|
||||
PreviousTxnLgrSeq: 11676651
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.transactionWithRippleState = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
issuer: addresses.ISSUER,
|
||||
account: addresses.ACCOUNT,
|
||||
balance: module.exports.FIAT_BALANCE
|
||||
});
|
||||
|
||||
return {
|
||||
mmeta: new Meta({
|
||||
AffectedNodes: [{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: options.balance
|
||||
},
|
||||
Flags: 131072,
|
||||
HighLimit: {
|
||||
currency: 'USD',
|
||||
issuer: options.issuer,
|
||||
value: '100'
|
||||
},
|
||||
HighNode: '0000000000000000',
|
||||
LowLimit: {
|
||||
currency: 'USD',
|
||||
issuer: options.account,
|
||||
value: '0'
|
||||
},
|
||||
LowNode: '0000000000000000'
|
||||
},
|
||||
PreviousFields: {
|
||||
Balance: {
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||
value: '0'
|
||||
}
|
||||
},
|
||||
LedgerEntryType: 'RippleState',
|
||||
LedgerIndex: 'EA4BF03B4700123CDFFB6EB09DC1D6E28D5CEB7F680FB00FC24BC1C3BB2DB959',
|
||||
PreviousTxnID: '53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8',
|
||||
PreviousTxnLgrSeq: 343570
|
||||
}
|
||||
}]
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithAccountRoot = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account: addresses.ACCOUNT,
|
||||
balance: module.exports.NATIVE_BALANCE,
|
||||
previous_balance: module.exports.NATIVE_BALANCE_PREVIOUS
|
||||
});
|
||||
|
||||
return {
|
||||
mmeta: new Meta({
|
||||
AffectedNodes: [{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: options.account,
|
||||
Balance: options.balance,
|
||||
Flags: 0,
|
||||
OwnerCount: 1,
|
||||
Sequence: 2
|
||||
},
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
LedgerIndex: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05',
|
||||
PreviousFields: {
|
||||
Balance: options.previous_balance,
|
||||
OwnerCount: 0,
|
||||
Sequence: 1
|
||||
},
|
||||
PreviousTxnID: 'B24159F8552C355D35E43623F0E5AD965ADBF034D482421529E2703904E1EC09',
|
||||
PreviousTxnLgrSeq: 16154
|
||||
}
|
||||
}]
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithInvalidAccountRoot = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account: addresses.ACCOUNT,
|
||||
balance: module.exports.NATIVE_BALANCE
|
||||
});
|
||||
|
||||
return {
|
||||
mmeta: new Meta({
|
||||
AffectedNodes: [{
|
||||
ModifiedNode: {
|
||||
FinalFields: {
|
||||
Account: options.account,
|
||||
Balance: options.balance,
|
||||
Flags: 0,
|
||||
OwnerCount: 3,
|
||||
Sequence: 188
|
||||
},
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
LedgerIndex: 'B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A',
|
||||
PreviousTxnID: 'E9E1988A0F061679E5D14DE77DB0163CE0BBDC00F29E396FFD1DA0366E7D8904',
|
||||
PreviousTxnLgrSeq: 195455
|
||||
}
|
||||
}]
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithCreatedOffer = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account: addresses.ACCOUNT,
|
||||
amount: '1.9951'
|
||||
});
|
||||
|
||||
var meta = new Meta({
|
||||
AffectedNodes: [
|
||||
{
|
||||
CreatedNode: {
|
||||
LedgerEntryType: 'Offer',
|
||||
LedgerIndex: 'AF3C702057C9C47DB9E809FD8C76CD22521012C5CC7AE95D914EC9E226F1D7E5',
|
||||
NewFields: {
|
||||
Account: options.account,
|
||||
BookDirectory: '7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F211CEE1E0697A0',
|
||||
Flags: 131072,
|
||||
Sequence: 1404,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: options.amount
|
||||
},
|
||||
TakerPays: module.exports.TAKER_PAYS
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
meta.getAffectedBooks();
|
||||
|
||||
return {
|
||||
mmeta: meta,
|
||||
transaction: {
|
||||
TransactionType: 'OfferCreate',
|
||||
owner_funds: '2010.027702881682'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithDeletedOffer = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
transaction_type: 'OfferCreate'
|
||||
});
|
||||
|
||||
var meta = new Meta({
|
||||
AffectedNodes: [
|
||||
{
|
||||
DeletedNode: {
|
||||
FinalFields: {
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 477086871,
|
||||
Flags: 131072,
|
||||
OwnerNode: '0000000000000979',
|
||||
PreviousTxnID: 'DDD2AB60A2AA1690A6CB99B094BFD2E39A81AFF2AA91B5E4049D2C96A4BC8EBA',
|
||||
PreviousTxnLgrSeq: 11674760,
|
||||
Sequence: 85006,
|
||||
TakerGets: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: module.exports.TAKER_GETS
|
||||
},
|
||||
TakerPays: module.exports.TAKER_PAYS
|
||||
},
|
||||
LedgerEntryType: 'Offer',
|
||||
LedgerIndex: module.exports.LEDGER_INDEX
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
meta.getAffectedBooks();
|
||||
|
||||
return {
|
||||
mmeta: meta,
|
||||
transaction: {
|
||||
TransactionType: options.transaction_type,
|
||||
owner_funds: '2010.027702881682'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithModifiedOffer = function() {
|
||||
var meta = new Meta({
|
||||
AffectedNodes: module.exports.MODIFIED_NODES.slice(0, 1)
|
||||
});
|
||||
|
||||
meta.getAffectedBooks();
|
||||
|
||||
return {
|
||||
mmeta: meta,
|
||||
transaction: {
|
||||
TransactionType: 'OfferCreate',
|
||||
owner_funds: '2010.027702881682'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithModifiedOffers = function() {
|
||||
var meta = new Meta({
|
||||
AffectedNodes: module.exports.MODIFIED_NODES
|
||||
});
|
||||
|
||||
meta.getAffectedBooks();
|
||||
|
||||
return {
|
||||
mmeta: meta,
|
||||
transaction: {
|
||||
TransactionType: 'OfferCreate',
|
||||
owner_funds: '2010.027702881682'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.transactionWithNoNodes = function() {
|
||||
var meta = new Meta({
|
||||
AffectedNodes: []
|
||||
});
|
||||
|
||||
meta.getAffectedBooks();
|
||||
|
||||
return {
|
||||
mmeta: meta,
|
||||
transaction: {
|
||||
TransactionType: 'OfferCreate',
|
||||
owner_funds: '2010.027702881682'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.accountInfoResponse = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account: addresses.ISSUER
|
||||
});
|
||||
|
||||
return {
|
||||
account_data: {
|
||||
Account: options.account,
|
||||
Balance: '6156166959471',
|
||||
Domain: '6269747374616D702E6E6574',
|
||||
EmailHash: '5B33B93C7FFE384D53450FC666BB11FB',
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 0,
|
||||
PreviousTxnID: '6A7D0AB36CBA6884FDC398254BC67DE7E0B4887E9B0252568391102FBB854C09',
|
||||
PreviousTxnLgrSeq: 8344426,
|
||||
Sequence: 561,
|
||||
TransferRate: module.exports.TRANSFER_RATE,
|
||||
index: 'B7D526FDDF9E3B3F95C3DC97C353065B0482302500BBB8051A5C090B596C6133',
|
||||
urlgravatar: 'http:www.gravatar.com/avatar/5b33b93c7ffe384d53450fc666bb11fb'
|
||||
}
|
||||
};
|
||||
};
|
||||
294
test/fixtures/transactionmanager.json
vendored
Normal file
294
test/fixtures/transactionmanager.json
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
{
|
||||
"ACCOUNT": {
|
||||
"address": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"secret": "snoBcf899BdZP6nyaRHnSvE7qAJFP"
|
||||
},
|
||||
"ACCOUNT2": {
|
||||
"address": "rn7GZeJpUafLAyKQ7wrU5SUCu2hpQq7S2W",
|
||||
"secret": "ssThngbFXQWyJpK1mTeaNBrhHxHhp"
|
||||
},
|
||||
"SUBSCRIBE_RESPONSE": {
|
||||
"id": 1,
|
||||
"type": "response",
|
||||
"status": "success",
|
||||
"result": {
|
||||
"fee_base": 10,
|
||||
"fee_ref": 10,
|
||||
"hostid": "NBZ",
|
||||
"ledger_hash": "F1AF7D977B01D99D013EEE75136263A0937575882CC9A741662C3C111B08B112",
|
||||
"ledger_index": 1,
|
||||
"ledger_time": 463782770,
|
||||
"load_base": 256,
|
||||
"load_factor": 256,
|
||||
"pubkey_node": "n3Lp7DfQmxjHF5mYJsV2U9anALHmPem8PWQHWGpw4XMz79HA5aJH",
|
||||
"random": "EECFEE93BBB608914F190EC177B11DE52FC1D75D2C97DACBD26D2DFC6050E874",
|
||||
"reserve_base": 20000000,
|
||||
"reserve_inc": 5000000,
|
||||
"server_status": "full",
|
||||
"validated_ledgers": "32570-11692908"
|
||||
}
|
||||
},
|
||||
"ACCOUNT_INFO_RESPONSE": {
|
||||
"id": 1,
|
||||
"type": "response",
|
||||
"status": "success",
|
||||
"result": {
|
||||
"account_data": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Balance": "10000",
|
||||
"Flags": 4849664,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 3,
|
||||
"index": "01F3A2D58A5B986BF31CD92B513EB539CE48F705BB0E18FA39EF042DBE07A5DE"
|
||||
},
|
||||
"ledger_current_index": 11699032,
|
||||
"validated": false
|
||||
}
|
||||
|
||||
},
|
||||
"TX_STREAM_TRANSACTION": {
|
||||
"engine_result": "tesSUCCESS",
|
||||
"engine_result_code": 0,
|
||||
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||
"ledger_hash": "8093A78DEFD1F02037ABD349BD452081554A1DB1FE5E20DCB82D8DF16DD23B6D",
|
||||
"ledger_index": 1,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Balance": "1000",
|
||||
"Flags": 4849664,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 1
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "A4B28FB972EF890DC39A8557DF8960D41DADA00D39B0F1EFCD4BBB85FCA13A30",
|
||||
"PreviousFields": {
|
||||
"Balance": "1000",
|
||||
"Sequence": 3864
|
||||
},
|
||||
"PreviousTxnID": "F4910E55A39C42AB82071212D84119631DDE0B0F4F8F9040F252B0066898DBDF",
|
||||
"PreviousTxnLgrSeq": 11693103
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 9,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"status": "closed",
|
||||
"transaction": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 11693114,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "2D7F6A1F5F1AE2E0105A88F47D33A0B68031DE7FC43FF42388DA7D4B4C93865F",
|
||||
"TransactionType": "AccountSet",
|
||||
"TxnSignature": "39A0EC2307723546901BC8017CED16DF3DD79F50CA68A32377E0CF1BE097DCA004C21D99120220321921230C53A87629D79E6A5E74C08ECB59F8CBB9D695256DE5D0F8CB22FF0A",
|
||||
"date": 4771619,
|
||||
"hash": "01D66ACBD00B2A8F5D66FC8F67AC879CAECF49BC94FB97CF24F66B8406F4C040"
|
||||
},
|
||||
"type": "transaction",
|
||||
"validated": true
|
||||
|
||||
},
|
||||
"ACCOUNT_TX_TRANSACTION": {
|
||||
"validated": true,
|
||||
"meta": {
|
||||
"TransactionIndex": 3,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 11693103,
|
||||
"PreviousTxnID": "F4910E55A39C42AB82071212D84119631DDE0B0F4F8F9040F252B0066898DBDF",
|
||||
"LedgerIndex": "A4B28FB972EF890DC39A8557DF8960D41DADA00D39B0F1EFCD4BBB85FCA13A30",
|
||||
"PreviousFields": {
|
||||
"Sequence": 3864,
|
||||
"Balance": "1000"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 4849664,
|
||||
"Sequence": 3865,
|
||||
"OwnerCount": 1,
|
||||
"Balance": "1000",
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx": {
|
||||
"TransactionType": "AccountSet",
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 3864,
|
||||
"LastLedgerSequence": 2,
|
||||
"Fee": "10",
|
||||
"SigningPubKey": "2D7F6A1F5F1AE2E0105A88F47D33A0B68031DE7FC43FF42388DA7D4B4C93865F",
|
||||
"TxnSignature": "39A0EC2307723546901BC8017CED16DF3DD79F50CA68A32377E0CF1BE097DCA004C21D99120220321921230C53A87629D79E6A5E74C08ECB59F8CBB9D695256DE5D0F8CB22FF",
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"hash": "01D66ACBD00B2A8F5D66FC8F67AC879CAECF49BC94FB97CF24F66B8406F4C040",
|
||||
"ledger_index": 1,
|
||||
"inLedger": 1
|
||||
}
|
||||
},
|
||||
"ACCOUNT_TX_RESPONSE": {
|
||||
"id": 1,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"ledger_index_max": 100,
|
||||
"ledger_index_min": 1,
|
||||
"limit": 10,
|
||||
"transactions": [ ]
|
||||
}
|
||||
},
|
||||
"LEDGER": {
|
||||
"type": "ledgerClosed",
|
||||
"fee_base": 10,
|
||||
"fee_ref": 10,
|
||||
"ledger_hash": "FF757ECCF710C27DBCEC569840C38C5583594B56C49693079D95D8A99C30A928",
|
||||
"ledger_index": 1,
|
||||
"ledger_time": 478088,
|
||||
"reserve_base": 20000000,
|
||||
"reserve_inc": 5000000,
|
||||
"txn_count": 1,
|
||||
"validated_ledgers": "1-2"
|
||||
},
|
||||
"ACCOUNT_TX_ERROR": {
|
||||
"id": 1,
|
||||
"status": "error",
|
||||
"type": "response",
|
||||
"error": "actMalformed",
|
||||
"error_code": 33,
|
||||
"error_message": "Account malformed.",
|
||||
"request": {
|
||||
"account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3dZ",
|
||||
"binary": true,
|
||||
"command": "account_tx",
|
||||
"id": 1,
|
||||
"ledger_index_max": -1,
|
||||
"ledger_index_min": -1,
|
||||
"limit": 10
|
||||
}
|
||||
},
|
||||
"SUBMIT_RESPONSE": {
|
||||
"id": 1,
|
||||
"result": {
|
||||
"engine_result": "tesSUCCESS",
|
||||
"engine_result_code": 0,
|
||||
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||
"tx_blob": "12000322800000002400000001201B0000000568400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC744730450221008DFE8B50D66F2094652AA6BD1B354CC97E885BC1AEDF586C7ED61C7D786AA66202200FEE38460CF25C726A7F31626BD7A45542AFB2E468EBE9A175F9A9EC3FD19DDB811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||
"tx_json": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 1,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||
"TransactionType": "AccountSet",
|
||||
"TxnSignature": "30440220332316AC7B96B1385F4BD0159706439889A9E05AD62D168E61AC5CBD7BD417C00220361D9FBC31A5919F68FA70E9FB78C6E6C25CC7F89D0A2F9CC42660594EE0D0A2",
|
||||
"hash": "0D15A847D605DB5F1B76A4EE88EDCD5D279D47F009CFCE27F1D3DFE763225975"
|
||||
}
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
|
||||
},
|
||||
"SUBMIT_TEC_RESPONSE": {
|
||||
"id": 1,
|
||||
"result": {
|
||||
"engine_result": "tecNO_REGULAR_KEY",
|
||||
"engine_result_code": 131,
|
||||
"engine_result_message": "Regular key is not set.",
|
||||
"tx_blob": "12000322800000002400000001201B0000000520210000000468400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC74473045022100EEB2D1EFDC4B63A3FA9BD934307D3377197E86133A156022A01FFAD7CE3A78FA022024EB39D525FE42853F8E6B62BB74124FD0A1F763C56621AA8EC6A0FC0D0A6FC0811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||
"tx_json": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 2,
|
||||
"Sequence": 1,
|
||||
"SetFlag": 4,
|
||||
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||
"TransactionType": "AccountSet",
|
||||
"TxnSignature": "304402202DF7ED29DCA16F7A6191A74127437ACA04ADFCE6DB570101737C6426DD664FF5022069E9C6965DED37207708420B3B77A8CE9D0D009EE1D2434580ED4871398574D0",
|
||||
"hash": "56DCAE121213AA2E3A74921F934E78635DC0576E4DA1184AEE7D0F8E49046790"
|
||||
}
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
},
|
||||
"SUBMIT_TER_RESPONSE": {
|
||||
"id": 1,
|
||||
"result": {
|
||||
"engine_result": "terNO_ACCOUNT",
|
||||
"engine_result_code": -96,
|
||||
"engine_result_message": "The source account does not exist.",
|
||||
"tx_blob": "12000022800000002400000004201B0000000561400000000000000168400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC74473045022100BDEF89CF25B541FFDBBE0B652BF29D8C30715C8226346C72DBA69B275BC471C50220582C5F3DE6DE489E10594BD8911B2917EE9A452E6ED3A1BEED25E402CD2E3EFF811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C883143108B9AC27BF036EFE5CBE787921F54D622B7A5B",
|
||||
"tx_json": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Amount": "1",
|
||||
"Destination": "rn7GZeJpUafLAyKQ7wrU5SUCu2hpQq7S2W",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 2,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3044022041F099FD8F35F67E73B5F41FFD3CBCF5781748BFEBA6FD1AB56586EE71B7EE9902205F1C4DF58B40859A404939B44A169DA995DA03C6ED713C5DF76E57A843CCE7D1",
|
||||
"hash": "31090EA7996DFA6C2E0B43F704C30EC9AE635C18D7BEF90F42D4E0E2943A2680"
|
||||
}
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
},
|
||||
"SUBMIT_TEF_RESPONSE": {
|
||||
"id": 1,
|
||||
"result": {
|
||||
"engine_result": "tefPAST_SEQ",
|
||||
"engine_result_code": -189,
|
||||
"engine_result_message": "This sequence number has already past.",
|
||||
"tx_blob": "12000322800000002400000002201B0000000568400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC744730450221008B213EA1B4AACA9545E3DBFE43C69711DF295170B6F510CCD24B383684852C0702200E2A8FA3B205F1AFECF6D6DE298889D71E06336942ADF538847C8EFB88D3AA74811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||
"tx_json": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 2,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||
"TransactionType": "AccountSet",
|
||||
"TxnSignature": "304402203F6B9445B3B2176957C1008EBC0F18668464080A2CB10E78D83FB67DE2ABC3F50220769673DE79E6C1AF0E076A716ABE53018158385615E7EC2866DCFD6268806BF8",
|
||||
"hash": "731E94632E219ECAF2043C09C0075F1DEA2EC08E66A381CD536F0B1F3B30844D"
|
||||
}
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
},
|
||||
"SUBMIT_TEL_RESPONSE": {
|
||||
"id": 1,
|
||||
"result": {
|
||||
"engine_result": "telINSUF_FEE_P",
|
||||
"engine_result_code": -394,
|
||||
"engine_result_message": "Fee insufficient.",
|
||||
"tx_blob": "12000322800000002400000003201B00000005684000000000000001732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC7446304402206480AC2410BE4370E74E27B4427EF05F8A156D313C9D768E57B6EEC3BB89CDD402201503759955F367F88E5442F08D713B5369C5528475F046500721E676C24D0DFD811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||
"tx_json": {
|
||||
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 2,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||
"TransactionType": "AccountSet",
|
||||
"TxnSignature": "3044022002C0C13B21F9B690C6A3FF4B5A3F966AC47ACEE80453DAD553F5051FB3CED0E902202851BCC9EF8E2160BD1F3F6CF91B7C679149BD5FAD502C2BA544F7E61755AD1B",
|
||||
"hash": "ABF970193B8C9BE9BBD2777750924B28E7542DE1491EB55F4795539045AEA8B9"
|
||||
}
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
}
|
||||
@@ -33,5 +33,4 @@ describe('Meta', function() {
|
||||
assert.strictEqual(meta.nodes[idx], curr);
|
||||
}, []);
|
||||
});
|
||||
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,34 +1,44 @@
|
||||
/* eslint max-len: 0 */
|
||||
'use strict';
|
||||
var assert = require('assert');
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
describe('Seed', function() {
|
||||
it('can generate many addresses', function () {
|
||||
|
||||
var test_data = [
|
||||
// Format:
|
||||
// [passphrase, address, nth-for-seed, expected-public-key]
|
||||
["masterpassphrase", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", 0,
|
||||
"0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020"],
|
||||
["masterpassphrase", "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP", 1,
|
||||
"02CD8C4CE87F86AAD1D9D18B03DE28E6E756F040BD72A9C127862833EB90D60BAD"],
|
||||
["masterpassphrase", "rLpAd4peHUMBPbVJASMYK5GTBUSwXRD9nx", 2,
|
||||
"0259A57642A6F4AEFC9B8062AF453FDEEEAC5572BA602BB1DBD5EF011394C6F9FC"],
|
||||
["otherpassphrase", "rpe3YWSVwGU2PmUzebAPg2deBXHtmba7hJ", 0,
|
||||
"022235A3DB2CAE57C60B7831929611D58867F86D28C0AD3C82473CC4A84990D01B"],
|
||||
["otherpassphrase", "raAPC2gALSmsTkXR4wUwQcPgX66kJuLv2S", 5,
|
||||
"03F0619AFABE08D22D98C8721895FE3673B6174168949976F2573CE1138C124994"],
|
||||
["yetanotherpassphrase", "rKnM44fS48qrGiDxB5fB5u64vHVJwjDPUo", 0,
|
||||
"0385AD049327EF7E5EC429350A15CEB23955037DE99660F6E70C11C5ABF4407036"],
|
||||
["yetanotherpassphrase", "rMvkT1RHPfsZwTFbKDKBEisa5U4d2a9V8n", 1,
|
||||
"023A2876EA130CBE7BBA0573C2DB4C4CEB9A7547666915BD40366CDC6150CF54DC"]
|
||||
];
|
||||
|
||||
function assert_helper(seed_json, address_or_nth, expected) {
|
||||
var seed = Seed.from_json(seed_json);
|
||||
var keypair = seed.get_key(address_or_nth, 500);
|
||||
assert.strictEqual(keypair.to_hex_pub(), expected);
|
||||
}
|
||||
|
||||
describe('Seed', function() {
|
||||
it('saESc82Vun7Ta5EJRzGJbrXb5HNYk', function () {
|
||||
var seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
|
||||
assert.strictEqual(seed.to_hex(), 'FF1CF838D02B2CF7B45BAC27F5F24F4F');
|
||||
});
|
||||
it('sp6iDHnmiPN7tQFHm5sCW59ax3hfE', function () {
|
||||
var seed = Seed.from_json('sp6iDHnmiPN7tQFHm5sCW59ax3hfE');
|
||||
assert.strictEqual(seed.to_hex(), '00AD8DA764C3C8AF5F9B8D51C94B9E49');
|
||||
});
|
||||
it('can generate many addresses', function () {
|
||||
|
||||
var test_data = [
|
||||
// Format:
|
||||
// [passphrase, address, nth-for-seed, expected-public-key]
|
||||
['masterpassphrase', 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', 0,
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020'],
|
||||
['masterpassphrase', 'r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP', 1,
|
||||
'02CD8C4CE87F86AAD1D9D18B03DE28E6E756F040BD72A9C127862833EB90D60BAD'],
|
||||
['masterpassphrase', 'rLpAd4peHUMBPbVJASMYK5GTBUSwXRD9nx', 2,
|
||||
'0259A57642A6F4AEFC9B8062AF453FDEEEAC5572BA602BB1DBD5EF011394C6F9FC'],
|
||||
['otherpassphrase', 'rpe3YWSVwGU2PmUzebAPg2deBXHtmba7hJ', 0,
|
||||
'022235A3DB2CAE57C60B7831929611D58867F86D28C0AD3C82473CC4A84990D01B'],
|
||||
['otherpassphrase', 'raAPC2gALSmsTkXR4wUwQcPgX66kJuLv2S', 5,
|
||||
'03F0619AFABE08D22D98C8721895FE3673B6174168949976F2573CE1138C124994'],
|
||||
['yetanotherpassphrase', 'rKnM44fS48qrGiDxB5fB5u64vHVJwjDPUo', 0,
|
||||
'0385AD049327EF7E5EC429350A15CEB23955037DE99660F6E70C11C5ABF4407036'],
|
||||
['yetanotherpassphrase', 'rMvkT1RHPfsZwTFbKDKBEisa5U4d2a9V8n', 1,
|
||||
'023A2876EA130CBE7BBA0573C2DB4C4CEB9A7547666915BD40366CDC6150CF54DC']
|
||||
];
|
||||
|
||||
for (var nth = 0; nth < test_data.length; nth++) {
|
||||
var seed_json = test_data[nth][0];
|
||||
var address = test_data[nth][1];
|
||||
@@ -43,7 +53,7 @@ describe('Seed', function() {
|
||||
|
||||
// This isn't too bad as it only needs to generate one keypair `seq`
|
||||
assert_helper(seed_json, nth_for_seed, expected);
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable max-len*/
|
||||
/* eslint-disable key-spacing*/
|
||||
/* eslint-disable no-spaced-func*/
|
||||
/* eslint-disable space-before-blocks*/
|
||||
/* eslint-disable space-unary-ops*/
|
||||
/* eslint-disable no-multi-spaces*/
|
||||
/* eslint-disable no-void*/
|
||||
/* eslint-disable semi*/
|
||||
/* eslint-disable no-unused-vars*/
|
||||
/* eslint-disable quotes*/
|
||||
|
||||
var assert = require('assert');
|
||||
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
|
||||
// Shortcuts
|
||||
@@ -54,6 +68,56 @@ describe('Serialized object', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#from_json(v).to_json() == v -- invalid amount', function(){
|
||||
it('outputs same as passed to from_json', function() {
|
||||
var input_json = {
|
||||
Account: 'rUR9gTCcrUY9fMkz9rwcM9urPREh3LKXoW',
|
||||
Fee: '10',
|
||||
Flags: 0,
|
||||
Sequence: 65,
|
||||
SigningPubKey: '033D0B1FB932E0408C119107483190B61561DCE8529E29CB5D1C69128DA54DA715',
|
||||
TakerGets: '2188313981504612096',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'r9rp9MUFRJVCVLRm3MTmUvSPNBSL3BuEFx',
|
||||
value: '99999999999'
|
||||
},
|
||||
TransactionType: 'OfferCreate',
|
||||
TxnSignature: '304602210085C6AE945643150E6D450CF796E45D74FB24B4E03E964A29CC6AFFEB346C77C80221009BE1B6678CF6C2E61F8F2696144C75AFAF66DF4FC0733DF9118EDEFEEFE33243'
|
||||
};
|
||||
|
||||
assert.throws(function() {
|
||||
SerializedObject.from_json(input_json).to_json();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#from_json(v).to_json() == v -- invalid amount, strict_mode = false', function(){
|
||||
it('outputs same as passed to from_json', function() {
|
||||
var input_json = {
|
||||
Account: 'rUR9gTCcrUY9fMkz9rwcM9urPREh3LKXoW',
|
||||
Fee: '10',
|
||||
Flags: 0,
|
||||
Sequence: 65,
|
||||
SigningPubKey: '033D0B1FB932E0408C119107483190B61561DCE8529E29CB5D1C69128DA54DA715',
|
||||
TakerGets: '2188313981504612096',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'r9rp9MUFRJVCVLRm3MTmUvSPNBSL3BuEFx',
|
||||
value: '99999999999'
|
||||
},
|
||||
TransactionType: 'OfferCreate',
|
||||
TxnSignature: 'FFFFFF210085C6AE945643150E6D450CF796E45D74FB24B4E03E964A29CC6AFFEB346C77C80221009BE1B6678CF6C2E61F8F2696144C75AFAF66DF4FC0733DF9118EDEFEEFE33243'
|
||||
};
|
||||
|
||||
var strictMode = Amount.strict_mode;
|
||||
Amount.strict_mode = false;
|
||||
var output_json = SerializedObject.from_json(input_json).to_json();
|
||||
assert.deepEqual(input_json, output_json);
|
||||
Amount.strict_mode = strictMode;
|
||||
});
|
||||
});
|
||||
|
||||
describe('#from_json', function() {
|
||||
it('understands TransactionType as a Number', function() {
|
||||
var input_json = {
|
||||
@@ -109,7 +173,6 @@ describe('Serialized object', function() {
|
||||
});
|
||||
|
||||
describe('Memos', function() {
|
||||
|
||||
var input_json;
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -222,7 +285,7 @@ describe('Serialized object', function() {
|
||||
|
||||
|
||||
it('should serialize json with memo - match hex output', function() {
|
||||
var input_json = {
|
||||
input_json = {
|
||||
Flags: 2147483648,
|
||||
TransactionType: 'Payment',
|
||||
Account: 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
|
||||
|
||||
630
test/transaction-manager-test.js
Normal file
630
test/transaction-manager-test.js
Normal file
@@ -0,0 +1,630 @@
|
||||
'use strict';
|
||||
|
||||
var ws = require('ws');
|
||||
var lodash = require('lodash');
|
||||
var assert = require('assert-diff');
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||
var Transaction = require('ripple-lib').Transaction;
|
||||
var TransactionManager = require('../src/js/ripple/transactionmanager')
|
||||
.TransactionManager;
|
||||
|
||||
var LEDGER = require('./fixtures/transactionmanager').LEDGER;
|
||||
var ACCOUNT = require('./fixtures/transactionmanager').ACCOUNT;
|
||||
var ACCOUNT2 = require('./fixtures/transactionmanager').ACCOUNT2;
|
||||
var SUBSCRIBE_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.SUBSCRIBE_RESPONSE;
|
||||
var ACCOUNT_INFO_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.ACCOUNT_INFO_RESPONSE;
|
||||
var TX_STREAM_TRANSACTION = require('./fixtures/transactionmanager')
|
||||
.TX_STREAM_TRANSACTION;
|
||||
var ACCOUNT_TX_TRANSACTION = require('./fixtures/transactionmanager')
|
||||
.ACCOUNT_TX_TRANSACTION;
|
||||
var ACCOUNT_TX_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.ACCOUNT_TX_RESPONSE;
|
||||
var ACCOUNT_TX_ERROR = require('./fixtures/transactionmanager')
|
||||
.ACCOUNT_TX_ERROR;
|
||||
var SUBMIT_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.SUBMIT_RESPONSE;
|
||||
var SUBMIT_TEC_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.SUBMIT_TEC_RESPONSE;
|
||||
var SUBMIT_TER_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.SUBMIT_TER_RESPONSE;
|
||||
var SUBMIT_TEF_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.SUBMIT_TEF_RESPONSE;
|
||||
var SUBMIT_TEL_RESPONSE = require('./fixtures/transactionmanager')
|
||||
.SUBMIT_TEL_RESPONSE;
|
||||
|
||||
describe('TransactionManager', function() {
|
||||
var rippled;
|
||||
var rippledConnection;
|
||||
var remote;
|
||||
var account;
|
||||
var transactionManager;
|
||||
|
||||
beforeEach(function(done) {
|
||||
rippled = new ws.Server({port: 5763});
|
||||
|
||||
rippled.on('connection', function(c) {
|
||||
var ledger = lodash.extend({}, LEDGER);
|
||||
c.sendJSON = function(v) {
|
||||
try {
|
||||
c.send(JSON.stringify(v));
|
||||
} catch (e) {
|
||||
}
|
||||
};
|
||||
c.sendResponse = function(baseResponse, ext) {
|
||||
assert.strictEqual(typeof baseResponse, 'object');
|
||||
assert.strictEqual(baseResponse.type, 'response');
|
||||
c.sendJSON(lodash.extend(baseResponse, ext));
|
||||
};
|
||||
c.closeLedger = function() {
|
||||
c.sendJSON(lodash.extend(ledger, {
|
||||
ledger_index: ++ledger.ledger_index
|
||||
}));
|
||||
};
|
||||
c.on('message', function(m) {
|
||||
m = JSON.parse(m);
|
||||
rippled.emit('request_' + m.command, m, c);
|
||||
});
|
||||
rippledConnection = c;
|
||||
});
|
||||
|
||||
rippled.on('request_subscribe', function(message, c) {
|
||||
if (lodash.isEqual(message.streams, ['ledger', 'server'])) {
|
||||
c.sendResponse(SUBSCRIBE_RESPONSE, {id: message.id});
|
||||
}
|
||||
});
|
||||
rippled.on('request_account_info', function(message, c) {
|
||||
if (message.account === ACCOUNT.address) {
|
||||
c.sendResponse(ACCOUNT_INFO_RESPONSE, {id: message.id});
|
||||
}
|
||||
});
|
||||
|
||||
remote = new Remote({servers: ['ws://localhost:5763']});
|
||||
remote.setSecret(ACCOUNT.address, ACCOUNT.secret);
|
||||
account = remote.account(ACCOUNT.address);
|
||||
transactionManager = account._transactionManager;
|
||||
|
||||
remote.connect(function() {
|
||||
setTimeout(done, 10);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
remote.disconnect(function() {
|
||||
rippled.close();
|
||||
setImmediate(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('Normalize transaction', function() {
|
||||
var t1 = TransactionManager.normalizeTransaction(TX_STREAM_TRANSACTION);
|
||||
var t2 = TransactionManager.normalizeTransaction(ACCOUNT_TX_TRANSACTION);
|
||||
|
||||
[t1, t2].forEach(function(t) {
|
||||
assert(t.hasOwnProperty('metadata'));
|
||||
assert(t.hasOwnProperty('tx_json'));
|
||||
assert.strictEqual(t.validated, true);
|
||||
assert.strictEqual(t.ledger_index, 1);
|
||||
assert.strictEqual(t.engine_result, 'tesSUCCESS');
|
||||
assert.strictEqual(t.type, 'transaction');
|
||||
assert.strictEqual(t.tx_json.hash,
|
||||
'01D66ACBD00B2A8F5D66FC8F67AC879CAECF49BC94FB97CF24F66B8406F4C040');
|
||||
});
|
||||
});
|
||||
|
||||
it('Handle received transaction', function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
|
||||
transaction.once('success', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||
transactionManager.getPending().push(transaction);
|
||||
rippledConnection.sendJSON(TX_STREAM_TRANSACTION);
|
||||
});
|
||||
it('Handle received transaction -- failed', function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
|
||||
transaction.once('error', function(err) {
|
||||
assert.strictEqual(err.engine_result, 'tecINSUFF_FEE_P');
|
||||
done();
|
||||
});
|
||||
|
||||
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||
transactionManager.getPending().push(transaction);
|
||||
rippledConnection.sendJSON(lodash.extend({ }, TX_STREAM_TRANSACTION, {
|
||||
engine_result: 'tecINSUFF_FEE_P'
|
||||
}));
|
||||
});
|
||||
it('Handle received transaction -- not submitted', function(done) {
|
||||
rippledConnection.sendJSON(TX_STREAM_TRANSACTION);
|
||||
|
||||
remote.once('transaction', function() {
|
||||
assert(transactionManager.getPending().getReceived(
|
||||
TX_STREAM_TRANSACTION.transaction.hash));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Handle received transaction -- Account mismatch', function(done) {
|
||||
var tx = lodash.extend({ }, TX_STREAM_TRANSACTION);
|
||||
lodash.extend(tx.transaction, {
|
||||
Account: 'rMP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d'
|
||||
});
|
||||
rippledConnection.sendJSON(tx);
|
||||
|
||||
setImmediate(function() {
|
||||
assert(!transactionManager.getPending().getReceived(
|
||||
TX_STREAM_TRANSACTION.transaction.hash));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Handle received transaction -- not validated', function(done) {
|
||||
var tx = lodash.extend({ }, TX_STREAM_TRANSACTION, {
|
||||
validated: false
|
||||
});
|
||||
rippledConnection.sendJSON(tx);
|
||||
|
||||
setImmediate(function() {
|
||||
assert(!transactionManager.getPending().getReceived(
|
||||
TX_STREAM_TRANSACTION.transaction.hash));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('Handle received transaction -- from account_tx', function(done) {
|
||||
var transaction = Transaction.from_json(ACCOUNT_TX_TRANSACTION.tx);
|
||||
transaction.once('success', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
transaction.addId(ACCOUNT_TX_TRANSACTION.tx.hash);
|
||||
transactionManager.getPending().push(transaction);
|
||||
transactionManager._transactionReceived(ACCOUNT_TX_TRANSACTION);
|
||||
});
|
||||
|
||||
it('Adjust pending transaction fee', function(done) {
|
||||
var transaction = new Transaction(remote);
|
||||
transaction.tx_json = ACCOUNT_TX_TRANSACTION.tx;
|
||||
|
||||
transaction.once('fee_adjusted', function(a, b) {
|
||||
assert.strictEqual(a, '10');
|
||||
assert.strictEqual(b, '24');
|
||||
assert.strictEqual(transaction.tx_json.Fee, '24');
|
||||
done();
|
||||
});
|
||||
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
rippledConnection.sendJSON({
|
||||
type: 'serverStatus',
|
||||
load_base: 256,
|
||||
load_factor: 256 * 2,
|
||||
server_status: 'full'
|
||||
});
|
||||
});
|
||||
|
||||
it('Adjust pending transaction fee -- max fee exceeded', function(done) {
|
||||
transactionManager._maxFee = 10;
|
||||
|
||||
var transaction = new Transaction(remote);
|
||||
transaction.tx_json = ACCOUNT_TX_TRANSACTION.tx;
|
||||
|
||||
transaction.once('fee_adjusted', function() {
|
||||
assert(false, 'Fee should not be adjusted');
|
||||
});
|
||||
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
rippledConnection.sendJSON({
|
||||
type: 'serverStatus',
|
||||
load_base: 256,
|
||||
load_factor: 256 * 2,
|
||||
server_status: 'full'
|
||||
});
|
||||
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('Adjust pending transaction fee -- no local fee', function(done) {
|
||||
remote.local_fee = false;
|
||||
|
||||
var transaction = new Transaction(remote);
|
||||
transaction.tx_json = ACCOUNT_TX_TRANSACTION.tx;
|
||||
|
||||
transaction.once('fee_adjusted', function() {
|
||||
assert(false, 'Fee should not be adjusted');
|
||||
});
|
||||
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
rippledConnection.sendJSON({
|
||||
type: 'serverStatus',
|
||||
load_base: 256,
|
||||
load_factor: 256 * 2,
|
||||
server_status: 'full'
|
||||
});
|
||||
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('Wait ledgers', function(done) {
|
||||
transactionManager._waitLedgers(3, done);
|
||||
|
||||
for (var i = 1; i <= 3; i++) {
|
||||
rippledConnection.closeLedger();
|
||||
}
|
||||
});
|
||||
|
||||
it('Wait ledgers -- no ledgers', function(done) {
|
||||
transactionManager._waitLedgers(0, done);
|
||||
});
|
||||
|
||||
it('Update pending status', function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
transaction.submitIndex = 1;
|
||||
transaction.tx_json.LastLedgerSequence = 10;
|
||||
|
||||
var receivedMissing = false;
|
||||
var receivedLost = false;
|
||||
|
||||
transaction.once('missing', function() {
|
||||
receivedMissing = true;
|
||||
});
|
||||
transaction.once('lost', function() {
|
||||
receivedLost = true;
|
||||
});
|
||||
transaction.once('error', function(err) {
|
||||
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||
assert(receivedMissing);
|
||||
assert(receivedLost);
|
||||
done();
|
||||
});
|
||||
|
||||
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
for (var i = 1; i <= 10; i++) {
|
||||
rippledConnection.closeLedger();
|
||||
}
|
||||
});
|
||||
|
||||
it('Update pending status -- finalized before max ledger exceeded',
|
||||
function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
transaction.submitIndex = 1;
|
||||
transaction.tx_json.LastLedgerSequence = 10;
|
||||
transaction.finalized = true;
|
||||
|
||||
var receivedMissing = false;
|
||||
var receivedLost = false;
|
||||
|
||||
transaction.once('missing', function() {
|
||||
receivedMissing = true;
|
||||
});
|
||||
transaction.once('lost', function() {
|
||||
receivedLost = true;
|
||||
});
|
||||
transaction.once('error', function() {
|
||||
assert(false, 'Should not err');
|
||||
});
|
||||
|
||||
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
for (var i = 1; i <= 10; i++) {
|
||||
rippledConnection.closeLedger();
|
||||
}
|
||||
|
||||
setImmediate(function() {
|
||||
assert(!receivedMissing);
|
||||
assert(!receivedLost);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Handle reconnect', function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
|
||||
var binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
||||
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
||||
tx_blob: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.tx).to_hex(),
|
||||
meta: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.meta).to_hex()
|
||||
});
|
||||
|
||||
var hash = new SerializedObject(binaryTx.tx_blob).hash(0x54584E00).to_hex();
|
||||
|
||||
transaction.addId(hash);
|
||||
|
||||
transaction.once('success', function(res) {
|
||||
assert.strictEqual(res.engine_result, 'tesSUCCESS');
|
||||
done();
|
||||
});
|
||||
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
rippled.once('request_account_tx', function(m, req) {
|
||||
var response = lodash.extend({}, ACCOUNT_TX_RESPONSE);
|
||||
response.result.transactions = [binaryTx];
|
||||
req.sendResponse(response, {id: m.id});
|
||||
});
|
||||
|
||||
remote.disconnect(remote.connect);
|
||||
});
|
||||
|
||||
it('Handle reconnect -- no matching transaction found', function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
|
||||
var binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
||||
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
||||
tx_blob: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.tx).to_hex(),
|
||||
meta: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.meta).to_hex()
|
||||
});
|
||||
|
||||
transactionManager._request = function() {
|
||||
// Resubmitting
|
||||
done();
|
||||
};
|
||||
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
rippled.once('request_account_tx', function(m, req) {
|
||||
var response = lodash.extend({}, ACCOUNT_TX_RESPONSE);
|
||||
response.result.transactions = [binaryTx];
|
||||
req.sendResponse(response, {id: m.id});
|
||||
});
|
||||
|
||||
remote.disconnect(remote.connect);
|
||||
});
|
||||
|
||||
it('Handle reconnect -- account_tx error', function(done) {
|
||||
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||
transactionManager.getPending().push(transaction);
|
||||
|
||||
transactionManager._resubmit = function() {
|
||||
assert(false, 'Should not resubmit');
|
||||
};
|
||||
|
||||
rippled.once('request_account_tx', function(m, req) {
|
||||
req.sendResponse(ACCOUNT_TX_ERROR, {id: m.id});
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
remote.disconnect(remote.connect);
|
||||
});
|
||||
|
||||
it('Submit transaction', function(done) {
|
||||
var transaction = remote.createTransaction('AccountSet', {
|
||||
account: ACCOUNT.address
|
||||
});
|
||||
|
||||
var receivedInitialSuccess = false;
|
||||
var receivedProposed = false;
|
||||
transaction.once('proposed', function(m) {
|
||||
assert.strictEqual(m.engine_result, 'tesSUCCESS');
|
||||
receivedProposed = true;
|
||||
});
|
||||
transaction.once('submitted', function(m) {
|
||||
assert.strictEqual(m.engine_result, 'tesSUCCESS');
|
||||
receivedInitialSuccess = true;
|
||||
});
|
||||
|
||||
rippled.once('request_submit', function(m, req) {
|
||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||
transaction.tx_json).to_hex());
|
||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||
req.sendResponse(SUBMIT_RESPONSE, {id: m.id});
|
||||
setImmediate(function() {
|
||||
var txEvent = lodash.extend({}, TX_STREAM_TRANSACTION);
|
||||
txEvent.transaction = transaction.tx_json;
|
||||
txEvent.transaction.hash = transaction.hash();
|
||||
rippledConnection.sendJSON(txEvent);
|
||||
});
|
||||
});
|
||||
|
||||
transaction.submit(function(err, res) {
|
||||
assert(!err, 'Transaction submission should succeed');
|
||||
assert(receivedInitialSuccess);
|
||||
assert(receivedProposed);
|
||||
assert.strictEqual(res.engine_result, 'tesSUCCESS');
|
||||
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Submit transaction -- tec error', function(done) {
|
||||
var transaction = remote.createTransaction('AccountSet', {
|
||||
account: ACCOUNT.address,
|
||||
set_flag: 'asfDisableMaster'
|
||||
});
|
||||
|
||||
var receivedSubmitted = false;
|
||||
transaction.once('proposed', function() {
|
||||
assert(false, 'Should not receive proposed event');
|
||||
});
|
||||
transaction.once('submitted', function(m) {
|
||||
assert.strictEqual(m.engine_result, 'tecNO_REGULAR_KEY');
|
||||
receivedSubmitted = true;
|
||||
});
|
||||
|
||||
rippled.once('request_submit', function(m, req) {
|
||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||
transaction.tx_json).to_hex());
|
||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||
req.sendResponse(SUBMIT_TEC_RESPONSE, {id: m.id});
|
||||
setImmediate(function() {
|
||||
var txEvent = lodash.extend({}, TX_STREAM_TRANSACTION,
|
||||
SUBMIT_TEC_RESPONSE.result);
|
||||
txEvent.transaction = transaction.tx_json;
|
||||
txEvent.transaction.hash = transaction.hash();
|
||||
rippledConnection.sendJSON(txEvent);
|
||||
});
|
||||
});
|
||||
|
||||
transaction.submit(function(err) {
|
||||
assert(err, 'Transaction submission should not succeed');
|
||||
assert(receivedSubmitted);
|
||||
assert.strictEqual(err.engine_result, 'tecNO_REGULAR_KEY');
|
||||
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Submit transaction -- ter error', function(done) {
|
||||
var transaction = remote.createTransaction('Payment', {
|
||||
account: ACCOUNT.address,
|
||||
destination: ACCOUNT2.address,
|
||||
amount: '1'
|
||||
});
|
||||
transaction.tx_json.Sequence = ACCOUNT_INFO_RESPONSE.result
|
||||
.account_data.Sequence + 1;
|
||||
|
||||
var receivedSubmitted = false;
|
||||
transaction.once('proposed', function() {
|
||||
assert(false, 'Should not receive proposed event');
|
||||
});
|
||||
transaction.once('submitted', function(m) {
|
||||
assert.strictEqual(m.engine_result, 'terNO_ACCOUNT');
|
||||
receivedSubmitted = true;
|
||||
});
|
||||
|
||||
rippled.on('request_submit', function(m, req) {
|
||||
var deserialized = new SerializedObject(m.tx_blob).to_json();
|
||||
|
||||
switch (deserialized.TransactionType) {
|
||||
case 'Payment':
|
||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||
assert.deepEqual(deserialized, transaction.tx_json);
|
||||
req.sendResponse(SUBMIT_TER_RESPONSE, {id: m.id});
|
||||
break;
|
||||
case 'AccountSet':
|
||||
assert.strictEqual(deserialized.Account, ACCOUNT.address);
|
||||
assert.strictEqual(deserialized.Flags, 2147483648);
|
||||
req.sendResponse(SUBMIT_RESPONSE, {id: m.id});
|
||||
req.closeLedger();
|
||||
break;
|
||||
}
|
||||
});
|
||||
rippled.once('request_submit', function(m, req) {
|
||||
req.sendJSON(lodash.extend({}, LEDGER, {
|
||||
ledger_index: transaction.tx_json.LastLedgerSequence + 1
|
||||
}));
|
||||
});
|
||||
|
||||
transaction.submit(function(err) {
|
||||
assert(err, 'Transaction submission should not succeed');
|
||||
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||
assert(receivedSubmitted);
|
||||
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||
transactionManager.once('sequence_filled', done);
|
||||
});
|
||||
});
|
||||
|
||||
it('Submit transaction -- tef error', function(done) {
|
||||
var transaction = remote.createTransaction('AccountSet', {
|
||||
account: ACCOUNT.address
|
||||
});
|
||||
|
||||
transaction.tx_json.Sequence = ACCOUNT_INFO_RESPONSE.result
|
||||
.account_data.Sequence - 1;
|
||||
|
||||
var receivedSubmitted = false;
|
||||
var receivedResubmitted = false;
|
||||
transaction.once('proposed', function() {
|
||||
assert(false, 'Should not receive proposed event');
|
||||
});
|
||||
transaction.once('submitted', function(m) {
|
||||
assert.strictEqual(m.engine_result, 'tefPAST_SEQ');
|
||||
receivedSubmitted = true;
|
||||
});
|
||||
|
||||
rippled.on('request_submit', function(m, req) {
|
||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||
transaction.tx_json).to_hex());
|
||||
req.sendResponse(SUBMIT_TEF_RESPONSE, {id: m.id});
|
||||
});
|
||||
|
||||
rippled.once('request_submit', function(m, req) {
|
||||
transaction.once('resubmitted', function() {
|
||||
receivedResubmitted = true;
|
||||
req.sendJSON(lodash.extend({}, LEDGER, {
|
||||
ledger_index: transaction.tx_json.LastLedgerSequence + 1
|
||||
}));
|
||||
});
|
||||
|
||||
req.closeLedger();
|
||||
});
|
||||
|
||||
transaction.submit(function(err) {
|
||||
assert(err, 'Transaction submission should not succeed');
|
||||
assert(receivedSubmitted);
|
||||
assert(receivedResubmitted);
|
||||
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Submit transaction -- tel error', function(done) {
|
||||
var transaction = remote.createTransaction('AccountSet', {
|
||||
account: ACCOUNT.address
|
||||
});
|
||||
|
||||
var receivedSubmitted = false;
|
||||
var receivedResubmitted = false;
|
||||
transaction.once('proposed', function() {
|
||||
assert(false, 'Should not receive proposed event');
|
||||
});
|
||||
transaction.once('submitted', function(m) {
|
||||
assert.strictEqual(m.engine_result, 'telINSUF_FEE_P');
|
||||
receivedSubmitted = true;
|
||||
});
|
||||
|
||||
rippled.on('request_submit', function(m, req) {
|
||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||
transaction.tx_json).to_hex());
|
||||
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
|
||||
});
|
||||
|
||||
rippled.once('request_submit', function(m, req) {
|
||||
transaction.once('resubmitted', function() {
|
||||
receivedResubmitted = true;
|
||||
req.sendJSON(lodash.extend({}, LEDGER, {
|
||||
ledger_index: transaction.tx_json.LastLedgerSequence + 1
|
||||
}));
|
||||
});
|
||||
|
||||
req.closeLedger();
|
||||
});
|
||||
|
||||
transaction.submit(function(err) {
|
||||
assert(err, 'Transaction submission should not succeed');
|
||||
assert(receivedSubmitted);
|
||||
assert(receivedResubmitted);
|
||||
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Submit transaction -- invalid secret', function(done) {
|
||||
remote.setSecret(ACCOUNT.address, ACCOUNT.secret + 'z');
|
||||
|
||||
var transaction = remote.createTransaction('AccountSet', {
|
||||
account: ACCOUNT.address
|
||||
});
|
||||
|
||||
rippled.once('request_submit', function() {
|
||||
assert(false, 'Should not request submit');
|
||||
});
|
||||
|
||||
transaction.submit(function(err) {
|
||||
assert.strictEqual(err.engine_result, 'tejSecretInvalid');
|
||||
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user