mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-04 21:15:47 +00:00
Compare commits
253 Commits
0.9.2
...
0.12.1-rc3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
2abac6ce5c | ||
|
|
53c7705c36 | ||
|
|
7059ab65d6 | ||
|
|
e133988b36 | ||
|
|
9af27e7964 | ||
|
|
a57b3835fb | ||
|
|
451cbb809e | ||
|
|
fd1b64393d | ||
|
|
ed875a35b4 | ||
|
|
e85b0c2122 | ||
|
|
f5b192f55f | ||
|
|
ff86d5381d | ||
|
|
b63ac4addb | ||
|
|
3e1a66d617 | ||
|
|
93ed5a8cae | ||
|
|
2e6e8807be | ||
|
|
1ed36fabdb | ||
|
|
8dc40ee379 | ||
|
|
db4c7c89e3 | ||
|
|
f9bc7cc746 | ||
|
|
8f87ed65f9 | ||
|
|
39c37631f3 | ||
|
|
d0fb291c4e | ||
|
|
793523cbe9 | ||
|
|
6da4dd9ecc | ||
|
|
79892af8f8 | ||
|
|
b86790c854 | ||
|
|
c8f18c8c85 | ||
|
|
b19ecb4482 | ||
|
|
ba9af55aca | ||
|
|
35d76b3520 | ||
|
|
a5a0326092 | ||
|
|
a05833f845 | ||
|
|
c5deb60510 | ||
|
|
ff2ff89e3e | ||
|
|
35a346a674 | ||
|
|
1217a95c52 | ||
|
|
d025b4a0c3 | ||
|
|
2cab50f920 | ||
|
|
b049278dde | ||
|
|
93335e74cb | ||
|
|
2833a7b66e | ||
|
|
0d05b960f7 | ||
|
|
9fd64a9209 | ||
|
|
1637d26de3 | ||
|
|
525ff9b75e | ||
|
|
42e7932f59 | ||
|
|
98f40abfc3 | ||
|
|
55cd13ed4e | ||
|
|
7cb113fcbc | ||
|
|
ddbb999194 | ||
|
|
1db96829ed | ||
|
|
3498dea18c | ||
|
|
97a8c87490 | ||
|
|
fa72e09840 | ||
|
|
d8cad710a5 | ||
|
|
f91dcc33d3 | ||
|
|
e5f524ec56 | ||
|
|
f9b13cbc7f | ||
|
|
c7e0ba68f6 | ||
|
|
220262d192 | ||
|
|
1f860ecba6 | ||
|
|
69a13b71ea | ||
|
|
0a27afe6ee | ||
|
|
a3de021cd2 | ||
|
|
4dcbe78e83 | ||
|
|
84a8e8cbf6 | ||
|
|
e4b2b3d06b | ||
|
|
000a2ea00c | ||
|
|
89de91301e | ||
|
|
6be84bfa73 | ||
|
|
6cd79e7237 | ||
|
|
11d73173b8 | ||
|
|
9b3d62b765 | ||
|
|
2bdff53e68 | ||
|
|
8af5f9c28e | ||
|
|
9f71abf978 | ||
|
|
3fc2d3c1d9 | ||
|
|
c0c8db6dcc | ||
|
|
27249c0bb4 | ||
|
|
62e9684542 | ||
|
|
74b006cb0b | ||
|
|
77b33f11ab | ||
|
|
0aba638e6e | ||
|
|
e82522349f | ||
|
|
e520700260 | ||
|
|
3ec335f3a6 | ||
|
|
0f212e4dd1 | ||
|
|
c263654c88 | ||
|
|
874e3f24a6 | ||
|
|
b14343f3cf | ||
|
|
732b50dea7 | ||
|
|
be3bbe9b61 | ||
|
|
51211bbba0 | ||
|
|
5d1ff1c912 | ||
|
|
ea1be4fc50 | ||
|
|
7cc05f0d92 | ||
|
|
54606f3c21 | ||
|
|
a5d1705930 | ||
|
|
bfc0fb6c88 | ||
|
|
d1d4452217 | ||
|
|
2166a434a3 | ||
|
|
1053fa18e1 | ||
|
|
fa147d467e | ||
|
|
3f61598d6c | ||
|
|
9bf3724ce6 | ||
|
|
c2f27a4deb | ||
|
|
b6b99dde02 | ||
|
|
1fd0f4a8fe | ||
|
|
67d39737a4 | ||
|
|
aef4fe29a3 | ||
|
|
34c0677c45 | ||
|
|
3cb4a64b47 | ||
|
|
0db0375a5e | ||
|
|
47e6bdc644 | ||
|
|
66c2e27711 | ||
|
|
72387873b4 | ||
|
|
59017bc0bd | ||
|
|
2dde114d3d | ||
|
|
9e89904f03 | ||
|
|
56d0aca254 | ||
|
|
239710cebf | ||
|
|
1eaad617cb | ||
|
|
3c21994adc | ||
|
|
d15d14e197 | ||
|
|
e32694dc79 | ||
|
|
6ec8124287 | ||
|
|
2222adfc10 | ||
|
|
fcc2377657 | ||
|
|
1704ac4ae1 | ||
|
|
666e4348e0 | ||
|
|
9b22f279bc | ||
|
|
0835de983b | ||
|
|
1a892d58fc | ||
|
|
73a3cce4a4 | ||
|
|
d5ef4774fa | ||
|
|
c5bd4239a4 | ||
|
|
634e811888 | ||
|
|
3204998fcb | ||
|
|
12e428733a | ||
|
|
9cc6ad09a9 | ||
|
|
84abb5962e | ||
|
|
4bba55d2dc | ||
|
|
b4cabad44e | ||
|
|
28cc0f9e3b | ||
|
|
95a2cc18fe | ||
|
|
8e315a9859 | ||
|
|
89adcf4f4e | ||
|
|
3a6c5e41c9 | ||
|
|
86ed24b94c | ||
|
|
c792c471c3 | ||
|
|
e371cc2c3c | ||
|
|
ccf218c8f0 | ||
|
|
0d7fc0a573 | ||
|
|
74cacd5209 | ||
|
|
bb79cf2a87 | ||
|
|
28451df1a8 | ||
|
|
38e288f62a | ||
|
|
905f908450 | ||
|
|
672171fd0c | ||
|
|
520660ecbc | ||
|
|
06acb5faf2 | ||
|
|
d43fa03f05 | ||
|
|
baed1aaf92 | ||
|
|
cc229e803c | ||
|
|
d6b1728c23 | ||
|
|
bc5dcc359c | ||
|
|
ced07e1d6b | ||
|
|
cffffd9591 | ||
|
|
b8766e263f | ||
|
|
fc426d5764 | ||
|
|
056d2381cd | ||
|
|
2932a0ec5f | ||
|
|
d3d85a3fcf | ||
|
|
7a1feaa897 | ||
|
|
5f3cf72cc6 | ||
|
|
cae980788e | ||
|
|
df763b8765 | ||
|
|
365085809e | ||
|
|
3ee7998261 | ||
|
|
6fb9ed8312 | ||
|
|
89f79c35f5 | ||
|
|
6bdd4b2670 | ||
|
|
8f17873da2 | ||
|
|
b0cac776ee | ||
|
|
625dba4d85 |
7
.flowconfig
Normal file
7
.flowconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
[ignore]
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
|
||||
[options]
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -25,6 +25,7 @@ Release/*.*
|
||||
|
||||
# Ignore locally installed node_modules
|
||||
node_modules
|
||||
!test/node_modules
|
||||
|
||||
# Ignore tmp directory.
|
||||
tmp
|
||||
@@ -52,3 +53,11 @@ npm-debug.log
|
||||
|
||||
# Ignore dist folder, build for bower
|
||||
dist/
|
||||
|
||||
# Ignore flow output directory
|
||||
out/
|
||||
|
||||
# Ignore perf test cache
|
||||
scripts/cache
|
||||
|
||||
eslintrc
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
script: npm test --coverage
|
||||
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
|
||||
notifications:
|
||||
email: false
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/d1ec4245f90231619d30
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
on_start: false # default: false
|
||||
|
||||
184
Gulpfile.js
184
Gulpfile.js
@@ -1,22 +1,22 @@
|
||||
'use strict';
|
||||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var watch = require('gulp-watch');
|
||||
var plumber = require('gulp-plumber');
|
||||
var filelog = require('gulp-filelog');
|
||||
var cleanDest = require('gulp-clean-dest');
|
||||
var concat = require('gulp-concat');
|
||||
var uglify = require('gulp-uglify');
|
||||
var rename = require('gulp-rename');
|
||||
var webpack = require('webpack');
|
||||
var jshint = require('gulp-jshint');
|
||||
var map = require('map-stream');
|
||||
var bump = require('gulp-bump');
|
||||
var react = require('gulp-react');
|
||||
var flow = require('gulp-flowtype');
|
||||
var argv = require('yargs').argv;
|
||||
//var header = require('gulp-header');
|
||||
// var header = require('gulp-header');
|
||||
|
||||
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',
|
||||
@@ -50,38 +50,98 @@ var sjclSrc = [
|
||||
'src/js/sjcl-custom/sjcl-jacobi.js'
|
||||
];
|
||||
|
||||
function logPluginError(error) {
|
||||
gutil.log(error.toString());
|
||||
}
|
||||
|
||||
gulp.task('concat-sjcl', function() {
|
||||
return gulp.src(sjclSrc)
|
||||
.pipe(concat('sjcl.js'))
|
||||
.pipe(gulp.dest('./build/'));
|
||||
});
|
||||
|
||||
gulp.task('build', [ 'concat-sjcl' ], function(callback) {
|
||||
gulp.task('build', ['concat-sjcl'], function(callback) {
|
||||
webpack({
|
||||
cache: true,
|
||||
entry: './src/js/ripple/index.js',
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: './build/',
|
||||
filename: [ 'ripple-', '.js' ].join(pkg.version)
|
||||
},
|
||||
filename: ['ripple-', '.js'].join(pkg.version)
|
||||
}
|
||||
}, callback);
|
||||
});
|
||||
|
||||
gulp.task('bower-build', [ 'build' ], function(callback) {
|
||||
return gulp.src([ './build/ripple-', '.js' ].join(pkg.version))
|
||||
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)))
|
||||
.pipe(gulp.dest('./build/'));
|
||||
});
|
||||
|
||||
gulp.task('build-debug', ['concat-sjcl'], function(callback) {
|
||||
webpack({
|
||||
cache: true,
|
||||
entry: './src/js/ripple/index.js',
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: './build/',
|
||||
filename: ['ripple-', '-debug.js'].join(pkg.version)
|
||||
},
|
||||
debug: true,
|
||||
devtool: 'eval'
|
||||
}, callback);
|
||||
});
|
||||
|
||||
/**
|
||||
* Generate a WebPack external for a given unavailable module which replaces
|
||||
* that module's constructor with an error-thrower
|
||||
*/
|
||||
|
||||
function buildUseError(cons) {
|
||||
return ('var {<CONS>:function(){throw new Error('
|
||||
+ '"Class is unavailable in this build: <CONS>")}}')
|
||||
.replace(new RegExp('<CONS>', 'g'), cons);
|
||||
}
|
||||
|
||||
gulp.task('build-core', ['concat-sjcl'], function(callback) {
|
||||
webpack({
|
||||
entry: [
|
||||
'./src/js/ripple/remote.js'
|
||||
],
|
||||
externals: [
|
||||
{
|
||||
'./transaction': buildUseError('Transaction'),
|
||||
'./orderbook': buildUseError('OrderBook'),
|
||||
'./account': buildUseError('Account'),
|
||||
'./serializedobject': buildUseError('SerializedObject')
|
||||
}
|
||||
],
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: './build/',
|
||||
filename: ['ripple-', '-core.js'].join(pkg.version)
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin()
|
||||
]
|
||||
}, 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) {
|
||||
return gulp.src([ './build/ripple-', '-min.js' ].join(pkg.version))
|
||||
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) {
|
||||
return gulp.src([ './build/ripple-', '-debug.js' ].join(pkg.version))
|
||||
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/'));
|
||||
});
|
||||
@@ -92,72 +152,46 @@ gulp.task('bower-version', function() {
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
});
|
||||
|
||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug',
|
||||
'bower-version']);
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('src/js/ripple/*', ['build-debug']);
|
||||
});
|
||||
|
||||
// To use this, each javascript file must have /* @flow */ on the first line
|
||||
gulp.task('typecheck', function() {
|
||||
return gulp.src('src/js/ripple/*.js')
|
||||
.pipe(flow({ // note: do not set the 'all' option, it is broken
|
||||
weak: true, // remove this after all errors are addressed
|
||||
killFlow: true
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('strip', function() {
|
||||
return gulp.src('src/js/ripple/*.js')
|
||||
.pipe(watch('src/js/ripple/*.js'))
|
||||
.pipe(cleanDest('out')) // delete outdated output file before stripping
|
||||
.pipe(plumber()) // prevent an error in one file from ending build
|
||||
.pipe(react({stripTypes: true}).on('error', logPluginError))
|
||||
.pipe(filelog())
|
||||
.pipe(gulp.dest('out'));
|
||||
});
|
||||
|
||||
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')
|
||||
.pipe(bump({type:argv.type}))
|
||||
.pipe(bump({type: argv.type}))
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
gulp.task('version-beta', function() {
|
||||
gulp.src('./package.json')
|
||||
.pipe(bump({version: pkg.version+'-beta'}))
|
||||
.pipe(bump({version: pkg.version + '-beta'}))
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
gulp.task('build-min', [ 'build' ], function(callback) {
|
||||
return gulp.src([ './build/ripple-', '.js' ].join(pkg.version))
|
||||
.pipe(uglify())
|
||||
.pipe(rename([ 'ripple-', '-min.js' ].join(pkg.version)))
|
||||
.pipe(gulp.dest('./build/'));
|
||||
});
|
||||
|
||||
gulp.task('build-debug', [ 'concat-sjcl' ], function(callback) {
|
||||
webpack({
|
||||
cache: true,
|
||||
entry: './src/js/ripple/index.js',
|
||||
output: {
|
||||
library: 'ripple',
|
||||
path: './build/',
|
||||
filename: [ 'ripple-', '-debug.js' ].join(pkg.version)
|
||||
},
|
||||
debug: true,
|
||||
devtool: 'eval'
|
||||
}, callback);
|
||||
});
|
||||
|
||||
gulp.task('lint', function() {
|
||||
gulp.src('src/js/ripple/*.js')
|
||||
.pipe(jshint())
|
||||
.pipe(map(function(file, callback) {
|
||||
if (!file.jshint.success) {
|
||||
console.log('\nIn', file.path);
|
||||
|
||||
file.jshint.results.forEach(function(err) {
|
||||
if (err && err.error) {
|
||||
var col1 = err.error.line + ':' + err.error.character;
|
||||
var col2 = '[' + err.error.reason + ']';
|
||||
var col3 = '(' + err.error.code + ')';
|
||||
|
||||
while (col1.length < 8) {
|
||||
col1 += ' ';
|
||||
}
|
||||
|
||||
console.log(' ' + [ col1, col2, col3 ].join(' '));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
callback(null, file);
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('src/js/ripple/*', [ 'build-debug' ]);
|
||||
});
|
||||
|
||||
gulp.task('default', [ 'concat-sjcl', 'build', 'build-debug', 'build-min' ]);
|
||||
|
||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug', 'bower-version']);
|
||||
gulp.task('default', ['concat-sjcl', 'build', 'build-debug', 'build-min']);
|
||||
|
||||
142
HISTORY.md
142
HISTORY.md
@@ -1,3 +1,145 @@
|
||||
##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)
|
||||
|
||||
+ [Fix handling of falsy parameters in requestLedger](https://github.com/ripple/ripple-lib/commit/6023efed41b7812b3bab660a1c0dc9f0a21000b9)
|
||||
|
||||
+ [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**
|
||||
|
||||
+ REMOVED Remote storage interface
|
||||
+ REMOVED Remote `ping` configuration
|
||||
+ REMOVED Old/deprecated Remote server configuration (websocket_ip, websocket_port)
|
||||
+ REMOVED browser `online` reconnect listener
|
||||
- [Cleanup, deprecations - 2833a7b6](https://github.com/ripple/ripple-lib/commit/2833a7b66e696dab427464625077f9b93092d0d5)
|
||||
|
||||
+ Remove `jsbn` and use `bignumber.js` instead for big number math
|
||||
+ The `allow_nan` flag has been removed. Results for invalid amounts will always be `NaN`
|
||||
- [Refactor to use bignumber.js - d025b4a0](https://github.com/ripple/ripple-lib/commit/d025b4a0c3a98a6de27a1bee9573c85347bcd66b)
|
||||
- [Handle invalid input in parse_human - c8f18c8c](https://github.com/ripple/ripple-lib/commit/c8f18c8c8590b7b48e370e0325b6677b7720294f)
|
||||
- [Check for null in isNumber - b86790c8](https://github.com/ripple/ripple-lib/commit/b86790c8543c239a532fd7697d4652829019d385)
|
||||
- [Cleanup amount.js - d0fb291c](https://github.com/ripple/ripple-lib/commit/d0fb291c4e330193a244902156f1d74730da357d)
|
||||
|
||||
|
||||
**Changes**
|
||||
|
||||
+ [Add deprecation warnings to request constructors. The first argument to request constructor functions should be an object containing request properties](https://github.com/ripple/ripple-lib/commit/35d76b3520934285f80059c1badd6c522539104c)
|
||||
|
||||
+ [Fix taker_gets_funded exceeding offer.TakerGets](https://github.com/ripple/ripple-lib/commit/b19ecb4482b589d575382b7a5d0480b963383bb1)
|
||||
|
||||
+ [Fix unsymmetric memo serializing](https://github.com/ripple/ripple-lib/commit/1ed36fabdbd54f4d31078c2b0eaa3becc0fe2821)
|
||||
|
||||
+ [Fix IOU value passed to `Amount.from_json()`](https://github.com/ripple/ripple-lib/commit/fd1b64393dffb3d1819cd40b8d43df43a4db042d)
|
||||
|
||||
+ [Update transaction binary parsing to account for XRP delivered amounts](https://github.com/ripple/ripple-lib/commit/35a346a674e6ee1e1e495db93700d55984efc7dd)
|
||||
|
||||
+ [Bumped dependencies](https://github.com/ripple/ripple-lib/commit/f9bc7cc746b44b24b61bbe260ae2e9d9617286da)
|
||||
|
||||
|
||||
|
||||
##0.11.0
|
||||
|
||||
+ [Track the funded status of an order based on cumulative account orders](https://github.com/ripple/ripple-lib/commit/67d39737a4d5e0fcd9d9b47b9083ee00e5a9e652) and [67d3973](https://github.com/ripple/ripple-lib/commit/b6b99dde022e1e14c4797e454b1d7fca50e49482)
|
||||
|
||||
+ Remove blobvault client from ripple-lib, use the [`ripple-vault-client`](https://github.com/ripple/ripple-vault-client) instead [9b3d62b7](https://github.com/ripple/ripple-lib/commit/9b3d62b765c4c25beae6eb0fa57ef3a07f2581b1)
|
||||
|
||||
+ [Add support for `ledger` option in requestBookOffers](https://github.com/ripple/ripple-lib/commit/34c0677c453c409ef0a5b351959abdc176d3bacb)
|
||||
|
||||
+ [Add support for `limit` option in requestBookOffers](https://github.com/ripple/ripple-lib/commit/d1d4452217c878d0b377d24830b4cd8b3162f6e0)
|
||||
|
||||
+ [Add `ledgerSelect` request constructor in `Remote`](https://github.com/ripple/ripple-lib/commit/98f40abfc3aa74dec5067a2d90002756cc8acd01)
|
||||
|
||||
+ [Default to binary data for commands that accept the binary flag](https://github.com/ripple/ripple-lib/commit/7cb113fcbcfc1e3e9830a999148b3e78df3387cc)
|
||||
|
||||
+ [Fix metadata account check](https://github.com/ripple/ripple-lib/commit/3f61598d6c87e3cc877af60e2d515f9eff73dfe1)
|
||||
|
||||
+ [Double check `tes` code before emitting `success`](https://github.com/ripple/ripple-lib/commit/97a8c874903eb7309d8f755955ac80872f670582)
|
||||
|
||||
+ [Decrease redundancy in binary account_tx parsing](https://github.com/ripple/ripple-lib/commit/0aba638e6e7f4f6e22cb6424eed3897ebad90a5a)
|
||||
|
||||
+ [Abort server connection on unrecoverable TLS error](https://github.com/ripple/ripple-lib/commit/000a2ea00c57157044aeca0fb3f24b37669b163c)
|
||||
|
||||
+ [Fix complete ledgers check on subscription that is not initial](https://github.com/ripple/ripple-lib/commit/89de91301e682a46dc60aaacc7ae152e8fe1b7c7)
|
||||
|
||||
|
||||
##0.10.0
|
||||
|
||||
+ [Transaction changes](https://github.com/ripple/ripple-lib/pull/221)
|
||||
|
||||
+ **Important** `tef*` and `tel*` and errors will no longer be presented as
|
||||
final. Rather than considering these errors final, ripple-lib will wait until
|
||||
the `LastLedgerSequence` specified in the transaction is exceeded. This makes
|
||||
failures more definitive, and ensures that no transaction will resubmit
|
||||
indefinitely.
|
||||
|
||||
+ A new, final tej-class error is introduced to account for transactions that
|
||||
are locally determined to have expired: `tejMaxLedger`.
|
||||
|
||||
+ [Allow per transaction fees to be set, `transaction.setFixedFee()`](https://github.com/ripple/ripple-lib/commit/9b22f279bcbe60ee6bcf4b7fa60a48e9c197a828)
|
||||
|
||||
+ [Improve memo support](https://github.com/ripple/ripple-lib/commit/1704ac4ae144c0ce54afad86f644c75a632080b1)
|
||||
- Add `MemoFormat` property for memo
|
||||
- Enforce `MemoFormat` and `MemoType` to be valid ASCII
|
||||
- Support `text` and `json` MemoFormat
|
||||
|
||||
+ [Update jscl library](https://github.com/ripple/ripple-lib/commit/3204998fcb6f31d6c90532a737a4adb8a1e420f6)
|
||||
- Improved entropy by taking advantage of platform crypto
|
||||
- Use jscl's k256 curve instead of altering the c256 curve with k256 configuration
|
||||
- **deprecated:** the c256 curve is linked to the k256 curve to provide backwards compatibility, this link will be removed in the future
|
||||
|
||||
+ [Fix empty queue check on reconnect](https://github.com/ripple/ripple-lib/commit/3c21994adcf72d1fbd87d453ceb917f9ad6df4ec)
|
||||
|
||||
##0.9.4
|
||||
|
||||
+ [Normalize offers from book_offers and transaction stream](https://github.com/ripple/ripple-lib/commit/86ed24b94cf7c8929c87db3a63e9bbea7f767e9c)
|
||||
|
||||
+ [Fix: Amount.to_human() precision rounding](https://github.com/ripple/ripple-lib/commit/e371cc2c3ceccb3c1cfdf18b98d80093147dd8b2)
|
||||
|
||||
+ [Fix: fractional drops in funded taker_pays setter](https://github.com/ripple/ripple-lib/commit/0d7fc0a573a144caac15dd13798b23eeb1f95fb4)
|
||||
|
||||
##0.9.3
|
||||
|
||||
+ [Change `presubmit` to emit immediately before transaction submit](https://github.com/ripple/ripple-lib/commit/7a1feaa89701bf861ab31ebd8ffdc8d8d1474e29)
|
||||
|
||||
+ [Add a "core" browser build of ripple-lib which has a subset of features and smaller file size](https://github.com/ripple/ripple-lib/pull/205)
|
||||
|
||||
+ [Update binformat with missing fields from rippled](https://github.com/ripple/ripple-lib/commit/cae980788efb00191bfd0988ed836d60cdf7a9a2)
|
||||
|
||||
+ [Wait for transaction validation before returning `tec` error](https://github.com/ripple/ripple-lib/commit/6bdd4b2670906588852fc4dda457607b4aac08e4)
|
||||
|
||||
+ [Change default `max_fee` on `Remote` to `1 XRP`](https://github.com/ripple/ripple-lib/commit/d6b1728c23ff85c3cc791bed6982a750641fd95f)
|
||||
|
||||
+ [Fix: Request ledger_accept should return the Remote](https://github.com/ripple/ripple-lib/pull/209)
|
||||
|
||||
##0.9.2
|
||||
|
||||
+ [**Breaking change**: Change accountRequest method signature](https://github.com/ripple/ripple-lib/commit/6f5d1104aa3eb440c518ec4f39e264fdce15fa15)
|
||||
|
||||
20
README.md
20
README.md
@@ -9,15 +9,15 @@ A JavaScript API for interacting with Ripple in Node.js and the browser
|
||||
###Features
|
||||
|
||||
+ Connect to a rippled server in JavaScript (Node.js or browser)
|
||||
+ Issue [rippled API](https://ripple.com/wiki/JSON_Messages) requests
|
||||
+ Issue [rippled API](https://ripple.com/build/rippled-apis/) requests
|
||||
+ Listen to events on the Ripple network (transaction, ledger, etc.)
|
||||
+ Sign and submit transactions to the Ripple network
|
||||
|
||||
###In this file
|
||||
|
||||
1. [Installation](README.md#installation)
|
||||
2. [Quickstart](README.md#quickstart)
|
||||
3. [Running tests](https://github.com/ripple/ripple-lib#running-tests)
|
||||
1. [Installation](#installation)
|
||||
2. [Quick start](#quick-start)
|
||||
3. [Running tests](#running-tests)
|
||||
|
||||
###Additional documentation
|
||||
|
||||
@@ -47,7 +47,9 @@ A JavaScript API for interacting with Ripple in Node.js and the browser
|
||||
See the [bower-ripple repo](https://github.com/ripple/bower-ripple) for additional bower instructions
|
||||
|
||||
|
||||
**Building ripple-lib from github**
|
||||
**Building ripple-lib for browser environments**
|
||||
|
||||
ripple-lib uses Gulp to generate browser builds. These steps will generate minified and non-minified builds of ripple-lib in the `build/` directory.
|
||||
|
||||
```
|
||||
$ git clone https://github.com/ripple/ripple-lib
|
||||
@@ -55,9 +57,13 @@ See the [bower-ripple repo](https://github.com/ripple/bower-ripple) for addition
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
Then use the minified `build/ripple-*-min.js`
|
||||
**Restricted browser builds**
|
||||
|
||||
##Quickstart
|
||||
You may generate browser builds that contain a subset of features. To do this, run `./node_modules/.bin/gulp build-<name>`
|
||||
|
||||
+ `build-core` Contains the functionality to make requests and listen for events such as `ledgerClose`. Only `ripple.Remote` is currently exposed. Advanced features like transaction submission and orderbook tracking are excluded from this build.
|
||||
|
||||
##Quick start
|
||||
|
||||
`Remote.js` ([remote.js](https://github.com/ripple/ripple-lib/blob/develop/src/js/ripple/remote.js)) is the point of entry for interacting with rippled
|
||||
|
||||
|
||||
20
docs/BUILD.md
Normal file
20
docs/BUILD.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Using Flow typechecking
|
||||
=======================
|
||||
|
||||
Stage 1
|
||||
-------
|
||||
1. Add /* @flow */ to the top of a file you want to typecheck
|
||||
2. Run `gulp typecheck` to generate a list of warnings
|
||||
|
||||
Stage 2
|
||||
-------
|
||||
When all source files have the /* @flow */ header and all warnings have been
|
||||
addressed, remove the `weak: true` option from Gulpfile.js, run
|
||||
`gulp typecheck` and remove all the additional warnings.
|
||||
|
||||
Stage 3
|
||||
-------
|
||||
Add type annotations to the source code and run `gulp strip` to strip
|
||||
the type annotations and write the output to the `out` directory. After
|
||||
type annotations are added, the program must be run from the `out` directory
|
||||
because Node does not understand the annotations
|
||||
@@ -16,17 +16,6 @@ This file provides step-by-step walkthroughs for some of the most common usages
|
||||
1. [The ripple-lib README](../README.md)
|
||||
2. [The ripple-lib API Reference](REFERENCE.md)
|
||||
|
||||
##Generating a new Ripple Wallet
|
||||
|
||||
```js
|
||||
var Wallet = require('ripple-lib').Wallet;
|
||||
|
||||
var wallet = Wallet.generate();
|
||||
console.log(wallet);
|
||||
// { address: 'rEf4sbVobiiDGExrNj2PkNHGMA8eS6jWh3',
|
||||
// secret: 'shFh4a38EZpEdZxrLifEnVPAoBRce' }
|
||||
```
|
||||
|
||||
##Connecting to the Ripple network
|
||||
|
||||
1. [Get ripple-lib](README.md#getting-ripple-lib)
|
||||
@@ -50,7 +39,7 @@ This file provides step-by-step walkthroughs for some of the most common usages
|
||||
]
|
||||
}
|
||||
|
||||
var remote = new Remote({options});
|
||||
var remote = new Remote(options);
|
||||
|
||||
remote.connect(function(err, res) {
|
||||
/* remote connected, use some remote functions here */
|
||||
@@ -60,10 +49,37 @@ This file provides step-by-step walkthroughs for some of the most common usages
|
||||
|
||||
4. You're connected! Read on to see what to do now.
|
||||
|
||||
##Generating a new Ripple Wallet
|
||||
|
||||
```js
|
||||
var ripple = require('ripple-lib');
|
||||
|
||||
// subscribing to a server allows for more entropy
|
||||
var remote = new ripple.Remote({
|
||||
servers: [
|
||||
{ host: 's1.ripple.com', port: 443, secure: true }
|
||||
]
|
||||
});
|
||||
|
||||
remote.connect(function(err, res) {
|
||||
/* remote connected */
|
||||
});
|
||||
|
||||
// Wait for randomness to have been added.
|
||||
// The entropy of the random generator is increased
|
||||
// by random data received from a rippled
|
||||
remote.once('random', function(err, info) {
|
||||
var wallet = ripple.Wallet.generate();
|
||||
console.log(wallet);
|
||||
// { address: 'rEf4sbVobiiDGExrNj2PkNHGMA8eS6jWh3',
|
||||
// secret: 'shFh4a38EZpEdZxrLifEnVPAoBRce' }
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
##Sending rippled API requests
|
||||
|
||||
`Remote` contains functions for constructing a `Request` object.
|
||||
`Remote` contains functions for constructing a `Request` object.
|
||||
|
||||
A `Request` is an `EventEmitter` so you can listen for success or failure events -- or, instead, you can provide a callback.
|
||||
|
||||
@@ -124,29 +140,29 @@ See the [wiki](https://ripple.com/wiki/JSON_Messages#subscribe) for details on s
|
||||
'ledger',
|
||||
'transactions'
|
||||
];
|
||||
|
||||
|
||||
var request = remote.requestSubscribe(streams);
|
||||
|
||||
|
||||
request.on('error', function(error) {
|
||||
console.log('request error: ', error);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// the `ledger_closed` and `transaction` will come in on the remote
|
||||
// since the request for subscribe is finalized after the success return
|
||||
// the streaming events will still come in, but not on the initial request
|
||||
remote.on('ledger_closed', function(ledger) {
|
||||
console.log('ledger_closed: ', JSON.stringify(ledger, null, 2));
|
||||
});
|
||||
|
||||
|
||||
remote.on('transaction', function(transaction) {
|
||||
console.log('transaction: ', JSON.stringify(transaction, null, 2));
|
||||
});
|
||||
|
||||
|
||||
remote.on('error', function(error) {
|
||||
console.log('remote error: ', error);
|
||||
});
|
||||
|
||||
|
||||
// fire the request
|
||||
request.request();
|
||||
});
|
||||
@@ -160,7 +176,7 @@ See the [wiki](https://ripple.com/wiki/JSON_Messages#subscribe) for details on s
|
||||
Submitting a payment transaction to the Ripple network involves connecting to a `Remote`, creating a transaction, signing it with the user's secret, and submitting it to the `rippled` server. Note that the `Amount` module is used to convert human-readable amounts like '1XRP' or '10.50USD' to the type of Amount object used by the Ripple network.
|
||||
|
||||
```js
|
||||
/* Loading ripple-lib Remote and Amount modules in Node.js */
|
||||
/* Loading ripple-lib Remote and Amount modules in Node.js */
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
|
||||
@@ -179,8 +195,8 @@ remote.connect(function() {
|
||||
remote.setSecret(MY_ADDRESS, MY_SECRET);
|
||||
|
||||
var transaction = remote.createTransaction('Payment', {
|
||||
account: MY_ADDRESS,
|
||||
destination: RECIPIENT,
|
||||
account: MY_ADDRESS,
|
||||
destination: RECIPIENT,
|
||||
amount: AMOUNT
|
||||
});
|
||||
|
||||
@@ -201,12 +217,12 @@ Since the fee required for a transaction may change between the time when the or
|
||||
The [`max_fee`](REFERENCE.md#1-remote-options) option can be used to avoid submitting a transaction to a server that is charging unreasonably high fees.
|
||||
|
||||
|
||||
##4. Submitting a trade offer to the network
|
||||
##Submitting a trade offer to the network
|
||||
|
||||
Submitting a trade offer to the network is similar to submitting a payment transaction. Here is an example for a trade that expires in 24 hours where you are offering to sell 1 USD in exchange for 100 XRP:
|
||||
Submitting a trade offer to the network is similar to submitting a payment transaction. Here is an example offering to sell 1 USD in exchange for 100 XRP:
|
||||
|
||||
```js
|
||||
/* Loading ripple-lib Remote and Amount modules in Node.js */
|
||||
/* Loading ripple-lib Remote and Amount modules in Node.js */
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
|
||||
@@ -225,7 +241,7 @@ remote.connect(function() {
|
||||
|
||||
var transaction = remote.createTransaction('OfferCreate', {
|
||||
account: MY_ADDRESS,
|
||||
taker_pays: '1',
|
||||
taker_pays: '100',
|
||||
taker_gets: '1/USD/' + GATEWAY
|
||||
});
|
||||
|
||||
|
||||
105
npm-shrinkwrap.json
generated
105
npm-shrinkwrap.json
generated
@@ -1,27 +1,41 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.9.0-rc5",
|
||||
"version": "0.12.1-rc3",
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "0.8.0",
|
||||
"from": "async@>=0.8.0 <0.9.0"
|
||||
"version": "0.9.0",
|
||||
"from": "async@>=0.9.0 <0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
|
||||
},
|
||||
"bignumber.js": {
|
||||
"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",
|
||||
"from": "extend@>=1.2.1 <1.3.0"
|
||||
"from": "extend@>=1.2.1 <1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
||||
},
|
||||
"lodash": {
|
||||
"version": "3.3.1",
|
||||
"from": "https://registry.npmjs.org/lodash/-/lodash-3.3.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.3.1.tgz"
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "2.5.0",
|
||||
"from": "lru-cache@>=2.5.0 <2.6.0"
|
||||
"from": "lru-cache@>=2.5.0 <2.6.0",
|
||||
"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",
|
||||
"from": "superagent@>=0.18.0 <0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/superagent/-/superagent-0.18.2.tgz",
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "0.6.6",
|
||||
@@ -56,6 +70,7 @@
|
||||
"debug": {
|
||||
"version": "1.0.4",
|
||||
"from": "debug@>=1.0.1 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "0.6.2",
|
||||
@@ -75,8 +90,9 @@
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.3.tgz",
|
||||
"dependencies": {
|
||||
"combined-stream": {
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.7",
|
||||
"from": "combined-stream@>=0.0.4 <0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
|
||||
"dependencies": {
|
||||
"delayed-stream": {
|
||||
"version": "0.0.5",
|
||||
@@ -84,20 +100,18 @@
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"async": {
|
||||
"version": "0.9.0",
|
||||
"from": "async@>=0.9.0 <0.10.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.0.27-1",
|
||||
"from": "readable-stream@1.0.27-1",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz",
|
||||
"dependencies": {
|
||||
"core-util-is": {
|
||||
"version": "1.0.1",
|
||||
"from": "core-util-is@>=1.0.0 <1.1.0"
|
||||
"from": "core-util-is@>=1.0.0 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
@@ -106,35 +120,64 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"from": "string_decoder@>=0.10.0 <0.11.0"
|
||||
"from": "string_decoder@>=0.10.0 <0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1",
|
||||
"from": "inherits@>=2.0.1 <2.1.0"
|
||||
"from": "inherits@>=2.0.1 <2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "0.4.32",
|
||||
"from": "ws@>=0.4.31 <0.5.0",
|
||||
"version": "0.7.1",
|
||||
"from": "ws@>=0.7.1 <0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-0.7.1.tgz",
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.1.0",
|
||||
"from": "commander@>=2.1.0 <2.2.0"
|
||||
},
|
||||
"nan": {
|
||||
"version": "1.0.0",
|
||||
"from": "nan@>=1.0.0 <1.1.0"
|
||||
},
|
||||
"tinycolor": {
|
||||
"version": "0.0.1",
|
||||
"from": "tinycolor@>=0.0.0 <1.0.0"
|
||||
},
|
||||
"options": {
|
||||
"version": "0.0.6",
|
||||
"from": "options@>=0.0.5"
|
||||
"from": "options@>=0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
|
||||
},
|
||||
"ultron": {
|
||||
"version": "1.0.1",
|
||||
"from": "ultron@>=1.0.0 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.1.tgz"
|
||||
},
|
||||
"bufferutil": {
|
||||
"version": "1.0.1",
|
||||
"from": "bufferutil@>=1.0.0 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.0.1.tgz",
|
||||
"dependencies": {
|
||||
"bindings": {
|
||||
"version": "1.2.1",
|
||||
"from": "bindings@>=1.2.0 <1.3.0"
|
||||
},
|
||||
"nan": {
|
||||
"version": "1.6.1",
|
||||
"from": "nan@>=1.6.0 <1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.1.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"version": "1.0.1",
|
||||
"from": "utf-8-validate@>=1.0.0 <1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.0.1.tgz",
|
||||
"dependencies": {
|
||||
"bindings": {
|
||||
"version": "1.2.1",
|
||||
"from": "bindings@>=1.2.0 <1.3.0"
|
||||
},
|
||||
"nan": {
|
||||
"version": "1.6.1",
|
||||
"from": "nan@>=1.6.0 <1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.1.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
package.json
46
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.9.2",
|
||||
"version": "0.12.1-rc3",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
"src/js/*",
|
||||
@@ -15,33 +15,45 @@
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.8.0",
|
||||
"ws": "~0.4.31",
|
||||
"async": "~0.9.0",
|
||||
"bignumber.js": "^2.0.3",
|
||||
"extend": "~1.2.1",
|
||||
"lodash": "^3.1.0",
|
||||
"lru-cache": "~2.5.0",
|
||||
"superagent": "^0.18.0",
|
||||
"ripple-wallet-generator": "1.0.1"
|
||||
"ripple-wallet-generator": "1.0.2",
|
||||
"ws": "~0.7.1",
|
||||
"superagent": "^0.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.14.0",
|
||||
"gulp": "~3.6.2",
|
||||
"gulp-concat": "~2.2.0",
|
||||
"gulp-jshint": "~1.5.5",
|
||||
"gulp-uglify": "~0.3.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-bump": "~0.1.10",
|
||||
"webpack": "~1.1.11",
|
||||
"map-stream": "~0.1.0",
|
||||
"istanbul": "~0.2.10",
|
||||
"assert-diff": "^1.0.1",
|
||||
"coveralls": "~2.10.0",
|
||||
"eslint": "^0.13.0",
|
||||
"gulp": "~3.8.10",
|
||||
"gulp-bump": "~0.1.13",
|
||||
"gulp-clean-dest": "^0.1.0",
|
||||
"gulp-concat": "~2.4.3",
|
||||
"gulp-filelog": "^0.4.1",
|
||||
"gulp-flowtype": "^0.4.1",
|
||||
"gulp-plumber": "^0.6.6",
|
||||
"gulp-react": "^2.0.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-uglify": "~1.1.0",
|
||||
"gulp-util": "^3.0.3",
|
||||
"gulp-watch": "^4.1.0",
|
||||
"istanbul": "~0.3.5",
|
||||
"map-stream": "~0.1.0",
|
||||
"mocha": "~2.1.0",
|
||||
"nock": "^0.34.1",
|
||||
"webpack": "~1.5.3",
|
||||
"yargs": "~1.3.1"
|
||||
},
|
||||
"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 spec test/*-test.js",
|
||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls"
|
||||
"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",
|
||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
|
||||
"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": {
|
||||
"type": "git",
|
||||
|
||||
11
scripts/perf_test.sh
Executable file
11
scripts/perf_test.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
URL="https://www.dropbox.com/s/a0gy7vbb86eeqlq/ledger-full-1000000.json?dl=1"
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
DEST="$DIR/cache/ledger-full-1000000.json"
|
||||
if [ ! -e "$DEST" ]
|
||||
then
|
||||
echo "Downloading test data..."
|
||||
mkdir -p "$DIR/cache"
|
||||
curl -L "$URL" > "$DEST"
|
||||
fi
|
||||
time node "$DIR/verify_ledger_json.js" "$DEST"
|
||||
1210
src/js/jsbn/jsbn.js
1210
src/js/jsbn/jsbn.js
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ function Account(remote, account) {
|
||||
if (!self._subs && self._remote._connected) {
|
||||
self._remote.request_subscribe()
|
||||
.add_account(self._account_id)
|
||||
.broadcast();
|
||||
.broadcast().request();
|
||||
}
|
||||
self._subs += 1;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ function Account(remote, account) {
|
||||
if (!self._subs && self._remote._connected) {
|
||||
self._remote.request_unsubscribe()
|
||||
.add_account(self._account_id)
|
||||
.broadcast();
|
||||
.broadcast().request();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
var async = require('async');
|
||||
var superagent = require('superagent');
|
||||
var RippleTxt = require('./rippletxt').RippleTxt;
|
||||
|
||||
var AuthInfo = { };
|
||||
|
||||
AuthInfo._getRippleTxt = function(domain, callback) {
|
||||
RippleTxt.get(domain, callback);
|
||||
};
|
||||
|
||||
AuthInfo._getUser = function(url, callback) {
|
||||
superagent.get(url, callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get auth info for a given username
|
||||
*
|
||||
* @param {string} domain - Domain which hosts the user's info
|
||||
* @param {string} username - Username who's info we are retreiving
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
AuthInfo.get = function(domain, username, callback) {
|
||||
var self = this;
|
||||
username = username.toLowerCase();
|
||||
|
||||
function getRippleTxt(callback) {
|
||||
self._getRippleTxt(domain, function(err, txt) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!txt.authinfo_url) {
|
||||
return callback(new Error('Authentication is not supported on ' + domain));
|
||||
}
|
||||
|
||||
var url = Array.isArray(txt.authinfo_url) ? txt.authinfo_url[0] : txt.authinfo_url;
|
||||
|
||||
url += '?domain=' + domain + '&username=' + username;
|
||||
|
||||
callback(null, url);
|
||||
});
|
||||
};
|
||||
|
||||
function getUser(url, callback) {
|
||||
self._getUser(url, function(err, res) {
|
||||
if (err || res.error) {
|
||||
callback(new Error('Authentication info server unreachable'));
|
||||
} else {
|
||||
callback(null, res.body);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
async.waterfall([ getRippleTxt, getUser ], callback);
|
||||
};
|
||||
|
||||
exports.AuthInfo = AuthInfo;
|
||||
@@ -1,135 +1,125 @@
|
||||
var sjcl = require('./utils').sjcl;
|
||||
var utils = require('./utils');
|
||||
var extend = require('extend');
|
||||
|
||||
var BigInteger = utils.jsbn.BigInteger;
|
||||
'use strict';
|
||||
var _ = require('lodash');
|
||||
var sjcl = require('./utils').sjcl;
|
||||
var utils = require('./utils');
|
||||
var extend = require('extend');
|
||||
var convertBase = require('./baseconverter');
|
||||
|
||||
var Base = {};
|
||||
|
||||
var alphabets = Base.alphabets = {
|
||||
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
|
||||
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
|
||||
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
|
||||
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
|
||||
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||
};
|
||||
|
||||
extend(Base, {
|
||||
VER_NONE : 1,
|
||||
VER_NODE_PUBLIC : 28,
|
||||
VER_NODE_PRIVATE : 32,
|
||||
VER_ACCOUNT_ID : 0,
|
||||
VER_ACCOUNT_PUBLIC : 35,
|
||||
VER_ACCOUNT_PRIVATE : 34,
|
||||
VER_FAMILY_GENERATOR : 41,
|
||||
VER_FAMILY_SEED : 33
|
||||
VER_NONE: 1,
|
||||
VER_NODE_PUBLIC: 28,
|
||||
VER_NODE_PRIVATE: 32,
|
||||
VER_ACCOUNT_ID: 0,
|
||||
VER_ACCOUNT_PUBLIC: 35,
|
||||
VER_ACCOUNT_PRIVATE: 34,
|
||||
VER_FAMILY_GENERATOR: 41,
|
||||
VER_FAMILY_SEED: 33
|
||||
});
|
||||
|
||||
function sha256(bytes) {
|
||||
return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
||||
};
|
||||
return sjcl.codec.bytes.fromBits(
|
||||
sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
||||
}
|
||||
|
||||
function sha256hash(bytes) {
|
||||
return sha256(sha256(bytes));
|
||||
};
|
||||
function encodeString(alphabet, input) {
|
||||
if (input.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
return alphabet[digit];
|
||||
});
|
||||
var prefix = leadingZeros.map(function() {
|
||||
return alphabet[0];
|
||||
});
|
||||
return prefix.concat(out).join('');
|
||||
}
|
||||
|
||||
function decodeString(indexes, input) {
|
||||
if (input.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var input58 = input.split('').map(function(c) {
|
||||
var charCode = c.charCodeAt(0);
|
||||
if (charCode >= indexes.length) {
|
||||
throw new Error('Character ' + c + ' is not valid for encoding');
|
||||
}
|
||||
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) {
|
||||
var indexes = utils.arraySet(128, -1);
|
||||
for (var i = 0; i < alphabet.length; i++) {
|
||||
indexes[alphabet.charCodeAt(i)] = i;
|
||||
}
|
||||
return {
|
||||
decode: decodeString.bind(null, indexes),
|
||||
encode: encodeString.bind(null, alphabet)
|
||||
};
|
||||
}
|
||||
|
||||
Base.encoders = {};
|
||||
Object.keys(alphabets).forEach(function(alphabet) {
|
||||
Base.encoders[alphabet] = new Base58(alphabets[alphabet]);
|
||||
});
|
||||
|
||||
// --> input: big-endian array of bytes.
|
||||
// <-- string at least as long as input.
|
||||
Base.encode = function(input, alpha) {
|
||||
var alphabet = alphabets[alpha || 'ripple'];
|
||||
var bi_base = new BigInteger(String(alphabet.length));
|
||||
var bi_q = new BigInteger();
|
||||
var bi_r = new BigInteger();
|
||||
var bi_value = new BigInteger(input);
|
||||
var buffer = [];
|
||||
|
||||
while (bi_value.compareTo(BigInteger.ZERO) > 0) {
|
||||
bi_value.divRemTo(bi_base, bi_q, bi_r);
|
||||
bi_q.copyTo(bi_value);
|
||||
buffer.push(alphabet[bi_r.intValue()]);
|
||||
}
|
||||
|
||||
for (var i=0; i !== input.length && !input[i]; i += 1) {
|
||||
buffer.push(alphabet[0]);
|
||||
}
|
||||
|
||||
return buffer.reverse().join('');
|
||||
return this.encoders[alpha || 'ripple'].encode(input);
|
||||
};
|
||||
|
||||
// --> input: String
|
||||
// <-- array of bytes or undefined.
|
||||
Base.decode = function(input, alpha) {
|
||||
if (typeof input !== 'string') {
|
||||
return void(0);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var alphabet = alphabets[alpha || 'ripple'];
|
||||
var bi_base = new BigInteger(String(alphabet.length));
|
||||
var bi_value = new BigInteger();
|
||||
var i;
|
||||
|
||||
for (i = 0; i !== input.length && input[i] === alphabet[0]; i += 1) {
|
||||
try {
|
||||
return this.encoders[alpha || 'ripple'].decode(input);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (; i !== input.length; i += 1) {
|
||||
var v = alphabet.indexOf(input[i]);
|
||||
|
||||
if (v < 0) {
|
||||
return void(0);
|
||||
}
|
||||
|
||||
var r = new BigInteger();
|
||||
r.fromInt(v);
|
||||
bi_value = bi_value.multiply(bi_base).add(r);
|
||||
}
|
||||
|
||||
// toByteArray:
|
||||
// - Returns leading zeros!
|
||||
// - Returns signed bytes!
|
||||
var bytes = bi_value.toByteArray().map(function(b) { return b ? b < 0 ? 256+b : b : 0; });
|
||||
var extra = 0;
|
||||
|
||||
while (extra !== bytes.length && !bytes[extra]) {
|
||||
extra += 1;
|
||||
}
|
||||
|
||||
if (extra) {
|
||||
bytes = bytes.slice(extra);
|
||||
}
|
||||
|
||||
var zeros = 0;
|
||||
|
||||
while (zeros !== input.length && input[zeros] === alphabet[0]) {
|
||||
zeros += 1;
|
||||
}
|
||||
|
||||
return [].concat(utils.arraySet(zeros, 0), bytes);
|
||||
};
|
||||
|
||||
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
|
||||
// <-- String
|
||||
Base.encode_check = function(version, input, alphabet) {
|
||||
var buffer = [].concat(version, input);
|
||||
var check = sha256(sha256(buffer)).slice(0, 4);
|
||||
var check = sha256(sha256(buffer)).slice(0, 4);
|
||||
|
||||
return Base.encode([].concat(buffer, check), alphabet);
|
||||
};
|
||||
|
||||
// --> input : String
|
||||
// <-- NaN || BigInteger
|
||||
// <-- NaN || sjcl.bn
|
||||
Base.decode_check = function(version, input, alphabet) {
|
||||
var buffer = Base.decode(input, alphabet);
|
||||
|
||||
@@ -143,16 +133,10 @@ 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) {
|
||||
return NaN;
|
||||
}
|
||||
if (Array.isArray(version) && _.every(version, function(v) {
|
||||
return v !== buffer[0];
|
||||
})) {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
if (!Base.verify_checksum(buffer)) {
|
||||
@@ -163,7 +147,8 @@ Base.decode_check = function(version, input, alphabet) {
|
||||
// intrepret the value as a negative number
|
||||
buffer[0] = 0;
|
||||
|
||||
return new BigInteger(buffer.slice(0, -4), 256);
|
||||
return sjcl.bn.fromBits(
|
||||
sjcl.codec.bytes.toBits(buffer.slice(0, -4)));
|
||||
};
|
||||
|
||||
exports.Base = Base;
|
||||
|
||||
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,10 +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
|
||||
*/
|
||||
var TYPES_MAP = exports.types = [
|
||||
void(0),
|
||||
|
||||
exports.types = [
|
||||
undefined,
|
||||
|
||||
// Common
|
||||
'Int16', // 1
|
||||
@@ -17,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
|
||||
@@ -106,7 +115,8 @@ var FIELDS_MAP = exports.fields = {
|
||||
16: 'BookDirectory',
|
||||
17: 'InvoiceID',
|
||||
18: 'Nickname',
|
||||
19: 'Feature'
|
||||
19: 'Amendment',
|
||||
20: 'TicketID'
|
||||
},
|
||||
6: { // Amount
|
||||
1: 'Amount',
|
||||
@@ -135,7 +145,8 @@ var FIELDS_MAP = exports.fields = {
|
||||
10: 'ExpireCode',
|
||||
11: 'CreateCode',
|
||||
12: 'MemoType',
|
||||
13: 'MemoData'
|
||||
13: 'MemoData',
|
||||
14: 'MemoFormat'
|
||||
},
|
||||
8: { // Account
|
||||
1: 'Account',
|
||||
@@ -146,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',
|
||||
@@ -158,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',
|
||||
@@ -187,7 +198,7 @@ var FIELDS_MAP = exports.fields = {
|
||||
19: { // Vector256
|
||||
1: 'Indexes',
|
||||
2: 'Hashes',
|
||||
3: 'Features'
|
||||
3: 'Amendments'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -199,7 +210,6 @@ Object.keys(FIELDS_MAP).forEach(function(k1) {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var REQUIRED = exports.REQUIRED = 0,
|
||||
OPTIONAL = exports.OPTIONAL = 1,
|
||||
DEFAULT = exports.DEFAULT = 2;
|
||||
@@ -224,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 ],
|
||||
@@ -234,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 ],
|
||||
@@ -266,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 ]
|
||||
])
|
||||
};
|
||||
|
||||
@@ -373,7 +395,7 @@ exports.ledger = {
|
||||
['Balance', REQUIRED],
|
||||
['LowLimit', REQUIRED],
|
||||
['HighLimit', REQUIRED]])
|
||||
}
|
||||
};
|
||||
|
||||
exports.metadata = [
|
||||
[ 'TransactionIndex' , REQUIRED ],
|
||||
@@ -409,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
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
||||
var extend = require('extend');
|
||||
'use strict';
|
||||
|
||||
var extend = require('extend');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var utils = require('./utils');
|
||||
var Float = require('./ieee754').Float;
|
||||
@@ -16,8 +18,7 @@ var Currency = extend(function() {
|
||||
// 3-letter code: ...
|
||||
// XXX Should support hex, C++ doesn't currently allow it.
|
||||
|
||||
this._value = NaN;
|
||||
|
||||
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,25 +156,28 @@ 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
|
||||
// 0.5% demurrage is expressed 0.995, 0.005 less than 1
|
||||
// 0.5% interest is expressed as 1.005, 0.005 more than 1
|
||||
var interestEfold = secondsPerYear / Math.log(1 + percentage/100);
|
||||
var interestEfold = secondsPerYear / Math.log(1 + percentage / 100);
|
||||
var bytes = Float.toIEEE754Double(interestEfold);
|
||||
|
||||
for (var i=0; i<=bytes.length; i++) {
|
||||
for (var i = 0; i <= bytes.length; i++) {
|
||||
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;
|
||||
@@ -192,8 +219,9 @@ Currency.prototype._update = function() {
|
||||
this._interest_period = NaN;
|
||||
this._iso_code = '';
|
||||
|
||||
for (var i=0; i<20; i++) {
|
||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || bytes[i]===0);
|
||||
for (var i = 0; i < 20; i++) {
|
||||
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';
|
||||
}
|
||||
@@ -215,8 +243,8 @@ Currency.prototype._update = function() {
|
||||
this._type = 1;
|
||||
this._interest_start = (bytes[4] << 24) +
|
||||
(bytes[5] << 16) +
|
||||
(bytes[6] << 8) +
|
||||
(bytes[7] );
|
||||
(bytes[6] << 8) +
|
||||
(bytes[7]);
|
||||
this._interest_period = Float.fromIEEE754Double(bytes.slice(8, 16));
|
||||
}
|
||||
};
|
||||
@@ -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,18 +322,20 @@ 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;
|
||||
var decimalMultiplier = decimals ? Math.pow(10,decimals) : 100;
|
||||
interest = (interest * 100) - 100;
|
||||
var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
|
||||
|
||||
// round to two decimals behind the dot
|
||||
return Math.round(interest*decimalMultiplier) / decimalMultiplier;
|
||||
return Math.round(interest * decimalMultiplier) / decimalMultiplier;
|
||||
};
|
||||
|
||||
// XXX Currently we inherit UInt.prototype.is_valid, which is mostly fine.
|
||||
@@ -307,9 +343,9 @@ Currency.prototype.get_interest_percentage_at = function(referenceDate, decimals
|
||||
// We could be doing further checks into the internal format of the
|
||||
// currency data, since there are some values that are invalid.
|
||||
//
|
||||
//Currency.prototype.is_valid = function() {
|
||||
// return this._value instanceof BigInteger && ...;
|
||||
//};
|
||||
// Currency.prototype.is_valid = function() {
|
||||
// return UInt.prototype.is_valid() && ...;
|
||||
// };
|
||||
|
||||
Currency.prototype.to_json = function(opts) {
|
||||
if (!this.is_valid()) {
|
||||
@@ -317,28 +353,35 @@ 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
|
||||
// possible.
|
||||
// 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,24 +1,27 @@
|
||||
exports.Remote = require('./remote').Remote;
|
||||
exports.Request = require('./request').Request;
|
||||
exports.Amount = require('./amount').Amount;
|
||||
exports.Account = require('./account').Account;
|
||||
exports.Transaction = require('./transaction').Transaction;
|
||||
exports.Currency = require('./currency').Currency;
|
||||
exports.Base = require('./base').Base;
|
||||
exports.UInt160 = require('./uint160').UInt160;
|
||||
exports.UInt256 = require('./uint256').UInt256;
|
||||
exports.Seed = require('./seed').Seed;
|
||||
exports.Meta = require('./meta').Meta;
|
||||
'use strict';
|
||||
exports.Remote = require('./remote').Remote;
|
||||
exports.Request = require('./request').Request;
|
||||
exports.Amount = require('./amount').Amount;
|
||||
exports.Account = require('./account').Account;
|
||||
exports.Transaction = require('./transaction').Transaction;
|
||||
exports.Currency = require('./currency').Currency;
|
||||
exports.Base = require('./base').Base;
|
||||
exports.UInt128 = require('./uint128').UInt128;
|
||||
exports.UInt160 = require('./uint160').UInt160;
|
||||
exports.UInt256 = require('./uint256').UInt256;
|
||||
exports.Seed = require('./seed').Seed;
|
||||
exports.Meta = require('./meta').Meta;
|
||||
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
||||
exports.RippleError = require('./rippleerror').RippleError;
|
||||
exports.Message = require('./message').Message;
|
||||
exports.VaultClient = require('./vaultclient').VaultClient;
|
||||
exports.AuthInfo = require('./authinfo').AuthInfo;
|
||||
exports.RippleTxt = require('./rippletxt').RippleTxt;
|
||||
exports.binformat = require('./binformat');
|
||||
exports.utils = require('./utils');
|
||||
exports.Server = require('./server').Server;
|
||||
exports.Wallet = require('./wallet');
|
||||
exports.RippleError = require('./rippleerror').RippleError;
|
||||
exports.Message = require('./message').Message;
|
||||
exports.binformat = require('./binformat');
|
||||
exports.utils = require('./utils');
|
||||
exports.Server = require('./server').Server;
|
||||
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
|
||||
@@ -27,34 +30,35 @@ exports.Wallet = require('./wallet');
|
||||
// However, for programs that are tied to a specific version of ripple.js like
|
||||
// the official client, it makes sense to expose the SJCL instance so we don't
|
||||
// have to include it twice.
|
||||
exports.sjcl = require('./utils').sjcl;
|
||||
exports.sjcl = require('./utils').sjcl;
|
||||
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;
|
||||
Object.keys(o.prototype).forEach(function(key) {
|
||||
var UPPERCASE = /([A-Z]{1})[a-z]+/g;
|
||||
|
||||
if (!UPPERCASE.test(key)) {
|
||||
return;
|
||||
}
|
||||
if (!UPPERCASE.test(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var underscored = key.replace(UPPERCASE, function(c) {
|
||||
return '_' + c.toLowerCase();
|
||||
});
|
||||
var underscored = key.replace(UPPERCASE, function(c) {
|
||||
return '_' + c.toLowerCase();
|
||||
});
|
||||
|
||||
o.prototype[underscored] = o.prototype[key];
|
||||
});
|
||||
};
|
||||
o.prototype[underscored] = o.prototype[key];
|
||||
});
|
||||
}
|
||||
|
||||
[ 'Remote',
|
||||
'Request',
|
||||
'Transaction',
|
||||
'Account',
|
||||
'Server'
|
||||
['Remote',
|
||||
'Request',
|
||||
'Transaction',
|
||||
'Account',
|
||||
'Server'
|
||||
].forEach(attachUnderscored);
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -5,7 +5,7 @@ var UInt256 = require('./uint256').UInt256;
|
||||
var Base = require('./base').Base;
|
||||
|
||||
function KeyPair() {
|
||||
this._curve = sjcl.ecc.curves.c256;
|
||||
this._curve = sjcl.ecc.curves.k256;
|
||||
this._secret = null;
|
||||
this._pubkey = null;
|
||||
};
|
||||
@@ -15,7 +15,7 @@ KeyPair.from_bn_secret = function(j) {
|
||||
};
|
||||
|
||||
KeyPair.prototype.parse_bn_secret = function(j) {
|
||||
this._secret = new sjcl.ecc.ecdsa.secretKey(sjcl.ecc.curves.c256, j);
|
||||
this._secret = new sjcl.ecc.ecdsa.secretKey(sjcl.ecc.curves.k256, j);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
@@ -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,17 +51,55 @@ 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)]));
|
||||
};
|
||||
};
|
||||
|
||||
Log.prototype.debug = Log.makeLevel(1);
|
||||
Log.prototype.info = Log.makeLevel(2);
|
||||
Log.prototype.warn = Log.makeLevel(3);
|
||||
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;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
var extend = require('extend');
|
||||
var utils = require('./utils');
|
||||
var utils = require('./utils');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Amount = require('./amount').Amount;
|
||||
|
||||
@@ -26,28 +26,37 @@ function Meta(data) {
|
||||
data.AffectedNodes.forEach(this.addNode, this);
|
||||
};
|
||||
|
||||
Meta.nodeTypes = [
|
||||
Meta.NODE_TYPES = [
|
||||
'CreatedNode',
|
||||
'ModifiedNode',
|
||||
'DeletedNode'
|
||||
];
|
||||
|
||||
Meta.amountFieldsAffectingIssuer = [
|
||||
Meta.AMOUNT_FIELDS_AFFECTING_ISSUER = [
|
||||
'LowLimit',
|
||||
'HighLimit',
|
||||
'TakerPays',
|
||||
'TakerGets'
|
||||
];
|
||||
|
||||
Meta.ACCOUNT_FIELDS = [
|
||||
'Account',
|
||||
'Owner',
|
||||
'Destination',
|
||||
'Issuer',
|
||||
'Target'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {Object} node
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Meta.prototype.getNodeType = function(node) {
|
||||
var result = null;
|
||||
|
||||
for (var i=0; i<Meta.nodeTypes.length; i++) {
|
||||
var type = Meta.nodeTypes[i];
|
||||
for (var i=0; i<Meta.NODE_TYPES.length; i++) {
|
||||
var type = Meta.NODE_TYPES[i];
|
||||
if (node.hasOwnProperty(type)) {
|
||||
result = type;
|
||||
break;
|
||||
@@ -57,6 +66,15 @@ Meta.prototype.getNodeType = function(node) {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} field
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Meta.prototype.isAccountField = function(field) {
|
||||
return Meta.ACCOUNT_FIELDS.indexOf(field) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add node to metadata
|
||||
*
|
||||
@@ -72,7 +90,6 @@ Meta.prototype.addNode = function(node) {
|
||||
|
||||
if ((result.nodeType = this.getNodeType(node))) {
|
||||
node = node[result.nodeType];
|
||||
|
||||
result.diffType = result.nodeType;
|
||||
result.entryType = node.LedgerEntryType;
|
||||
result.ledgerIndex = node.LedgerIndex;
|
||||
@@ -114,57 +131,6 @@ Meta.prototype.getNodes = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a function on each affected node.
|
||||
*
|
||||
* The callback is passed two parameters. The first is a node object which looks
|
||||
* like this:
|
||||
*
|
||||
* {
|
||||
* // Type of diff, e.g. CreatedNode, ModifiedNode
|
||||
* nodeType: 'CreatedNode'
|
||||
*
|
||||
* // Type of node affected, e.g. RippleState, AccountRoot
|
||||
* entryType: 'RippleState',
|
||||
*
|
||||
* // Index of the ledger this change occurred in
|
||||
* ledgerIndex: '01AB01AB...',
|
||||
*
|
||||
* // Contains all fields with later versions taking precedence
|
||||
* //
|
||||
* // This is a shorthand for doing things like checking which account
|
||||
* // this affected without having to check the nodeType.
|
||||
* fields: {...},
|
||||
*
|
||||
* // Old fields (before the change)
|
||||
* fieldsPrev: {...},
|
||||
*
|
||||
* // New fields (that have been added)
|
||||
* fieldsNew: {...},
|
||||
*
|
||||
* // Changed fields
|
||||
* fieldsFinal: {...}
|
||||
* }
|
||||
*
|
||||
* The second parameter to the callback is the index of the node in the metadata
|
||||
* (first entry is index 0).
|
||||
*/
|
||||
|
||||
[
|
||||
'forEach',
|
||||
'map',
|
||||
'filter',
|
||||
'every',
|
||||
'some',
|
||||
'reduce'
|
||||
].forEach(function(fn) {
|
||||
Meta.prototype[fn] = function() {
|
||||
return Array.prototype[fn].apply(this.nodes, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
Meta.prototype.each = Meta.prototype.forEach;
|
||||
|
||||
Meta.prototype.getAffectedAccounts = function(from) {
|
||||
if (this._affectedAccounts) {
|
||||
return this._affectedAccounts;
|
||||
@@ -176,12 +142,16 @@ Meta.prototype.getAffectedAccounts = function(from) {
|
||||
// TransactionMetaSet::getAffectedAccounts
|
||||
for (var i=0; i<this.nodes.length; i++) {
|
||||
var node = this.nodes[i];
|
||||
var fields = (node.nodeType === 'CreatedNode') ? node.fieldsNew : node.fieldsFinal;
|
||||
var fields = (node.nodeType === 'CreatedNode')
|
||||
? node.fieldsNew
|
||||
: node.fieldsFinal;
|
||||
|
||||
for (var fieldName in fields) {
|
||||
var field = fields[fieldName];
|
||||
if (typeof field === 'string' && UInt160.is_valid(field)) {
|
||||
|
||||
if (this.isAccountField(fieldName) && UInt160.is_valid(field)) {
|
||||
accounts.push(field);
|
||||
} else if (~Meta.amountFieldsAffectingIssuer.indexOf(fieldName)) {
|
||||
} else if (~Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName)) {
|
||||
var amount = Amount.from_json(field);
|
||||
var issuer = amount.issuer();
|
||||
if (issuer.is_valid() && !issuer.is_zero()) {
|
||||
@@ -193,7 +163,7 @@ Meta.prototype.getAffectedAccounts = function(from) {
|
||||
|
||||
this._affectedAccounts = utils.arrayUnique(accounts);
|
||||
|
||||
return this._affectedAccounts;
|
||||
return this._affectedAccounts;
|
||||
};
|
||||
|
||||
Meta.prototype.getAffectedBooks = function() {
|
||||
@@ -238,4 +208,53 @@ Meta.prototype.getAffectedBooks = function() {
|
||||
return this._affectedBooks;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Execute a function on each affected node.
|
||||
*
|
||||
* The callback is passed two parameters. The first is a node object which looks
|
||||
* like this:
|
||||
*
|
||||
* {
|
||||
* // Type of diff, e.g. CreatedNode, ModifiedNode
|
||||
* nodeType: 'CreatedNode'
|
||||
*
|
||||
* // Type of node affected, e.g. RippleState, AccountRoot
|
||||
* entryType: 'RippleState',
|
||||
*
|
||||
* // Index of the ledger this change occurred in
|
||||
* ledgerIndex: '01AB01AB...',
|
||||
*
|
||||
* // Contains all fields with later versions taking precedence
|
||||
* //
|
||||
* // This is a shorthand for doing things like checking which account
|
||||
* // this affected without having to check the nodeType.
|
||||
* fields: {...},
|
||||
*
|
||||
* // Old fields (before the change)
|
||||
* fieldsPrev: {...},
|
||||
*
|
||||
* // New fields (that have been added)
|
||||
* fieldsNew: {...},
|
||||
*
|
||||
* // Changed fields
|
||||
* fieldsFinal: {...}
|
||||
* }
|
||||
*/
|
||||
|
||||
[
|
||||
'forEach',
|
||||
'map',
|
||||
'filter',
|
||||
'every',
|
||||
'some',
|
||||
'reduce'
|
||||
].forEach(function(fn) {
|
||||
Meta.prototype[fn] = function() {
|
||||
return Array.prototype[fn].apply(this.nodes, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
Meta.prototype.each = Meta.prototype.forEach;
|
||||
|
||||
exports.Meta = Meta;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,28 +35,27 @@ util.inherits(PathFind, EventEmitter);
|
||||
PathFind.prototype.create = function () {
|
||||
var self = this;
|
||||
|
||||
var req = this.remote.request_path_find_create(this.src_account,
|
||||
this.dst_account,
|
||||
this.dst_amount,
|
||||
this.src_currencies,
|
||||
handleInitialPath);
|
||||
var req = this.remote.request_path_find_create(
|
||||
this.src_account,
|
||||
this.dst_account,
|
||||
this.dst_amount,
|
||||
this.src_currencies);
|
||||
|
||||
function handleInitialPath(err, msg) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
} else {
|
||||
self.notify_update(msg);
|
||||
}
|
||||
}
|
||||
req.once('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
req.once('success', function(msg) {
|
||||
self.notify_update(msg);
|
||||
});
|
||||
|
||||
// XXX We should add ourselves to prepare_subscribe or a similar mechanism so
|
||||
// that we can resubscribe after a reconnection.
|
||||
|
||||
req.request();
|
||||
req.broadcast().request();
|
||||
};
|
||||
|
||||
PathFind.prototype.close = function () {
|
||||
this.remote.request_path_find_close().request();
|
||||
this.remote.request_path_find_close().broadcast().request();
|
||||
this.emit('end');
|
||||
this.emit('close');
|
||||
};
|
||||
|
||||
67
src/js/ripple/rangeset.js
Normal file
67
src/js/ripple/rangeset.js
Normal file
@@ -0,0 +1,67 @@
|
||||
var assert = require('assert');
|
||||
var lodash = require('lodash');
|
||||
|
||||
function RangeSet() {
|
||||
this._ranges = [ ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a ledger range
|
||||
*
|
||||
* @param {Number|String} range string (n-n2,n3-n4)
|
||||
*/
|
||||
|
||||
RangeSet.prototype.add = function(range) {
|
||||
assert(typeof range !== 'number' || !isNaN(range), 'Ledger range malformed');
|
||||
|
||||
range = String(range).split(',');
|
||||
|
||||
if (range.length > 1) {
|
||||
return range.forEach(this.add, this);
|
||||
}
|
||||
|
||||
range = range[0].split('-').map(Number);
|
||||
|
||||
var lRange = {
|
||||
start: range[0],
|
||||
end: range[range.length === 1 ? 0 : 1]
|
||||
};
|
||||
|
||||
// Comparisons on NaN should be falsy
|
||||
assert(lRange.start <= lRange.end, 'Ledger range malformed');
|
||||
|
||||
var insertionPoint = lodash.sortedIndex(this._ranges, lRange, function(r) {
|
||||
return r.start;
|
||||
});
|
||||
|
||||
this._ranges.splice(insertionPoint, 0, lRange);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check presence of ledger in range
|
||||
*
|
||||
* @param {Number|String} ledger
|
||||
* @return Boolean
|
||||
*/
|
||||
|
||||
RangeSet.prototype.has =
|
||||
RangeSet.prototype.contains = function(ledger) {
|
||||
assert(ledger != null && !isNaN(ledger), 'Ledger must be a number');
|
||||
|
||||
ledger = Number(ledger);
|
||||
|
||||
return this._ranges.some(function(r) {
|
||||
return ledger >= r.start && ledger <= r.end;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset ledger ranges
|
||||
*/
|
||||
|
||||
RangeSet.prototype.reset = function() {
|
||||
this._ranges = [ ];
|
||||
};
|
||||
|
||||
exports.RangeSet = RangeSet;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var async = require('async');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
@@ -24,6 +25,9 @@ function Request(remote, command) {
|
||||
|
||||
this.remote = remote;
|
||||
this.requested = false;
|
||||
this.reconnectTimeout = 1000 * 3;
|
||||
this.successEvent = 'success';
|
||||
this.errorEvent = 'error';
|
||||
this.message = {
|
||||
command: command,
|
||||
id: void(0)
|
||||
@@ -32,22 +36,20 @@ function Request(remote, command) {
|
||||
|
||||
util.inherits(Request, EventEmitter);
|
||||
|
||||
Request.prototype.broadcast = function() {
|
||||
var connectedServers = this.remote.getConnectedServers();
|
||||
this.request(connectedServers);
|
||||
return connectedServers.length;
|
||||
};
|
||||
|
||||
// Send the request to a remote.
|
||||
Request.prototype.request = function(servers, callback) {
|
||||
if (this.requested) {
|
||||
return this;
|
||||
}
|
||||
this.emit('before');
|
||||
|
||||
if (typeof servers === 'function') {
|
||||
callback = servers;
|
||||
}
|
||||
|
||||
this.callback(callback);
|
||||
|
||||
if (this.requested) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.requested = true;
|
||||
this.on('error', function(){});
|
||||
this.emit('request', this.remote);
|
||||
@@ -61,7 +63,129 @@ Request.prototype.request = function(servers, callback) {
|
||||
this.remote.request(this);
|
||||
}
|
||||
|
||||
this.callback(callback);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Broadcast request to all servers, filter responses if a function is
|
||||
* provided. Return first response that satisfies the filter. Pre-filter
|
||||
* requests by ledger_index (if a ledger_index is set on the request), and
|
||||
* automatically retry servers when they reconnect--if they are expected to
|
||||
*
|
||||
* Whew
|
||||
*
|
||||
* @param [Function] fn
|
||||
*/
|
||||
|
||||
Request.prototype.filter =
|
||||
Request.prototype.addFilter =
|
||||
Request.prototype.broadcast = function(filterFn) {
|
||||
var self = this;
|
||||
|
||||
if (!this.requested) {
|
||||
// Defer until requested, and prevent the normal request() from executing
|
||||
this.once('before', function() {
|
||||
self.requested = true;
|
||||
self.broadcast(filterFn);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
var filterFn = typeof filterFn === 'function' ? filterFn : Boolean;
|
||||
var lastResponse = new Error('No servers available');
|
||||
var connectTimeouts = { };
|
||||
var emit = this.emit;
|
||||
|
||||
this.emit = function(event, a, b) {
|
||||
// Proxy success/error events
|
||||
switch (event) {
|
||||
case 'success':
|
||||
case 'error':
|
||||
emit.call(self, 'proposed', a, b);
|
||||
break;
|
||||
default:
|
||||
emit.apply(self, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
function iterator(server, callback) {
|
||||
// Iterator is called in parallel
|
||||
|
||||
if (server.isConnected()) {
|
||||
// Listen for proxied success/error event and apply filter
|
||||
self.once('proposed', function(res) {
|
||||
lastResponse = res;
|
||||
callback(filterFn(res));
|
||||
});
|
||||
|
||||
return server._request(self);
|
||||
}
|
||||
|
||||
// Server is disconnected but should reconnect. Wait for it to reconnect,
|
||||
// and abort after a timeout
|
||||
var serverID = server.getServerID();
|
||||
|
||||
function serverReconnected() {
|
||||
clearTimeout(connectTimeouts[serverID]);
|
||||
connectTimeouts[serverID] = null;
|
||||
iterator(server, callback);
|
||||
};
|
||||
|
||||
connectTimeouts[serverID] = setTimeout(function() {
|
||||
server.removeListener('connect', serverReconnected);
|
||||
callback(false);
|
||||
}, self.reconnectTimeout);
|
||||
|
||||
server.once('connect', serverReconnected);
|
||||
};
|
||||
|
||||
function complete(success) {
|
||||
// Emit success if the filter is satisfied by any server
|
||||
// Emit error if the filter is not satisfied by any server
|
||||
// Include the last response
|
||||
emit.call(self, success ? 'success' : 'error', lastResponse);
|
||||
};
|
||||
|
||||
var servers = this.remote._servers.filter(function(server) {
|
||||
// Pre-filter servers that are disconnected and should not reconnect
|
||||
return (server.isConnected() || server._shouldConnect)
|
||||
// Pre-filter servers that do not contain the ledger in request
|
||||
&& (!self.message.hasOwnProperty('ledger_index')
|
||||
|| server.hasLedger(self.message.ledger_index))
|
||||
&& (!self.message.hasOwnProperty('ledger_index_min')
|
||||
|| self.message.ledger_index_min === -1
|
||||
|| server.hasLedger(self.message.ledger_index_min))
|
||||
&& (!self.message.hasOwnProperty('ledger_index_max')
|
||||
|| self.message.ledger_index_max === -1
|
||||
|| server.hasLedger(self.message.ledger_index_max))
|
||||
});
|
||||
|
||||
// Apply iterator in parallel to connected servers, complete when the
|
||||
// supplied filter function is satisfied once by a server's response
|
||||
async.some(servers, iterator, complete);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.cancel = function() {
|
||||
this.removeAllListeners();
|
||||
this.on('error', function(){});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.setCallback = function(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
this.callback(fn);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.setReconnectTimeout = function(timeout) {
|
||||
if (typeof timeout === 'number' && !isNaN(timeout)) {
|
||||
this.reconnectTimeout = timeout;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -73,6 +197,13 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (typeof successEvent === 'string') {
|
||||
this.successEvent = successEvent;
|
||||
}
|
||||
if (typeof errorEvent === 'string') {
|
||||
this.errorEvent = errorEvent;
|
||||
}
|
||||
|
||||
var called = false;
|
||||
|
||||
function requestSuccess(message) {
|
||||
@@ -94,8 +225,8 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
}
|
||||
};
|
||||
|
||||
this.once(successEvent || 'success', requestSuccess);
|
||||
this.once(errorEvent || 'error' , requestError);
|
||||
this.once(this.successEvent, requestSuccess);
|
||||
this.once(this.errorEvent, requestError);
|
||||
this.request();
|
||||
|
||||
return this;
|
||||
@@ -124,6 +255,7 @@ Request.prototype.timeout = function(duration, callback) {
|
||||
}
|
||||
|
||||
emit.call(self, 'timeout');
|
||||
self.cancel();
|
||||
}, duration);
|
||||
|
||||
this.emit = function() {
|
||||
@@ -157,9 +289,7 @@ Request.prototype.setServer = function(server) {
|
||||
break;
|
||||
};
|
||||
|
||||
if (selected instanceof Server) {
|
||||
this.server = selected;
|
||||
}
|
||||
this.server = selected;
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -222,11 +352,10 @@ Request.prototype.ledgerSelect = function(ledger) {
|
||||
case 'validated':
|
||||
this.message.ledger_index = ledger;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Number(ledger)) {
|
||||
if (Number(ledger) && isFinite(Number(ledger))) {
|
||||
this.message.ledger_index = Number(ledger);
|
||||
} else if (/^[A-F0-9]+$/.test(ledger)) {
|
||||
} else if (/^[A-F0-9]{64}$/.test(ledger)) {
|
||||
this.message.ledger_hash = ledger;
|
||||
}
|
||||
break;
|
||||
@@ -236,12 +365,12 @@ Request.prototype.ledgerSelect = function(ledger) {
|
||||
};
|
||||
|
||||
Request.prototype.accountRoot = function(account) {
|
||||
this.message.account_root = UInt160.json_rewrite(account);
|
||||
this.message.account_root = UInt160.json_rewrite(account);
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.index = function(index) {
|
||||
this.message.index = index;
|
||||
this.message.index = index;
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -250,8 +379,8 @@ Request.prototype.index = function(index) {
|
||||
// --> seq : sequence number of transaction creating offer (integer)
|
||||
Request.prototype.offerId = function(account, sequence) {
|
||||
this.message.offer = {
|
||||
account: UInt160.json_rewrite(account),
|
||||
seq: sequence
|
||||
account: UInt160.json_rewrite(account),
|
||||
seq: sequence
|
||||
};
|
||||
return this;
|
||||
};
|
||||
@@ -286,8 +415,8 @@ Request.prototype.txBlob = function(json) {
|
||||
|
||||
Request.prototype.rippleState = function(account, issuer, currency) {
|
||||
this.message.ripple_state = {
|
||||
currency : currency,
|
||||
accounts : [
|
||||
currency: currency,
|
||||
accounts: [
|
||||
UInt160.json_rewrite(account),
|
||||
UInt160.json_rewrite(issuer)
|
||||
]
|
||||
@@ -322,12 +451,8 @@ Request.prototype.addAccount = function(account, proposed) {
|
||||
}
|
||||
|
||||
var processedAccount = UInt160.json_rewrite(account);
|
||||
|
||||
if (proposed === true) {
|
||||
this.message.accounts_proposed = (this.message.accounts_proposed || []).concat(processedAccount);
|
||||
} else {
|
||||
this.message.accounts = (this.message.accounts || []).concat(processedAccount);
|
||||
}
|
||||
var prop = proposed === true ? 'accounts_proposed' : 'accounts';
|
||||
this.message[prop] = (this.message[prop] || []).concat(processedAccount);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
var request = require('superagent');
|
||||
var Currency = require('./currency').Currency;
|
||||
|
||||
var RippleTxt = {
|
||||
txts : { }
|
||||
};
|
||||
|
||||
RippleTxt.urlTemplates = [
|
||||
'https://{{domain}}/ripple.txt',
|
||||
'https://www.{{domain}}/ripple.txt',
|
||||
'https://ripple.{{domain}}/ripple.txt',
|
||||
'http://{{domain}}/ripple.txt',
|
||||
'http://www.{{domain}}/ripple.txt',
|
||||
'http://ripple.{{domain}}/ripple.txt'
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets the ripple.txt file for the given domain
|
||||
* @param {string} domain - Domain to retrieve file from
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
RippleTxt.get = function(domain, fn) {
|
||||
var self = this;
|
||||
|
||||
if (self.txts[domain]) {
|
||||
return fn(null, self.txts[domain]);
|
||||
}
|
||||
|
||||
;(function nextUrl(i) {
|
||||
var url = RippleTxt.urlTemplates[i];
|
||||
|
||||
if (!url) {
|
||||
return fn(new Error('No ripple.txt found'));
|
||||
}
|
||||
|
||||
url = url.replace('{{domain}}', domain);
|
||||
|
||||
request.get(url, function(err, resp) {
|
||||
if (err || !resp.text) {
|
||||
return nextUrl(++i);
|
||||
}
|
||||
|
||||
var sections = self.parse(resp.text);
|
||||
self.txts[domain] = sections;
|
||||
|
||||
fn(null, sections);
|
||||
});
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a ripple.txt file
|
||||
* @param {string} txt - Unparsed ripple.txt data
|
||||
*/
|
||||
|
||||
RippleTxt.parse = function(txt) {
|
||||
var currentSection = '';
|
||||
var sections = { };
|
||||
|
||||
txt = txt.replace(/\r?\n/g, '\n').split('\n');
|
||||
|
||||
for (var i = 0, l = txt.length; i < l; i++) {
|
||||
var line = txt[i];
|
||||
|
||||
if (!line.length || line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] === '[' && line[line.length - 1] === ']') {
|
||||
currentSection = line.slice(1, line.length - 1);
|
||||
sections[currentSection] = [];
|
||||
} else {
|
||||
line = line.replace(/^\s+|\s+$/g, '');
|
||||
if (sections[currentSection]) {
|
||||
sections[currentSection].push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sections;
|
||||
};
|
||||
|
||||
/**
|
||||
* extractDomain
|
||||
* attempt to extract the domain from a given url
|
||||
* returns the url if unsuccessful
|
||||
* @param {Object} url
|
||||
*/
|
||||
|
||||
RippleTxt.extractDomain = function (url) {
|
||||
match = /[^.]*\.[^.]{2,3}(?:\.[^.]{2,3})?([^.\?][^\?.]+?)?$/.exec(url);
|
||||
return match && match[0] ? match[0] : url;
|
||||
};
|
||||
|
||||
/**
|
||||
* getCurrencies
|
||||
* returns domain, issuer account and currency object
|
||||
* for each currency found in the domain's ripple.txt file
|
||||
* @param {Object} domain
|
||||
* @param {Object} fn
|
||||
*/
|
||||
|
||||
RippleTxt.getCurrencies = function(domain, fn) {
|
||||
domain = RippleTxt.extractDomain(domain);
|
||||
this.get(domain, function(err, txt) {
|
||||
if (err) {
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
if (err || !txt.currencies || !txt.accounts) {
|
||||
return fn(null, []);
|
||||
}
|
||||
|
||||
//NOTE: this won't be accurate if there are
|
||||
//multiple issuer accounts with different
|
||||
//currencies associated with each.
|
||||
var issuer = txt.accounts[0];
|
||||
var currencies = [];
|
||||
|
||||
txt.currencies.forEach(function(currency) {
|
||||
currencies.push({
|
||||
issuer : issuer,
|
||||
currency : Currency.from_json(currency),
|
||||
domain : domain
|
||||
});
|
||||
});
|
||||
|
||||
fn(null, currencies);
|
||||
});
|
||||
};
|
||||
|
||||
exports.RippleTxt = RippleTxt;
|
||||
@@ -6,8 +6,6 @@ var extend = require('extend');
|
||||
var utils = require('./utils');
|
||||
var sjcl = utils.sjcl;
|
||||
|
||||
var BigInteger = utils.jsbn.BigInteger;
|
||||
|
||||
var Base = require('./base').Base;
|
||||
var UInt = require('./uint').UInt;
|
||||
var UInt256 = require('./uint256').UInt256;
|
||||
@@ -15,8 +13,7 @@ var UInt160 = require('./uint160').UInt160;
|
||||
var KeyPair = require('./keypair').KeyPair;
|
||||
|
||||
var Seed = extend(function () {
|
||||
// Internal form: NaN or BigInteger
|
||||
this._curve = sjcl.ecc.curves.c256;
|
||||
this._curve = sjcl.ecc.curves.k256;
|
||||
this._value = NaN;
|
||||
}, UInt);
|
||||
|
||||
@@ -60,7 +57,7 @@ Seed.prototype.parse_passphrase = function (j) {
|
||||
};
|
||||
|
||||
Seed.prototype.to_json = function () {
|
||||
if (!(this._value instanceof BigInteger)) {
|
||||
if (!(this.is_valid())) {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
var extend = require('extend');
|
||||
var binformat = require('./binformat');
|
||||
var stypes = require('./serializedtypes');
|
||||
var UInt256 = require('./uint256').UInt256;
|
||||
var Crypt = require('./crypt').Crypt;
|
||||
var utils = require('./utils');
|
||||
|
||||
var sjcl = utils.sjcl;
|
||||
var BigInteger = utils.jsbn.BigInteger;
|
||||
|
||||
var TRANSACTION_TYPES = { };
|
||||
|
||||
@@ -27,6 +26,13 @@ Object.keys(binformat.ter).forEach(function(key) {
|
||||
TRANSACTION_RESULTS[binformat.ter[key]] = key;
|
||||
});
|
||||
|
||||
function normalize_sjcl_bn_hex(string) {
|
||||
var hex = string.slice(2); // remove '0x' prefix
|
||||
// now strip leading zeros
|
||||
var i = _.findIndex(hex, function(c) { return c !== '0'; });
|
||||
return i >= 0 ? hex.slice(i) : '0';
|
||||
}
|
||||
|
||||
function SerializedObject(buf) {
|
||||
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf)) ) {
|
||||
this.buffer = buf;
|
||||
@@ -38,11 +44,11 @@ function SerializedObject(buf) {
|
||||
throw new Error('Invalid buffer passed.');
|
||||
}
|
||||
this.pointer = 0;
|
||||
};
|
||||
}
|
||||
|
||||
SerializedObject.from_json = function(obj) {
|
||||
// Create a copy of the object so we don't modify it
|
||||
var obj = extend({}, obj);
|
||||
obj = extend(true, {}, obj);
|
||||
var so = new SerializedObject();
|
||||
var typedef;
|
||||
|
||||
@@ -103,8 +109,8 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
|
||||
|
||||
if (binformat.REQUIRED === requirement && obj[field] === void(0)) {
|
||||
missing_fields.push(field);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (missing_fields.length > 0) {
|
||||
var object_name;
|
||||
@@ -114,12 +120,12 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
|
||||
} else if (obj.LedgerEntryType != null){
|
||||
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
|
||||
} else {
|
||||
object_name = "TransactionMetaData";
|
||||
object_name = 'TransactionMetaData';
|
||||
}
|
||||
|
||||
throw new Error(object_name + " is missing fields: " +
|
||||
throw new Error(object_name + ' is missing fields: ' +
|
||||
JSON.stringify(missing_fields));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
SerializedObject.prototype.append = function(bytes) {
|
||||
@@ -152,7 +158,7 @@ function readOrPeek(advance) {
|
||||
|
||||
return result;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
SerializedObject.prototype.read = readOrPeek(true);
|
||||
|
||||
@@ -209,8 +215,8 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
|
||||
|
||||
if (typeof structure.to_json === 'function') {
|
||||
output = structure.to_json();
|
||||
} else if (structure instanceof BigInteger) {
|
||||
output = structure.toString(16).toUpperCase();
|
||||
} else if (structure instanceof sjcl.bn) {
|
||||
output = ('0000000000000000' + normalize_sjcl_bn_hex(structure.toString()).toUpperCase()).slice(-16);
|
||||
} else {
|
||||
//new Array or Object
|
||||
output = new structure.constructor();
|
||||
@@ -248,15 +254,15 @@ SerializedObject.prototype.serialize = function(typedef, obj) {
|
||||
|
||||
SerializedObject.prototype.hash = function(prefix) {
|
||||
var sign_buffer = new SerializedObject();
|
||||
|
||||
|
||||
// Add hashing prefix
|
||||
if ("undefined" !== typeof prefix) {
|
||||
if ('undefined' !== typeof prefix) {
|
||||
stypes.Int32.serialize(sign_buffer, prefix);
|
||||
}
|
||||
|
||||
// Copy buffer to temporary buffer
|
||||
sign_buffer.append(this.buffer);
|
||||
|
||||
|
||||
// XXX We need a proper Buffer class then Crypt could accept that
|
||||
var bits = sjcl.codec.bytes.toBits(sign_buffer.buffer);
|
||||
return Crypt.hashSha512Half(bits);
|
||||
@@ -312,7 +318,7 @@ SerializedObject.sort_typedef = function(typedef) {
|
||||
function sort_field_compare(a, b) {
|
||||
// Sort by type id first, then by field id
|
||||
return a[3] !== b[3] ? stypes[a[3]].id - stypes[b[3]].id : a[2] - b[2];
|
||||
};
|
||||
}
|
||||
|
||||
return typedef.sort(sort_field_compare);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Type definitions for binary format.
|
||||
*
|
||||
@@ -6,66 +8,87 @@
|
||||
* SerializedObject.parse() or SerializedObject.serialize().
|
||||
*/
|
||||
|
||||
var assert = require('assert');
|
||||
var extend = require('extend');
|
||||
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 utils = require('./utils');
|
||||
var sjcl = utils.sjcl;
|
||||
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 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
|
||||
});
|
||||
|
||||
// Shortcuts
|
||||
var hex = sjcl.codec.hex;
|
||||
var bytes = sjcl.codec.bytes;
|
||||
|
||||
var BigInteger = utils.jsbn.BigInteger;
|
||||
|
||||
|
||||
var SerializedType = function (methods) {
|
||||
function SerializedType(methods) {
|
||||
extend(this, methods);
|
||||
};
|
||||
}
|
||||
|
||||
function isNumber(val) {
|
||||
return typeof val === 'number' && isFinite(val);
|
||||
};
|
||||
}
|
||||
|
||||
function isString(val) {
|
||||
return typeof val === 'string';
|
||||
};
|
||||
}
|
||||
|
||||
function isHexInt64String(val) {
|
||||
return isString(val) && /^[0-9A-F]{0,16}$/i.test(val);
|
||||
};
|
||||
}
|
||||
|
||||
function isCurrencyString(val) {
|
||||
return isString(val) && /^[A-Z0-9]{3}$/.test(val);
|
||||
};
|
||||
|
||||
function isBigInteger(val) {
|
||||
return val instanceof BigInteger;
|
||||
};
|
||||
|
||||
function serialize_hex(so, hexData, noLength) {
|
||||
var byteData = bytes.fromBits(hex.toBits(hexData));
|
||||
function serializeBits(so, bits, noLength) {
|
||||
var byteData = sjcl.codec.bytes.fromBits(bits);
|
||||
if (!noLength) {
|
||||
SerializedType.serialize_varint(so, byteData.length);
|
||||
}
|
||||
so.append(byteData);
|
||||
};
|
||||
}
|
||||
|
||||
function serializeHex(so, hexData, noLength) {
|
||||
serializeBits(so, sjcl.codec.hex.toBits(hexData), noLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* parses bytes as hex
|
||||
*
|
||||
* @param {Array} byte_array bytes
|
||||
* @return {String} hex string
|
||||
*/
|
||||
function convert_bytes_to_hex (byte_array) {
|
||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
|
||||
};
|
||||
function convertByteArrayToHex(byte_array) {
|
||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array))
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
function convertHexToString(hexString) {
|
||||
var bits = sjcl.codec.hex.toBits(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) {
|
||||
@@ -79,7 +102,7 @@ SerializedType.serialize_varint = function (so, val) {
|
||||
so.append([193 + (val >>> 8), val & 0xff]);
|
||||
} else if (val <= 918744) {
|
||||
val -= 12481;
|
||||
so.append([ 241 + (val >>> 16), val >>> 8 & 0xff, val & 0xff ]);
|
||||
so.append([241 + (val >>> 16), val >>> 8 & 0xff, val & 0xff]);
|
||||
} else {
|
||||
throw new Error('Variable integer overflow.');
|
||||
}
|
||||
@@ -107,33 +130,39 @@ 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 append_byte_array(so, val, bytes) {
|
||||
function convertIntegerToByteArray(val, bytes) {
|
||||
if (!isNumber(val)) {
|
||||
throw new Error('Value is not a number', bytes);
|
||||
}
|
||||
|
||||
if (val < 0 || val >= Math.pow(256, bytes)) {
|
||||
throw new Error('Value out of bounds');
|
||||
throw new Error('Value out of bounds ');
|
||||
}
|
||||
|
||||
var newBytes = [ ];
|
||||
|
||||
for (var i=0; i<bytes; i++) {
|
||||
for (var i = 0; i < bytes; i++) {
|
||||
newBytes.unshift(val >>> (i * 8) & 0xff);
|
||||
}
|
||||
|
||||
so.append(newBytes);
|
||||
};
|
||||
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;
|
||||
|
||||
@@ -141,18 +170,18 @@ function readAndSum(so, bytes) {
|
||||
throw new Error('This function only supports up to four bytes.');
|
||||
}
|
||||
|
||||
for (var i=0; i<bytes; i++) {
|
||||
for (var i = 0; i < bytes; i++) {
|
||||
var byte = so.read(1)[0];
|
||||
sum += (byte << (8 * (bytes - i - 1)));
|
||||
}
|
||||
|
||||
// Convert to unsigned integer
|
||||
return sum >>> 0;
|
||||
};
|
||||
}
|
||||
|
||||
var STInt8 = exports.Int8 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
append_byte_array(so, val, 1);
|
||||
so.append(convertIntegerToByteArray(val, 1));
|
||||
},
|
||||
parse: function (so) {
|
||||
return readAndSum(so, 1);
|
||||
@@ -161,9 +190,92 @@ 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) {
|
||||
append_byte_array(so, val, 2);
|
||||
so.append(convertIntegerToByteArray(val, 2));
|
||||
},
|
||||
parse: function (so) {
|
||||
return readAndSum(so, 2);
|
||||
@@ -174,7 +286,7 @@ STInt16.id = 1;
|
||||
|
||||
var STInt32 = exports.Int32 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
append_byte_array(so, val, 4);
|
||||
so.append(convertIntegerToByteArray(val, 4));
|
||||
},
|
||||
parse: function (so) {
|
||||
return readAndSum(so, 4);
|
||||
@@ -192,40 +304,25 @@ var STInt64 = exports.Int64 = new SerializedType({
|
||||
if (val < 0) {
|
||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
||||
}
|
||||
bigNumObject = new BigInteger(String(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 BigInteger(val, 16);
|
||||
} else if (isBigInteger(val)) {
|
||||
if (val.compareTo(BigInteger.ZERO) < 0) {
|
||||
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.');
|
||||
}
|
||||
bigNumObject = val;
|
||||
} else {
|
||||
throw new Error('Invalid type for Int64');
|
||||
}
|
||||
|
||||
var hex = bigNumObject.toString(16);
|
||||
|
||||
if (hex.length > 16) {
|
||||
throw new Error('Int64 is too large');
|
||||
}
|
||||
|
||||
while (hex.length < 16) {
|
||||
hex = '0' + hex;
|
||||
}
|
||||
|
||||
serialize_hex(so, hex, true); //noLength = true
|
||||
serializeBits(so, bigNumObject.toBits(64), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
var bytes = so.read(8);
|
||||
// We need to add a 0, so if the high bit is set it won't think it's a
|
||||
// pessimistic numeric fraek. What doth lief?
|
||||
var result = new BigInteger([0].concat(bytes), 256);
|
||||
assert(result instanceof BigInteger);
|
||||
return result;
|
||||
return SJCL_BN.fromBits(sjcl.codec.bytes.toBits(bytes));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -237,7 +334,7 @@ var STHash128 = exports.Hash128 = new SerializedType({
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error('Invalid Hash128');
|
||||
}
|
||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
||||
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
return UInt128.from_bytes(so.read(16));
|
||||
@@ -252,7 +349,7 @@ var STHash256 = exports.Hash256 = new SerializedType({
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error('Invalid Hash256');
|
||||
}
|
||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
||||
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
return UInt256.from_bytes(so.read(32));
|
||||
@@ -267,7 +364,7 @@ var STHash160 = exports.Hash160 = new SerializedType({
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error('Invalid Hash160');
|
||||
}
|
||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
||||
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
return UInt160.from_bytes(so.read(20));
|
||||
@@ -278,11 +375,12 @@ STHash160.id = 17;
|
||||
|
||||
// Internal
|
||||
var STCurrency = new SerializedType({
|
||||
serialize: function (so, val, xrp_as_ascii) {
|
||||
serialize: function (so, val) {
|
||||
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);
|
||||
@@ -292,10 +390,11 @@ 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.
|
||||
//if (!currency.is_valid()) {
|
||||
// throw new Error('Invalid currency: '+convert_bytes_to_hex(bytes));
|
||||
//}
|
||||
// deserialization to be usable, we need to allow invalid results for
|
||||
// now.
|
||||
// if (!currency.is_valid()) {
|
||||
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
|
||||
// }
|
||||
return currency;
|
||||
}
|
||||
});
|
||||
@@ -303,18 +402,26 @@ 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.');
|
||||
}
|
||||
|
||||
var value = new BigNumber(amount.to_text());
|
||||
var offset = value.e - 15;
|
||||
|
||||
// Amount (64-bit integer)
|
||||
var valueBytes = utils.arraySet(8, 0);
|
||||
|
||||
if (amount.is_native()) {
|
||||
var valueHex = amount._value.toString(16);
|
||||
var valueHex = value.abs().toString(16);
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -322,7 +429,7 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
valueHex = '0' + valueHex;
|
||||
}
|
||||
|
||||
valueBytes = bytes.fromBits(hex.toBits(valueHex));
|
||||
valueBytes = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(valueHex));
|
||||
// Clear most significant two bits - these bits should already be 0 if
|
||||
// Amount enforces the range correctly, but we'll clear them anyway just
|
||||
// so this code can make certain guarantees about the encoded value.
|
||||
@@ -344,10 +451,16 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
}
|
||||
|
||||
// Next eight bits: offset/exponent
|
||||
hi |= ((97 + amount._offset) & 0xff) << 22;
|
||||
hi |= ((97 + offset) & 0xff) << 22;
|
||||
|
||||
// Remaining 54 bits: mantissa
|
||||
hi |= amount._value.shiftRight(32).intValue() & 0x3fffff;
|
||||
lo = amount._value.intValue() & 0xffffffff;
|
||||
var mantissaDecimal = utils.getMantissaDecimalString(value.abs());
|
||||
var mantissaHex = (new BigNumber(mantissaDecimal)).toString(16);
|
||||
assert(mantissaHex.length <= 16,
|
||||
'Mantissa hex representation ' + mantissaHex +
|
||||
' exceeds the maximum length of 16');
|
||||
hi |= parseInt(mantissaHex.slice(0, -8), 16) & 0x3fffff;
|
||||
lo = parseInt(mantissaHex.slice(-8), 16);
|
||||
}
|
||||
|
||||
valueBytes = sjcl.codec.bytes.fromBits([hi, lo]);
|
||||
@@ -365,16 +478,17 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
var amount = new Amount();
|
||||
var value_bytes = so.read(8);
|
||||
var is_zero = !(value_bytes[0] & 0x7f);
|
||||
|
||||
for (var i=1; i<8; i++) {
|
||||
for (var i = 1; i < 8; i++) {
|
||||
is_zero = is_zero && !value_bytes[i];
|
||||
}
|
||||
|
||||
var is_negative = !is_zero && !(value_bytes[0] & 0x40);
|
||||
|
||||
if (value_bytes[0] & 0x80) {
|
||||
//non-native
|
||||
// non-native
|
||||
var currency = STCurrency.parse(so);
|
||||
var issuer_bytes = so.read(20);
|
||||
var issuer = UInt160.from_bytes(issuer_bytes);
|
||||
@@ -382,26 +496,23 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
var offset = ((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
|
||||
var mantissa_bytes = value_bytes.slice(1);
|
||||
mantissa_bytes[0] &= 0x3f;
|
||||
var value = new BigInteger(mantissa_bytes, 256);
|
||||
var mantissa = new BigNumber(utils.arrayToHex(mantissa_bytes), 16);
|
||||
var sign = is_negative ? '-' : '';
|
||||
var valueString = sign + mantissa.toString() + 'e' + offset.toString();
|
||||
|
||||
if (value.equals(BigInteger.ZERO) && !is_zero ) {
|
||||
throw new Error('Invalid zero representation');
|
||||
}
|
||||
|
||||
amount._value = value;
|
||||
amount._offset = offset;
|
||||
amount._currency = currency;
|
||||
amount._issuer = issuer;
|
||||
amount._is_native = false;
|
||||
} else {
|
||||
//native
|
||||
var integer_bytes = value_bytes.slice();
|
||||
integer_bytes[0] &= 0x3f;
|
||||
amount._value = new BigInteger(integer_bytes, 256);
|
||||
amount._is_native = true;
|
||||
return Amount.from_json({
|
||||
currency: currency,
|
||||
issuer: issuer.to_json(),
|
||||
value: valueString
|
||||
});
|
||||
}
|
||||
amount._is_negative = !is_zero && !(value_bytes[0] & 0x40);
|
||||
return amount;
|
||||
|
||||
// native
|
||||
var integer_bytes = value_bytes.slice();
|
||||
integer_bytes[0] &= 0x3f;
|
||||
var integer_hex = utils.arrayToHex(integer_bytes);
|
||||
var value = new BigNumber(integer_hex, 16);
|
||||
return Amount.from_json((is_negative ? '-' : '') + value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -410,14 +521,14 @@ STAmount.id = 6;
|
||||
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
if (typeof val === 'string') {
|
||||
serialize_hex(so, val);
|
||||
serializeHex(so, val);
|
||||
} else {
|
||||
throw new Error('Unknown datatype.');
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
var len = this.parse_varint(so);
|
||||
return convert_bytes_to_hex(so.read(len));
|
||||
return convertByteArrayToHex(so.read(len));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -429,7 +540,7 @@ var STAccount = exports.Account = new SerializedType({
|
||||
if (!account.is_valid()) {
|
||||
throw new Error('Invalid account!');
|
||||
}
|
||||
serialize_hex(so, account.to_hex());
|
||||
serializeBits(so, account.to_bits());
|
||||
},
|
||||
parse: function (so) {
|
||||
var len = this.parse_varint(so);
|
||||
@@ -441,7 +552,6 @@ var STAccount = exports.Account = new SerializedType({
|
||||
var result = UInt160.from_bytes(so.read(len));
|
||||
result.set_version(Base.VER_ACCOUNT_ID);
|
||||
|
||||
//console.log('PARSED 160:', result.to_json());
|
||||
if (false && !result.is_valid()) {
|
||||
throw new Error('Invalid Account');
|
||||
}
|
||||
@@ -453,21 +563,21 @@ var STAccount = exports.Account = new SerializedType({
|
||||
STAccount.id = 8;
|
||||
|
||||
var STPathSet = exports.PathSet = new SerializedType({
|
||||
typeBoundary: 0xff,
|
||||
typeEnd: 0x00,
|
||||
typeAccount: 0x01,
|
||||
typeCurrency: 0x10,
|
||||
typeIssuer: 0x20,
|
||||
typeBoundary: 0xff,
|
||||
typeEnd: 0x00,
|
||||
typeAccount: 0x01,
|
||||
typeCurrency: 0x10,
|
||||
typeIssuer: 0x20,
|
||||
serialize: function (so, val) {
|
||||
for (var i=0, l=val.length; i<l; i++) {
|
||||
for (var i = 0, l = val.length; i < l; i++) {
|
||||
// Boundary
|
||||
if (i) {
|
||||
STInt8.serialize(so, this.typeBoundary);
|
||||
}
|
||||
|
||||
for (var j=0, l2=val[i].length; j<l2; j++) {
|
||||
for (var j = 0, l2 = val[i].length; j < l2; j++) {
|
||||
var entry = val[i][j];
|
||||
//if (entry.hasOwnProperty('_value')) {entry = entry._value;}
|
||||
// if (entry.hasOwnProperty('_value')) {entry = entry._value;}
|
||||
var type = 0;
|
||||
|
||||
if (entry.account) {
|
||||
@@ -483,7 +593,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
STInt8.serialize(so, type);
|
||||
|
||||
if (entry.account) {
|
||||
so.append(UInt160.from_json(entry.account).to_bytes());
|
||||
STHash160.serialize(so, entry.account);
|
||||
}
|
||||
|
||||
if (entry.currency) {
|
||||
@@ -492,7 +602,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
}
|
||||
|
||||
if (entry.issuer) {
|
||||
so.append(UInt160.from_json(entry.issuer).to_bytes());
|
||||
STHash160.serialize(so, entry.issuer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,61 +619,64 @@ 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 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.
|
||||
//Now determine: is this an end, boundary, or entry-begin-tag?
|
||||
//console.log('Tag byte:', tag_byte);
|
||||
// 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,
|
||||
if (current_path) { // close the current path, if there is one,
|
||||
path_list.push(current_path);
|
||||
}
|
||||
current_path = [ ]; //and start a new one.
|
||||
current_path = [ ]; // and start a new one.
|
||||
continue;
|
||||
}
|
||||
|
||||
//It's an entry-begin tag.
|
||||
//console.log('It's an entry-begin tag.');
|
||||
// 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;
|
||||
}
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
if (current_path) {
|
||||
//close the current path, if there is one,
|
||||
// close the current path, if there is one,
|
||||
path_list.push(current_path);
|
||||
}
|
||||
|
||||
@@ -574,9 +687,10 @@ 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.
|
||||
var length_as_varint = SerializedType.serialize_varint(so, val.length * 32);
|
||||
for (var i=0, l=val.length; i<l; i++) {
|
||||
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]);
|
||||
}
|
||||
},
|
||||
@@ -584,7 +698,7 @@ var STVector256 = exports.Vector256 = new SerializedType({
|
||||
var length = this.parse_varint(so);
|
||||
var output = [];
|
||||
// length is number of bytes not number of Hash256
|
||||
for (var i=0; i<length / 32; i++) {
|
||||
for (var i = 0; i < length / 32; i++) {
|
||||
output.push(STHash256.parse(so));
|
||||
}
|
||||
return output;
|
||||
@@ -593,114 +707,122 @@ var STVector256 = exports.Vector256 = new SerializedType({
|
||||
|
||||
STVector256.id = 19;
|
||||
|
||||
exports.serialize = exports.serialize_whatever = serialize;
|
||||
// Internal
|
||||
exports.STMemo = new SerializedType({
|
||||
serialize: function(so, val, no_marker) {
|
||||
var keys = [];
|
||||
|
||||
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);
|
||||
Object.keys(val).forEach(function (key) {
|
||||
// Ignore lowercase field names - they're non-serializable fields by
|
||||
// convention.
|
||||
if (key[0] === key[0].toLowerCase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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...) for a field based on the type bits.
|
||||
var serialized_object_type = exports[binformat.types[type_bits]];
|
||||
//do something with val[keys] and val[keys[i]];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
// Get the parser class (ST...) for a field based on the type bits.
|
||||
var type = exports[binformat.types[type_bits]];
|
||||
|
||||
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
||||
|
||||
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));
|
||||
|
||||
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 = Object.keys(val);
|
||||
|
||||
// Ignore lowercase field names - they're non-serializable fields by
|
||||
// convention.
|
||||
keys = keys.filter(function (key) {
|
||||
return key[0] !== key[0].toLowerCase();
|
||||
});
|
||||
|
||||
keys.forEach(function (key) {
|
||||
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
||||
throw new Error('JSON contains unknown field: "' + key + '"');
|
||||
}
|
||||
|
||||
keys.push(key);
|
||||
});
|
||||
|
||||
// Sort fields
|
||||
keys = sort_fields(keys);
|
||||
|
||||
for (var i=0; i<keys.length; i++) {
|
||||
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 !== undefined) {
|
||||
try {
|
||||
var parsedType = convertHexToString(output.MemoType);
|
||||
|
||||
if (parsedType !== 'unformatted_memo') {
|
||||
output.parsed_memo_type = parsedType;
|
||||
}
|
||||
} catch (e) {
|
||||
// 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 !== 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
|
||||
// this is fine, we won't add the parsed_memo_format field
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
so.read(1);
|
||||
return output;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var STObject = exports.Object = new SerializedType({
|
||||
serialize: function (so, val, no_marker) {
|
||||
var keys = [];
|
||||
|
||||
Object.keys(val).forEach(function (key) {
|
||||
// Ignore lowercase field names - they're non-serializable fields by
|
||||
// convention.
|
||||
if (key[0] === key[0].toLowerCase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
||||
throw new Error('JSON contains unknown field: "' + key + '"');
|
||||
}
|
||||
|
||||
keys.push(key);
|
||||
});
|
||||
|
||||
// Sort fields
|
||||
keys = sort_fields(keys);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
serialize(so, keys[i], val[keys[i]]);
|
||||
}
|
||||
|
||||
if (!no_marker) {
|
||||
//Object ending marker
|
||||
// Object ending marker
|
||||
STInt8.serialize(so, 0xe1);
|
||||
}
|
||||
},
|
||||
@@ -720,11 +842,12 @@ STObject.id = 14;
|
||||
|
||||
var STArray = exports.Array = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
for (var i=0, l=val.length; i<l; i++) {
|
||||
for (var i = 0, l = val.length; i < l; i++) {
|
||||
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];
|
||||
@@ -732,7 +855,7 @@ var STArray = exports.Array = new SerializedType({
|
||||
serialize(so, field_name, value);
|
||||
}
|
||||
|
||||
//Array ending marker
|
||||
// Array ending marker
|
||||
STInt8.serialize(so, 0xf1);
|
||||
},
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
var util = require('util');
|
||||
var url = require('url');
|
||||
var LRU = require('lru-cache');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Amount = require('./amount').Amount;
|
||||
var Transaction = require('./transaction').Transaction;
|
||||
var RangeSet = require('./rangeset').RangeSet;
|
||||
var log = require('./log').internal.sub('server');
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ function Server(remote, opts) {
|
||||
throw new TypeError('Server configuration is not an Object');
|
||||
}
|
||||
|
||||
if (!Server.domainRE.test(opts.host)) {
|
||||
if (!Server.DOMAIN_RE.test(opts.host)) {
|
||||
throw new Error('Server host is malformed, use "host" and "port" server configuration');
|
||||
}
|
||||
|
||||
@@ -57,6 +58,8 @@ function Server(remote, opts) {
|
||||
this._connected = false;
|
||||
this._shouldConnect = false;
|
||||
this._state = 'offline';
|
||||
this._ledgerRanges = new RangeSet();
|
||||
this._ledgerMap = LRU({ max: 200 });
|
||||
|
||||
this._id = 0; // request ID
|
||||
this._retry = 0;
|
||||
@@ -118,31 +121,29 @@ function Server(remote, opts) {
|
||||
self._updateScore('loadchange', load);
|
||||
});
|
||||
|
||||
// If server is not up-to-date, request server_info
|
||||
// for getting pubkey_node & hostid information.
|
||||
// Otherwise this information is available on the
|
||||
// initial server subscribe response
|
||||
this.on('connect', function requestServerID() {
|
||||
if (self._pubkey_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.on('response_server_info', function setServerID(message) {
|
||||
try {
|
||||
self._pubkey_node = message.info.pubkey_node;
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
var serverInfoRequest = self._remote.requestServerInfo();
|
||||
serverInfoRequest.on('error', function() { });
|
||||
self._request(serverInfoRequest);
|
||||
this.on('connect', function() {
|
||||
self.requestServerID();
|
||||
});
|
||||
};
|
||||
|
||||
util.inherits(Server, EventEmitter);
|
||||
|
||||
Server.domainRE = /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?)*\.?$/;
|
||||
Server.DOMAIN_RE = /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?)*\.?$/;
|
||||
|
||||
Server.TLS_ERRORS = [
|
||||
'UNABLE_TO_GET_ISSUER_CERT', 'UNABLE_TO_GET_CRL',
|
||||
'UNABLE_TO_DECRYPT_CERT_SIGNATURE', 'UNABLE_TO_DECRYPT_CRL_SIGNATURE',
|
||||
'UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY', 'CERT_SIGNATURE_FAILURE',
|
||||
'CRL_SIGNATURE_FAILURE', 'CERT_NOT_YET_VALID', 'CERT_HAS_EXPIRED',
|
||||
'CRL_NOT_YET_VALID', 'CRL_HAS_EXPIRED', 'ERROR_IN_CERT_NOT_BEFORE_FIELD',
|
||||
'ERROR_IN_CERT_NOT_AFTER_FIELD', 'ERROR_IN_CRL_LAST_UPDATE_FIELD',
|
||||
'ERROR_IN_CRL_NEXT_UPDATE_FIELD', 'OUT_OF_MEM',
|
||||
'DEPTH_ZERO_SELF_SIGNED_CERT', 'SELF_SIGNED_CERT_IN_CHAIN',
|
||||
'UNABLE_TO_GET_ISSUER_CERT_LOCALLY', 'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
|
||||
'CERT_CHAIN_TOO_LONG', 'CERT_REVOKED', 'INVALID_CA',
|
||||
'PATH_LENGTH_EXCEEDED', 'INVALID_PURPOSE', 'CERT_UNTRUSTED',
|
||||
'CERT_REJECTED'
|
||||
];
|
||||
|
||||
/**
|
||||
* Server states that we will treat as the server being online.
|
||||
@@ -236,6 +237,31 @@ Server.prototype._checkActivity = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If server is not up-to-date, request server_info for getting pubkey_node
|
||||
* & hostid information. Otherwise this information is available on the
|
||||
* initial server subscribe response
|
||||
*/
|
||||
|
||||
Server.prototype.requestServerID = function() {
|
||||
var self = this;
|
||||
|
||||
if (this._pubkey_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.on('response_server_info', function setServerID(message) {
|
||||
try {
|
||||
self._pubkey_node = message.info.pubkey_node;
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
var serverInfoRequest = this._remote.requestServerInfo();
|
||||
serverInfoRequest.on('error', function() { });
|
||||
this._request(serverInfoRequest);
|
||||
};
|
||||
|
||||
/**
|
||||
* Server maintains a score for request prioritization.
|
||||
*
|
||||
@@ -329,6 +355,8 @@ Server.prototype.disconnect = function() {
|
||||
this._lastLedgerClose = NaN;
|
||||
this._score = 0;
|
||||
this._shouldConnect = false;
|
||||
this._ledgerRanges.reset();
|
||||
this._ledgerMap.reset();
|
||||
this._setState('offline');
|
||||
|
||||
if (this._ws) {
|
||||
@@ -421,6 +449,11 @@ Server.prototype.connect = function() {
|
||||
log.info(self.getServerID(), 'onerror:', e.data || e);
|
||||
}
|
||||
|
||||
if (Server.TLS_ERRORS.indexOf(e.message) !== -1) {
|
||||
// Unrecoverable
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Most connection errors for WebSockets are conveyed as 'close' events with
|
||||
// code 1006. This is done for security purposes and therefore unlikely to
|
||||
// ever change.
|
||||
@@ -546,6 +579,8 @@ Server.prototype._handleMessage = function(message) {
|
||||
Server.prototype._handleLedgerClosed = function(message) {
|
||||
this._lastLedgerIndex = message.ledger_index;
|
||||
this._lastLedgerClose = Date.now();
|
||||
this._ledgerRanges.add(message.ledger_index);
|
||||
this._ledgerMap.set(message.ledger_hash, message.ledger_index);
|
||||
this.emit('ledger_closed', message);
|
||||
};
|
||||
|
||||
@@ -621,24 +656,33 @@ Server.prototype._handlePathFind = function(message) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle subscription response messages. Subscription response
|
||||
* messages indicate that a connection to the server is ready
|
||||
* Handle initial subscription response message. The server is considered
|
||||
* `connected` after it has received a response to initial subscription to
|
||||
* ledger and server streams
|
||||
*
|
||||
* @param {Object} message
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Server.prototype._handleResponseSubscribe = function(message) {
|
||||
if (!this._remote._allow_partial_history
|
||||
if (this.isConnected()) {
|
||||
// This function only concerns initializing the server's internal
|
||||
// state after a connection
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._remote.allow_partial_history
|
||||
&& !Server.hasFullLedgerHistory(message)) {
|
||||
// Server has partial history and Remote has been configured to disallow
|
||||
// servers with incomplete history
|
||||
return this.reconnect();
|
||||
}
|
||||
|
||||
if (message.pubkey_node) {
|
||||
// pubkey_node is used to identify the server
|
||||
this._pubkey_node = message.pubkey_node;
|
||||
}
|
||||
|
||||
if (Server.isLoadStatus(message)) {
|
||||
this._load_base = message.load_base || 256;
|
||||
this._load_factor = message.load_factor || 256;
|
||||
@@ -647,6 +691,12 @@ Server.prototype._handleResponseSubscribe = function(message) {
|
||||
this._reserve_base = message.reserve_base;
|
||||
this._reserve_inc = message.reserve_inc;
|
||||
}
|
||||
|
||||
if (message.validated_ledgers) {
|
||||
// Add validated ledgers to ledger range set
|
||||
this._ledgerRanges.add(message.validated_ledgers);
|
||||
}
|
||||
|
||||
if (~Server.onlineStates.indexOf(message.server_status)) {
|
||||
this._setState('online');
|
||||
}
|
||||
@@ -751,6 +801,12 @@ Server.prototype._request = function(request) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get server connected status
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
Server.prototype.isConnected =
|
||||
Server.prototype._isConnected = function() {
|
||||
return this._connected;
|
||||
@@ -760,22 +816,16 @@ Server.prototype._isConnected = function() {
|
||||
* Calculate transaction fee
|
||||
*
|
||||
* @param {Transaction|Number} Fee units for a provided transaction
|
||||
* @return {Number} Final fee in XRP for specified number of fee units
|
||||
* @return {String} Final fee in XRP for specified number of fee units
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Server.prototype._computeFee = function(transaction) {
|
||||
var units;
|
||||
|
||||
if (transaction instanceof Transaction) {
|
||||
units = transaction._getFeeUnits();
|
||||
} else if (typeof transaction === 'number') {
|
||||
units = transaction;
|
||||
} else {
|
||||
Server.prototype._computeFee = function(feeUnits) {
|
||||
if (isNaN(feeUnits)) {
|
||||
throw new Error('Invalid argument');
|
||||
}
|
||||
|
||||
return this._feeTx(units).to_json();
|
||||
return this._feeTx(Number(feeUnits)).to_json();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -831,6 +881,36 @@ Server.prototype._reserve = function(ownerCount) {
|
||||
return reserve_base.add(reserve_inc.product_human(owner_count));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that server has seen closed ledger
|
||||
*
|
||||
* @param {string|number} ledger hash or index
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
Server.prototype.hasLedger = function(ledger) {
|
||||
var result = false;
|
||||
|
||||
if (typeof ledger === 'string' && /^[A-F0-9]{64}$/.test(ledger)) {
|
||||
result = this._ledgerMap.has(ledger);
|
||||
} else if (ledger != null && !isNaN(ledger)) {
|
||||
result = this._ledgerRanges.has(ledger);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get ledger index of last seen validated ledger
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
|
||||
Server.prototype.getLastLedger =
|
||||
Server.prototype.getLastLedgerIndex = function() {
|
||||
return this._lastLedgerIndex;
|
||||
};
|
||||
|
||||
exports.Server = Server;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
var Crypt = require('./crypt').Crypt;
|
||||
var Message = require('./message').Message;
|
||||
var parser = require("url");
|
||||
var querystring = require('querystring');
|
||||
var extend = require("extend");
|
||||
|
||||
var SignedRequest = function (config) {
|
||||
// XXX Constructor should be generalized and constructing from an Angular.js
|
||||
// $http config should be a SignedRequest.from... utility method.
|
||||
this.config = extend(true, {}, config);
|
||||
if (!this.config.data) this.config.data = {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a string from request parameters that
|
||||
* will be used to sign a request
|
||||
* @param {Object} parsed - parsed url
|
||||
* @param {Object} date
|
||||
* @param {Object} mechanism - type of signing
|
||||
*/
|
||||
SignedRequest.prototype.getStringToSign = function (parsed, date, mechanism) {
|
||||
// XXX This method doesn't handle signing GET requests correctly. The data
|
||||
// field will be merged into the search string, not the request body.
|
||||
|
||||
// Sort the properties of the JSON object into canonical form
|
||||
var canonicalData = JSON.stringify(copyObjectWithSortedKeys(this.config.data));
|
||||
|
||||
// Canonical request using Amazon's v4 signature format
|
||||
// See: http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
var canonicalRequest = [
|
||||
this.config.method || 'GET',
|
||||
parsed.pathname || '',
|
||||
parsed.search || '',
|
||||
// XXX Headers signing not supported
|
||||
'',
|
||||
'',
|
||||
Crypt.hashSha512(canonicalData).toLowerCase()
|
||||
].join('\n');
|
||||
|
||||
// String to sign inspired by Amazon's v4 signature format
|
||||
// See: http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
||||
//
|
||||
// We don't have a credential scope, so we skip it.
|
||||
//
|
||||
// But that modifies the format, so the format ID is RIPPLE1, instead of AWS4.
|
||||
return [
|
||||
mechanism,
|
||||
date,
|
||||
Crypt.hashSha512(canonicalRequest).toLowerCase()
|
||||
].join('\n');
|
||||
};
|
||||
|
||||
//prepare for signing
|
||||
function copyObjectWithSortedKeys(object) {
|
||||
if (isPlainObject(object)) {
|
||||
var newObj = {};
|
||||
var keysSorted = Object.keys(object).sort();
|
||||
var key;
|
||||
for (var i in keysSorted) {
|
||||
key = keysSorted[i];
|
||||
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
||||
newObj[key] = copyObjectWithSortedKeys(object[key]);
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
} else if (Array.isArray(object)) {
|
||||
return object.map(copyObjectWithSortedKeys);
|
||||
} else {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
//from npm extend
|
||||
function isPlainObject(obj) {
|
||||
var hasOwn = Object.prototype.hasOwnProperty;
|
||||
var toString = Object.prototype.toString;
|
||||
|
||||
if (!obj || toString.call(obj) !== '[object Object]' || obj.nodeType || obj.setInterval)
|
||||
return false;
|
||||
|
||||
var has_own_constructor = hasOwn.call(obj, 'constructor');
|
||||
var has_is_property_of_method = hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
|
||||
// Not own constructor property must be Object
|
||||
if (obj.constructor && !has_own_constructor && !has_is_property_of_method)
|
||||
return false;
|
||||
|
||||
// Own properties are enumerated firstly, so to speed up,
|
||||
// if last one is own, then all properties are own.
|
||||
var key;
|
||||
for ( key in obj ) {}
|
||||
|
||||
return key === undefined || hasOwn.call( obj, key );
|
||||
};
|
||||
|
||||
/**
|
||||
* HMAC signed request
|
||||
* @param {Object} config
|
||||
* @param {Object} auth_secret
|
||||
* @param {Object} blob_id
|
||||
*/
|
||||
SignedRequest.prototype.signHmac = function (auth_secret, blob_id) {
|
||||
var config = extend(true, {}, this.config);
|
||||
|
||||
// Parse URL
|
||||
var parsed = parser.parse(config.url);
|
||||
var date = dateAsIso8601();
|
||||
var signatureType = 'RIPPLE1-HMAC-SHA512';
|
||||
var stringToSign = this.getStringToSign(parsed, date, signatureType);
|
||||
var signature = Crypt.signString(auth_secret, stringToSign);
|
||||
|
||||
var query = querystring.stringify({
|
||||
signature: Crypt.base64ToBase64Url(signature),
|
||||
signature_date: date,
|
||||
signature_blob_id: blob_id,
|
||||
signature_type: signatureType
|
||||
});
|
||||
|
||||
config.url += (parsed.search ? '&' : '?') + query;
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asymmetric signed request
|
||||
* @param {Object} config
|
||||
* @param {Object} secretKey
|
||||
* @param {Object} account
|
||||
* @param {Object} blob_id
|
||||
*/
|
||||
SignedRequest.prototype.signAsymmetric = function (secretKey, account, blob_id) {
|
||||
var config = extend(true, {}, this.config);
|
||||
|
||||
// Parse URL
|
||||
var parsed = parser.parse(config.url);
|
||||
var date = dateAsIso8601();
|
||||
var signatureType = 'RIPPLE1-ECDSA-SHA512';
|
||||
var stringToSign = this.getStringToSign(parsed, date, signatureType);
|
||||
var signature = Message.signMessage(stringToSign, secretKey);
|
||||
|
||||
var query = querystring.stringify({
|
||||
signature: Crypt.base64ToBase64Url(signature),
|
||||
signature_date: date,
|
||||
signature_blob_id: blob_id,
|
||||
signature_account: account,
|
||||
signature_type: signatureType
|
||||
});
|
||||
|
||||
config.url += (parsed.search ? '&' : '?') + query;
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asymmetric signed request for vault recovery
|
||||
* @param {Object} config
|
||||
* @param {Object} secretKey
|
||||
* @param {Object} username
|
||||
*/
|
||||
SignedRequest.prototype.signAsymmetricRecovery = function (secretKey, username) {
|
||||
var config = extend(true, {}, this.config);
|
||||
|
||||
// Parse URL
|
||||
var parsed = parser.parse(config.url);
|
||||
var date = dateAsIso8601();
|
||||
var signatureType = 'RIPPLE1-ECDSA-SHA512';
|
||||
var stringToSign = this.getStringToSign(parsed, date, signatureType);
|
||||
var signature = Message.signMessage(stringToSign, secretKey);
|
||||
|
||||
var query = querystring.stringify({
|
||||
signature: Crypt.base64ToBase64Url(signature),
|
||||
signature_date: date,
|
||||
signature_username: username,
|
||||
signature_type: signatureType
|
||||
});
|
||||
|
||||
config.url += (parsed.search ? '&' : '?') + query;
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
var dateAsIso8601 = (function () {
|
||||
function pad(n) {
|
||||
return (n < 0 || n > 9 ? "" : "0") + n;
|
||||
}
|
||||
|
||||
return function dateAsIso8601() {
|
||||
var date = new Date();
|
||||
return date.getUTCFullYear() + "-" +
|
||||
pad(date.getUTCMonth() + 1) + "-" +
|
||||
pad(date.getUTCDate()) + "T" +
|
||||
pad(date.getUTCHours()) + ":" +
|
||||
pad(date.getUTCMinutes()) + ":" +
|
||||
pad(date.getUTCSeconds()) + ".000Z";
|
||||
};
|
||||
})();
|
||||
|
||||
// XXX Add methods for verifying requests
|
||||
// SignedRequest.prototype.verifySignatureHmac
|
||||
// SignedRequest.prototype.verifySignatureAsymetric
|
||||
|
||||
exports.SignedRequest = SignedRequest;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
var lodash = require('lodash');
|
||||
var LRU = require('lru-cache');
|
||||
var Transaction = require('./transaction').Transaction;
|
||||
|
||||
/**
|
||||
* Manager for pending transactions
|
||||
*/
|
||||
|
||||
var LRU = require('lru-cache');
|
||||
var Transaction = require('./transaction').Transaction;
|
||||
|
||||
function TransactionQueue() {
|
||||
this._queue = [ ];
|
||||
this._idCache = LRU();
|
||||
this._sequenceCache = LRU();
|
||||
};
|
||||
this._idCache = new LRU({max: 200});
|
||||
this._sequenceCache = new LRU({max: 200});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store received (validated) sequence
|
||||
*
|
||||
* @param {Number} sequence
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.addReceivedSequence = function(sequence) {
|
||||
@@ -23,6 +27,9 @@ TransactionQueue.prototype.addReceivedSequence = function(sequence) {
|
||||
/**
|
||||
* Check that sequence number has been consumed by a validated
|
||||
* transaction
|
||||
*
|
||||
* @param {Number} sequence
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.hasSequence = function(sequence) {
|
||||
@@ -31,6 +38,9 @@ TransactionQueue.prototype.hasSequence = function(sequence) {
|
||||
|
||||
/**
|
||||
* Store received (validated) ID transaction
|
||||
*
|
||||
* @param {String} transaction id
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.addReceivedId = function(id, transaction) {
|
||||
@@ -39,6 +49,9 @@ TransactionQueue.prototype.addReceivedId = function(id, transaction) {
|
||||
|
||||
/**
|
||||
* Get received (validated) transaction by ID
|
||||
*
|
||||
* @param {String} transaction id
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getReceived = function(id) {
|
||||
@@ -48,23 +61,47 @@ TransactionQueue.prototype.getReceived = function(id) {
|
||||
/**
|
||||
* Get a submitted transaction by ID. Transactions
|
||||
* may have multiple associated IDs.
|
||||
*
|
||||
* @param {String} transaction id
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getSubmission = function(id) {
|
||||
var result = void(0);
|
||||
return lodash.find(this._queue, function(tx) {
|
||||
return lodash.contains(tx.submittedIDs, id);
|
||||
});
|
||||
};
|
||||
|
||||
for (var i=0, tx; (tx=this._queue[i]); i++) {
|
||||
if (~tx.submittedIDs.indexOf(id)) {
|
||||
result = tx;
|
||||
break;
|
||||
/**
|
||||
* Get earliest ledger in the pending queue
|
||||
*
|
||||
* @return {Number} ledger
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getMinLedger = function() {
|
||||
if (this.length() < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var result = Infinity;
|
||||
|
||||
for (var i = 0; i < this.length(); i++) {
|
||||
if (this._queue[i].initialSubmitIndex < result) {
|
||||
result = this._queue[i].initialSubmitIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFinite(result)) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a transaction from the queue
|
||||
*
|
||||
* @param {String|Transaction} transaction or id
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.remove = function(tx) {
|
||||
@@ -87,17 +124,41 @@ TransactionQueue.prototype.remove = function(tx) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a transaction to pending queue
|
||||
*
|
||||
* @param {Transaction} transaction
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.push = function(tx) {
|
||||
this._queue.push(tx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate over pending transactions
|
||||
*
|
||||
* @param {Function} iterator
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.forEach = function(fn) {
|
||||
this._queue.forEach(fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Number} length of pending queue
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.length =
|
||||
TransactionQueue.prototype.getLength = function() {
|
||||
return this._queue.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Array} pending queue
|
||||
*/
|
||||
|
||||
TransactionQueue.prototype.getQueue = function() {
|
||||
return this._queue;
|
||||
};
|
||||
|
||||
exports.TransactionQueue = TransactionQueue;
|
||||
|
||||
@@ -2,8 +2,6 @@ var utils = require('./utils');
|
||||
var sjcl = utils.sjcl;
|
||||
var config = require('./config');
|
||||
|
||||
var BigInteger = utils.jsbn.BigInteger;
|
||||
|
||||
//
|
||||
// Abstract UInt class
|
||||
//
|
||||
@@ -11,9 +9,8 @@ var BigInteger = utils.jsbn.BigInteger;
|
||||
//
|
||||
|
||||
var UInt = function() {
|
||||
// Internal form: NaN or BigInteger
|
||||
// Internal form: NaN or sjcl.bn
|
||||
this._value = NaN;
|
||||
|
||||
this._update();
|
||||
};
|
||||
|
||||
@@ -96,6 +93,10 @@ UInt.prototype.clone = function() {
|
||||
UInt.prototype.copyTo = function(d) {
|
||||
d._value = this._value;
|
||||
|
||||
if (this._version_byte !== void(0)) {
|
||||
d._version_byte = this._version_byte;
|
||||
}
|
||||
|
||||
if (typeof d._update === 'function') {
|
||||
d._update();
|
||||
}
|
||||
@@ -104,15 +105,15 @@ UInt.prototype.copyTo = function(d) {
|
||||
};
|
||||
|
||||
UInt.prototype.equals = function(d) {
|
||||
return this._value instanceof BigInteger && d._value instanceof BigInteger && this._value.equals(d._value);
|
||||
return this.is_valid() && d.is_valid() && this._value.equals(d._value);
|
||||
};
|
||||
|
||||
UInt.prototype.is_valid = function() {
|
||||
return this._value instanceof BigInteger;
|
||||
return this._value instanceof sjcl.bn;
|
||||
};
|
||||
|
||||
UInt.prototype.is_zero = function() {
|
||||
return this._value.equals(BigInteger.ZERO);
|
||||
return this.is_valid() && this._value.equals(new sjcl.bn(0));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -142,24 +143,25 @@ UInt.prototype.parse_generic = function(j) {
|
||||
case this.constructor.STR_ZERO:
|
||||
case this.constructor.ACCOUNT_ZERO:
|
||||
case this.constructor.HEX_ZERO:
|
||||
this._value = BigInteger.valueOf();
|
||||
this._value = new sjcl.bn(0);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
case this.constructor.STR_ONE:
|
||||
case this.constructor.ACCOUNT_ONE:
|
||||
case this.constructor.HEX_ONE:
|
||||
this._value = new BigInteger([1]);
|
||||
this._value = new sjcl.bn(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (typeof j !== 'string') {
|
||||
this._value = NaN;
|
||||
} else if (this.constructor.width === j.length) {
|
||||
this._value = new BigInteger(utils.stringToArray(j), 256);
|
||||
var hex = utils.arrayToHex(utils.stringToArray(j));
|
||||
this._value = new sjcl.bn(hex, 16);
|
||||
} else if ((this.constructor.width * 2) === j.length) {
|
||||
// XXX Check char set!
|
||||
this._value = new BigInteger(j, 16);
|
||||
this._value = new sjcl.bn(j, 16);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
@@ -172,7 +174,7 @@ UInt.prototype.parse_generic = function(j) {
|
||||
|
||||
UInt.prototype.parse_hex = function(j) {
|
||||
if (typeof j === 'string' && j.length === (this.constructor.width * 2)) {
|
||||
this._value = new BigInteger(j, 16);
|
||||
this._value = new sjcl.bn(j, 16);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
@@ -186,8 +188,9 @@ UInt.prototype.parse_bits = function(j) {
|
||||
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
var bytes = sjcl.codec.bytes.fromBits(j);
|
||||
this.parse_bytes(bytes);
|
||||
this._value = sjcl.bn.fromBits(j);
|
||||
// var bytes = sjcl.codec.bytes.fromBits(j);
|
||||
// this.parse_bytes(bytes);
|
||||
}
|
||||
|
||||
this._update();
|
||||
@@ -200,7 +203,8 @@ UInt.prototype.parse_bytes = function(j) {
|
||||
if (!Array.isArray(j) || j.length !== this.constructor.width) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
this._value = new BigInteger([0].concat(j), 256);
|
||||
var bits = sjcl.codec.bytes.toBits(j);
|
||||
this._value = sjcl.bn.fromBits(bits);
|
||||
}
|
||||
|
||||
this._update();
|
||||
@@ -213,8 +217,9 @@ UInt.prototype.parse_json = UInt.prototype.parse_hex;
|
||||
|
||||
UInt.prototype.parse_bn = function(j) {
|
||||
if ((j instanceof sjcl.bn) && j.bitLength() <= this.constructor.width * 8) {
|
||||
var bytes = sjcl.codec.bytes.fromBits(j.toBits());
|
||||
this._value = new BigInteger(bytes, 256);
|
||||
// var bytes = sjcl.codec.bytes.fromBits(j.toBits());
|
||||
// this._value = new sjcl.bn(utils.arrayToHex(bytes), 16);
|
||||
this._value = new sjcl.bn(j);
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
@@ -228,7 +233,7 @@ UInt.prototype.parse_number = function(j) {
|
||||
this._value = NaN;
|
||||
|
||||
if (typeof j === 'number' && isFinite(j) && j >= 0) {
|
||||
this._value = new BigInteger(String(j));
|
||||
this._value = new sjcl.bn(j);
|
||||
}
|
||||
|
||||
this._update();
|
||||
@@ -238,51 +243,31 @@ UInt.prototype.parse_number = function(j) {
|
||||
|
||||
// Convert from internal form.
|
||||
UInt.prototype.to_bytes = function() {
|
||||
if (!(this._value instanceof BigInteger)) {
|
||||
if (!this.is_valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var bytes = this._value.toByteArray();
|
||||
|
||||
bytes = bytes.map(function(b) {
|
||||
return (b + 256) % 256;
|
||||
});
|
||||
|
||||
var target = this.constructor.width;
|
||||
|
||||
// XXX Make sure only trim off leading zeros.
|
||||
bytes = bytes.slice(-target);
|
||||
|
||||
while (bytes.length < target) {
|
||||
bytes.unshift(0);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
return sjcl.codec.bytes.fromBits(this.to_bits());
|
||||
};
|
||||
|
||||
UInt.prototype.to_hex = function() {
|
||||
if (!(this._value instanceof BigInteger)) {
|
||||
if (!this.is_valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var bytes = this.to_bytes();
|
||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(bytes)).toUpperCase();
|
||||
return sjcl.codec.hex.fromBits(this.to_bits()).toUpperCase();
|
||||
};
|
||||
|
||||
UInt.prototype.to_json = UInt.prototype.to_hex;
|
||||
|
||||
UInt.prototype.to_bits = function() {
|
||||
if (!(this._value instanceof BigInteger)) {
|
||||
if (!this.is_valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var bytes = this.to_bytes();
|
||||
|
||||
return sjcl.codec.bytes.toBits(bytes);
|
||||
return this._value.toBits(this.constructor.width * 8);
|
||||
};
|
||||
|
||||
UInt.prototype.to_bn = function() {
|
||||
if (!(this._value instanceof BigInteger)) {
|
||||
if (!this.is_valid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ var UInt = require('./uint').UInt;
|
||||
//
|
||||
|
||||
var UInt128 = extend(function () {
|
||||
// Internal form: NaN or BigInteger
|
||||
this._value = NaN;
|
||||
}, UInt);
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ var utils = require('./utils');
|
||||
var config = require('./config');
|
||||
var extend = require('extend');
|
||||
|
||||
var BigInteger = utils.jsbn.BigInteger;
|
||||
|
||||
var UInt = require('./uint').UInt;
|
||||
var Base = require('./base').Base;
|
||||
|
||||
@@ -12,7 +10,6 @@ var Base = require('./base').Base;
|
||||
//
|
||||
|
||||
var UInt160 = extend(function() {
|
||||
// Internal form: NaN or BigInteger
|
||||
this._value = NaN;
|
||||
this._version_byte = void(0);
|
||||
this._update();
|
||||
@@ -49,7 +46,7 @@ UInt160.prototype.parse_json = function(j) {
|
||||
// Allow raw numbers - DEPRECATED
|
||||
// This is used mostly by the test suite and is supported
|
||||
// as a legacy feature only. DO NOT RELY ON THIS BEHAVIOR.
|
||||
this._value = new BigInteger(String(j));
|
||||
this.parse_number(j);
|
||||
this._version_byte = Base.VER_ACCOUNT_ID;
|
||||
} else if (typeof j !== 'string') {
|
||||
this._value = NaN;
|
||||
@@ -83,7 +80,7 @@ UInt160.prototype.parse_generic = function(j) {
|
||||
UInt160.prototype.to_json = function(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
if (this._value instanceof BigInteger) {
|
||||
if (this.is_valid()) {
|
||||
// If this value has a type, return a Base58 encoded string.
|
||||
if (typeof this._version_byte === 'number') {
|
||||
var output = Base.encode_check(this._version_byte, this.to_bytes());
|
||||
|
||||
@@ -7,7 +7,6 @@ var UInt = require('./uint').UInt;
|
||||
//
|
||||
|
||||
var UInt256 = extend(function() {
|
||||
// Internal form: NaN or BigInteger
|
||||
this._value = NaN;
|
||||
}, UInt);
|
||||
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
|
||||
function getMantissaDecimalString(bignum) {
|
||||
var mantissa = bignum.toPrecision(16)
|
||||
.replace(/\./, '') // remove decimal point
|
||||
.replace(/e.*/, '') // remove scientific notation
|
||||
.replace(/^0*/, ''); // remove leading zeroes
|
||||
while (mantissa.length < 16) {
|
||||
mantissa += '0'; // add trailing zeroes until length is 16
|
||||
}
|
||||
return mantissa;
|
||||
}
|
||||
|
||||
function filterErr(code, done) {
|
||||
return function(e) {
|
||||
done(e.code !== code ? e : void(0));
|
||||
@@ -69,6 +81,13 @@ function hexToArray(h) {
|
||||
return stringToArray(hexToString(h));
|
||||
};
|
||||
|
||||
function arrayToHex(a) {
|
||||
return a.map(function(byteValue) {
|
||||
var hex = byteValue.toString(16);
|
||||
return hex.length > 1 ? hex : '0' + hex;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function chunkString(str, n, leftAlign) {
|
||||
var ret = [];
|
||||
var i=0, len=str.length;
|
||||
@@ -144,15 +163,16 @@ exports.hexToString = hexToString;
|
||||
exports.hexToArray = hexToArray;
|
||||
exports.stringToArray = stringToArray;
|
||||
exports.stringToHex = stringToHex;
|
||||
exports.arrayToHex = arrayToHex;
|
||||
exports.chunkString = chunkString;
|
||||
exports.assert = assert;
|
||||
exports.arrayUnique = arrayUnique;
|
||||
exports.toTimestamp = toTimestamp;
|
||||
exports.fromTimestamp = fromTimestamp;
|
||||
exports.getMantissaDecimalString = getMantissaDecimalString;
|
||||
|
||||
// Going up three levels is needed to escape the src-cov folder used for the
|
||||
// test coverage stuff.
|
||||
exports.sjcl = require('../../../build/sjcl');
|
||||
exports.jsbn = require('../../../src/js/jsbn/jsbn');
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -1,593 +0,0 @@
|
||||
var async = require('async');
|
||||
var blobClient = require('./blob').BlobClient;
|
||||
var AuthInfo = require('./authinfo').AuthInfo;
|
||||
var crypt = require('./crypt').Crypt;
|
||||
var log = require('./log').sub('vault');
|
||||
function VaultClient(opts) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (!opts) {
|
||||
opts = { };
|
||||
}
|
||||
|
||||
if (typeof opts === 'string') {
|
||||
opts = { domain: opts };
|
||||
}
|
||||
|
||||
this.domain = opts.domain || 'ripple.com';
|
||||
this.infos = { };
|
||||
};
|
||||
|
||||
/**
|
||||
* getAuthInfo
|
||||
* gets auth info for a username. returns authinfo
|
||||
* even if user does not exists (with exist set to false)
|
||||
* @param {string} username
|
||||
* @param {function} callback
|
||||
*/
|
||||
VaultClient.prototype.getAuthInfo = function (username, callback) {
|
||||
|
||||
AuthInfo.get(this.domain, username, function(err, authInfo) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (authInfo.version !== 3) {
|
||||
return callback(new Error('This wallet is incompatible with this version of the vault-client.'));
|
||||
}
|
||||
|
||||
if (!authInfo.pakdf) {
|
||||
return callback(new Error('No settings for PAKDF in auth packet.'));
|
||||
}
|
||||
|
||||
if (typeof authInfo.blobvault !== 'string') {
|
||||
return callback(new Error('No blobvault specified in the authinfo.'));
|
||||
}
|
||||
|
||||
callback(null, authInfo);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* _deriveLoginKeys
|
||||
* method designed for asnyc waterfall
|
||||
*/
|
||||
|
||||
VaultClient.prototype._deriveLoginKeys = function (authInfo, password, callback) {
|
||||
var normalizedUsername = authInfo.username.toLowerCase().replace(/-/g, '');
|
||||
|
||||
//derive login keys
|
||||
crypt.derive(authInfo.pakdf, 'login', normalizedUsername, password, function(err, keys) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, authInfo, password, keys);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* _deriveUnlockKey
|
||||
* method designed for asnyc waterfall
|
||||
*/
|
||||
|
||||
VaultClient.prototype._deriveUnlockKey = function (authInfo, password, keys, callback) {
|
||||
var normalizedUsername = authInfo.username.toLowerCase().replace(/-/g, '');
|
||||
|
||||
//derive unlock key
|
||||
crypt.derive(authInfo.pakdf, 'unlock', normalizedUsername, password, function(err, unlock) {
|
||||
if (err) {
|
||||
log.error('derive:', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!keys) {
|
||||
keys = { };
|
||||
}
|
||||
|
||||
keys.unlock = unlock.unlock;
|
||||
callback(null, authInfo, keys);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a ripple name from a given account address, if it has one
|
||||
* @param {string} address - Account address to query
|
||||
* @param {string} url - Url of blob vault
|
||||
*/
|
||||
|
||||
VaultClient.prototype.getRippleName = function(address, url, callback) {
|
||||
//use the url from previously retrieved authInfo, if necessary
|
||||
if (!url) {
|
||||
callback(new Error('Blob vault URL is required'));
|
||||
} else {
|
||||
blobClient.getRippleName(url, address, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check blobvault for existance of username
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.exists = function(username, callback) {
|
||||
AuthInfo.get(this.domain, username.toLowerCase(), function(err, authInfo) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, !!authInfo.exists);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Authenticate and retrieve a decrypted blob using a ripple name and password
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.login = function(username, password, device_id, callback) {
|
||||
var self = this;
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
getBlob
|
||||
];
|
||||
|
||||
async.waterfall(steps, callback);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(username, function(err, authInfo){
|
||||
|
||||
if (authInfo && !authInfo.exists) {
|
||||
return callback(new Error('User does not exist.'));
|
||||
}
|
||||
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
}
|
||||
|
||||
function getBlob(authInfo, password, keys, callback) {
|
||||
var options = {
|
||||
url : authInfo.blobvault,
|
||||
blob_id : keys.id,
|
||||
key : keys.crypt,
|
||||
device_id : device_id
|
||||
};
|
||||
|
||||
blobClient.get(options, function(err, blob) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
//save for relogin
|
||||
self.infos[keys.id] = authInfo;
|
||||
|
||||
//migrate missing fields
|
||||
if (blob.missing_fields) {
|
||||
if (blob.missing_fields.encrypted_blobdecrypt_key) {
|
||||
log.info('migration: saving encrypted blob decrypt key');
|
||||
authInfo.blob = blob;
|
||||
//get the key to unlock the secret, then update the blob keys
|
||||
self._deriveUnlockKey(authInfo, password, keys, updateKeys);
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
blob : blob,
|
||||
username : authInfo.username,
|
||||
verified : authInfo.emailVerified
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function updateKeys (err, params, keys) {
|
||||
if (err || !keys.unlock) {
|
||||
return; //unable to unlock
|
||||
}
|
||||
|
||||
var secret;
|
||||
try {
|
||||
secret = crypt.decrypt(keys.unlock, params.blob.encrypted_secret);
|
||||
} catch (error) {
|
||||
return log.error('decrypt:', error);
|
||||
}
|
||||
|
||||
options = {
|
||||
username : params.username,
|
||||
blob : params.blob,
|
||||
masterkey : secret,
|
||||
keys : keys
|
||||
};
|
||||
|
||||
blobClient.updateKeys(options, function(err, resp){
|
||||
if (err) {
|
||||
log.error('updateKeys:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retreive and decrypt blob using a blob url, id and crypt derived previously.
|
||||
*
|
||||
* @param {string} url - Blob vault url
|
||||
* @param {string} id - Blob id from previously retreived blob
|
||||
* @param {string} key - Blob decryption key
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.relogin = function(url, id, key, device_id, callback) {
|
||||
//use the url from previously retrieved authInfo, if necessary
|
||||
if (!url && this.infos[id]) {
|
||||
url = this.infos[id].blobvault;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return callback(new Error('Blob vault URL is required'));
|
||||
}
|
||||
|
||||
var options = {
|
||||
url : url,
|
||||
blob_id : id,
|
||||
key : key,
|
||||
device_id : device_id
|
||||
};
|
||||
|
||||
blobClient.get(options, function(err, blob) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback (null, { blob: blob });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypt the secret key using a username and password
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @param {string} encryptSecret
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.unlock = function(username, password, encryptSecret, fn) {
|
||||
var self = this;
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveUnlockKey,
|
||||
unlockSecret
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(username, function(err, authInfo){
|
||||
|
||||
if (authInfo && !authInfo.exists) {
|
||||
return callback(new Error('User does not exist.'));
|
||||
}
|
||||
|
||||
return callback (err, authInfo, password, {});
|
||||
});
|
||||
}
|
||||
|
||||
function unlockSecret (authinfo, keys, callback) {
|
||||
|
||||
var secret;
|
||||
try {
|
||||
secret = crypt.decrypt(keys.unlock, encryptSecret);
|
||||
} catch (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
keys : keys,
|
||||
secret : secret
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the decrypted blob and secret key in one step using
|
||||
* the username and password
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.loginAndUnlock = function(username, password, device_id, fn) {
|
||||
var self = this;
|
||||
|
||||
var steps = [
|
||||
login,
|
||||
deriveUnlockKey,
|
||||
unlockSecret
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function login (callback) {
|
||||
self.login(username, password, device_id, function(err, resp) {
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!resp.blob || !resp.blob.encrypted_secret) {
|
||||
return callback(new Error('Unable to retrieve blob and secret.'));
|
||||
}
|
||||
|
||||
if (!resp.blob.id || !resp.blob.key) {
|
||||
return callback(new Error('Unable to retrieve keys.'));
|
||||
}
|
||||
|
||||
//get authInfo via id - would have been saved from login
|
||||
var authInfo = self.infos[resp.blob.id];
|
||||
|
||||
if (!authInfo) {
|
||||
return callback(new Error('Unable to find authInfo'));
|
||||
}
|
||||
|
||||
callback(null, authInfo, password, resp.blob);
|
||||
});
|
||||
};
|
||||
|
||||
function deriveUnlockKey (authInfo, password, blob, callback) {
|
||||
self._deriveUnlockKey(authInfo, password, null, function(err, authInfo, keys){
|
||||
callback(err, keys.unlock, authInfo, blob);
|
||||
});
|
||||
};
|
||||
|
||||
function unlockSecret (unlock, authInfo, blob, callback) {
|
||||
var secret;
|
||||
try {
|
||||
secret = crypt.decrypt(unlock, blob.encrypted_secret);
|
||||
} catch (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
blob : blob,
|
||||
unlock : unlock,
|
||||
secret : secret,
|
||||
username : authInfo.username,
|
||||
verified : authInfo.emailVerified
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify an email address for an existing user
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} token - Verification token
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.verify = function(username, token, callback) {
|
||||
var self = this;
|
||||
|
||||
self.getAuthInfo(username, function (err, authInfo){
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
blobClient.verify(authInfo.blobvault, username.toLowerCase(), token, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* changePassword
|
||||
* @param {object} options
|
||||
* @param {string} options.username
|
||||
* @param {string} options.password
|
||||
* @param {string} options.masterkey
|
||||
* @param {object} options.blob
|
||||
*/
|
||||
|
||||
VaultClient.prototype.changePassword = function (options, fn) {
|
||||
var self = this;
|
||||
var password = String(options.password).trim();
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
self._deriveUnlockKey,
|
||||
changePassword
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(options.username, function(err, authInfo) {
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
};
|
||||
|
||||
function changePassword (authInfo, keys, callback) {
|
||||
options.keys = keys;
|
||||
blobClient.updateKeys(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* rename
|
||||
* rename a ripple account
|
||||
* @param {object} options
|
||||
* @param {string} options.username
|
||||
* @param {string} options.new_username
|
||||
* @param {string} options.password
|
||||
* @param {string} options.masterkey
|
||||
* @param {object} options.blob
|
||||
* @param {function} fn
|
||||
*/
|
||||
|
||||
VaultClient.prototype.rename = function (options, fn) {
|
||||
var self = this;
|
||||
var new_username = String(options.new_username).trim();
|
||||
var password = String(options.password).trim();
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
self._deriveUnlockKey,
|
||||
renameBlob
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(new_username, function(err, authInfo){
|
||||
|
||||
if (authInfo && authInfo.exists) {
|
||||
return callback(new Error('username already taken.'));
|
||||
} else {
|
||||
authInfo.username = new_username;
|
||||
}
|
||||
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
};
|
||||
|
||||
function renameBlob (authInfo, keys, callback) {
|
||||
options.keys = keys;
|
||||
blobClient.rename(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a new user and save to the blob vault
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {string} options.username
|
||||
* @param {string} options.password
|
||||
* @param {string} options.masterkey //optional, will create if absent
|
||||
* @param {string} options.email
|
||||
* @param {string} options.activateLink
|
||||
* @param {object} options.oldUserBlob //optional
|
||||
* @param {function} fn
|
||||
*/
|
||||
|
||||
VaultClient.prototype.register = function(options, fn) {
|
||||
var self = this;
|
||||
var username = String(options.username).trim();
|
||||
var password = String(options.password).trim();
|
||||
var result = self.validateUsername(username);
|
||||
|
||||
if (!result.valid) {
|
||||
return fn(new Error('invalid username.'));
|
||||
}
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
self._deriveUnlockKey,
|
||||
create
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(username, function(err, authInfo){
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
};
|
||||
|
||||
function create(authInfo, keys, callback) {
|
||||
var params = {
|
||||
url : authInfo.blobvault,
|
||||
id : keys.id,
|
||||
crypt : keys.crypt,
|
||||
unlock : keys.unlock,
|
||||
username : username,
|
||||
email : options.email,
|
||||
masterkey : options.masterkey || crypt.createMaster(),
|
||||
activateLink : options.activateLink,
|
||||
oldUserBlob : options.oldUserBlob,
|
||||
domain : options.domain
|
||||
};
|
||||
|
||||
blobClient.create(params, function(err, blob) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, {
|
||||
blob : blob,
|
||||
username : username
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* validateUsername
|
||||
* check username for validity
|
||||
*/
|
||||
|
||||
VaultClient.prototype.validateUsername = function (username) {
|
||||
username = String(username).trim();
|
||||
var result = {
|
||||
valid : false,
|
||||
reason : ''
|
||||
};
|
||||
|
||||
if (username.length < 2) {
|
||||
result.reason = 'tooshort';
|
||||
} else if (username.length > 20) {
|
||||
result.reason = 'toolong';
|
||||
} else if (!/^[a-zA-Z0-9\-]+$/.exec(username)) {
|
||||
result.reason = 'charset';
|
||||
} else if (/^-/.exec(username)) {
|
||||
result.reason = 'starthyphen';
|
||||
} else if (/-$/.exec(username)) {
|
||||
result.reason = 'endhyphen';
|
||||
} else if (/--/.exec(username)) {
|
||||
result.reason = 'multhyphen';
|
||||
} else {
|
||||
result.valid = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* generateDeviceID
|
||||
* create a new random device ID for 2FA
|
||||
*/
|
||||
VaultClient.prototype.generateDeviceID = function () {
|
||||
return crypt.createSecret(4);
|
||||
};
|
||||
|
||||
/*** pass thru some blob client function ***/
|
||||
|
||||
VaultClient.prototype.resendEmail = blobClient.resendEmail;
|
||||
|
||||
VaultClient.prototype.recoverBlob = blobClient.recoverBlob;
|
||||
|
||||
VaultClient.prototype.deleteBlob = blobClient.deleteBlob;
|
||||
|
||||
VaultClient.prototype.requestToken = blobClient.requestToken;
|
||||
|
||||
VaultClient.prototype.verifyToken = blobClient.verifyToken;
|
||||
|
||||
VaultClient.prototype.getAttestation = blobClient.getAttestation;
|
||||
|
||||
VaultClient.prototype.updateAttestation = blobClient.updateAttestation;
|
||||
|
||||
VaultClient.prototype.getAttestationSummary = blobClient.getAttestationSummary;
|
||||
|
||||
//export by name
|
||||
exports.VaultClient = VaultClient;
|
||||
@@ -65,7 +65,7 @@ sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function(hash,
|
||||
*
|
||||
* @param {bitArray} hash
|
||||
* @param {bitArray} signature
|
||||
* @param {sjcl.ecc.curve} [sjcl.ecc.curves['c256']] curve
|
||||
* @param {sjcl.ecc.curve} [sjcl.ecc.curves['k256']] curve
|
||||
* @returns {sjcl.ecc.ecdsa.publicKey} Public key
|
||||
*/
|
||||
sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function(hash, signature, curve) {
|
||||
@@ -75,7 +75,7 @@ sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function(hash, signature, curve)
|
||||
}
|
||||
|
||||
if (!curve) {
|
||||
curve = sjcl.ecc.curves['c256'];
|
||||
curve = sjcl.ecc.curves['k256'];
|
||||
}
|
||||
|
||||
// Convert hash to bits and determine encoding for output
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
// ----- for secp256k1 ------
|
||||
|
||||
// Overwrite NIST-P256 with secp256k1
|
||||
sjcl.ecc.curves.c256 = new sjcl.ecc.curve(
|
||||
sjcl.bn.pseudoMersennePrime(256, [[0,-1],[4,-1],[6,-1],[7,-1],[8,-1],[9,-1],[32,-1]]),
|
||||
"0x14551231950b75fc4402da1722fc9baee",
|
||||
0,
|
||||
7,
|
||||
"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
|
||||
);
|
||||
sjcl.ecc.point.prototype.toBytesCompressed = function () {
|
||||
var header = this.y.mod(2).toString() == "0x0" ? 0x02 : 0x03;
|
||||
return [header].concat(sjcl.codec.bytes.fromBits(this.x.toBits()))
|
||||
};
|
||||
|
||||
// Replace point addition and doubling algorithms
|
||||
// NIST-P256 is a=-3, we need algorithms for a=0
|
||||
//
|
||||
// This is a custom point addition formula that
|
||||
// only works for a=-3 Jacobian curve. It's much
|
||||
// faster than the generic implementation
|
||||
sjcl.ecc.pointJac.prototype.add = function(T) {
|
||||
var S = this;
|
||||
if (S.curve !== T.curve) {
|
||||
@@ -43,7 +42,7 @@ sjcl.ecc.pointJac.prototype.add = function(T) {
|
||||
var j = h.mul(i);
|
||||
var r = s2.sub(S.y).doubleM();
|
||||
var v = S.x.mul(i);
|
||||
|
||||
|
||||
var x = r.square().subM(j).subM(v.copy().doubleM());
|
||||
var y = r.mul(v.sub(x)).subM(S.y.mul(j).doubleM());
|
||||
var z = S.z.add(h).square().subM(z1z1).subM(hh);
|
||||
@@ -51,6 +50,9 @@ sjcl.ecc.pointJac.prototype.add = function(T) {
|
||||
return new sjcl.ecc.pointJac(this.curve,x,y,z);
|
||||
};
|
||||
|
||||
// This is a custom doubling algorithm that
|
||||
// only works for a=-3 Jacobian curve. It's much
|
||||
// faster than the generic implementation
|
||||
sjcl.ecc.pointJac.prototype.doubl = function () {
|
||||
if (this.isIdentity) { return this; }
|
||||
|
||||
@@ -66,7 +68,9 @@ sjcl.ecc.pointJac.prototype.doubl = function () {
|
||||
return new sjcl.ecc.pointJac(this.curve, x, y, z);
|
||||
};
|
||||
|
||||
sjcl.ecc.point.prototype.toBytesCompressed = function () {
|
||||
var header = this.y.mod(2).toString() == "0x0" ? 0x02 : 0x03;
|
||||
return [header].concat(sjcl.codec.bytes.fromBits(this.x.toBits()))
|
||||
};
|
||||
// DEPRECATED:
|
||||
// previously the c256 curve was overridden with the secp256k1 curve
|
||||
// since then, sjcl has been updated to support k256
|
||||
// this override exist to keep supporting the old c256 with k256 behavior
|
||||
// this will be removed in future release
|
||||
sjcl.ecc.curves.c256 = sjcl.ecc.curves.k256;
|
||||
2
src/js/sjcl/.gitignore
vendored
Normal file
2
src/js/sjcl/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
core.js
|
||||
core_closure.js
|
||||
9
src/js/sjcl/.travis.yml
Normal file
9
src/js/sjcl/.travis.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
before_script: ./configure --with-all
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
# 0.6 appears to be unreliable on Travis at the moment.
|
||||
# - "0.6"
|
||||
@@ -54,10 +54,11 @@ lint: core.js core/*.js test/*.js browserTest/*.js lint/coding_guidelines.pl
|
||||
lint/coding_guidelines.pl core/*.js test/*.js browserTest/*.js
|
||||
|
||||
|
||||
TEST_COMMON= browserTest/rhinoUtil.js test/test.js
|
||||
TEST_COMMON= browserTest/nodeUtil.js test/test.js
|
||||
|
||||
TEST_SCRIPTS= $(TEST_COMMON) \
|
||||
test/aes_vectors.js test/aes_test.js \
|
||||
test/bitArray_vectors.js test/bitArray_test.js \
|
||||
test/ocb2_vectors.js test/ocb2_test.js \
|
||||
test/ccm_vectors.js test/ccm_test.js \
|
||||
test/cbc_vectors.js test/cbc_test.js \
|
||||
@@ -70,18 +71,14 @@ TEST_SCRIPTS= $(TEST_COMMON) \
|
||||
test/hmac_vectors.js test/hmac_test.js \
|
||||
test/pbkdf2_test.js \
|
||||
test/bn_vectors.js test/bn_test.js \
|
||||
test/ecdsa_test.js test/ecdsa_vectors.js test/ecdh_test.js
|
||||
test/ecdsa_test.js test/ecdsa_vectors.js test/ecdh_test.js \
|
||||
test/srp_vectors.js test/srp_test.js \
|
||||
test/json_test.js
|
||||
|
||||
TEST_SCRIPTS_OPT= $(TEST_COMMON) \
|
||||
test/srp_vectors.js test/srp_test.js
|
||||
# Run all tests in node.js.
|
||||
|
||||
# Rhino fails at -O 0. Probably because the big files full of test vectors blow the
|
||||
# bytecode limit. So, run most tests with -O -1. But modular exponentiation is
|
||||
# currently very slow (on Rhino), so run the SRP test with optimizations on.
|
||||
|
||||
test: sjcl.js $(TEST_SCRIPTS) test/run_tests_rhino.js
|
||||
@rhino -O -1 -w test/run_tests_rhino.js $< $(TEST_SCRIPTS)
|
||||
@rhino -O 9 -w test/run_tests_rhino.js $< $(TEST_SCRIPTS_OPT)
|
||||
test: sjcl.js $(TEST_SCRIPTS) test/run_tests_node.js
|
||||
node test/run_tests_node.js $< $(TEST_SCRIPTS)
|
||||
|
||||
tidy:
|
||||
find . -name '*~' -delete
|
||||
|
||||
21
src/js/sjcl/README.md
Normal file
21
src/js/sjcl/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
sjcl
|
||||
====
|
||||
|
||||
[](https://travis-ci.org/bitwiseshiftleft/sjcl)
|
||||
|
||||
Stanford Javascript Crypto Library
|
||||
|
||||
Security Advisories
|
||||
===
|
||||
* 12.02.2014: the current development version has a paranoia bug in the ecc module. The bug was introduced in commit [ac0b3fe0](https://github.com/bitwiseshiftleft/sjcl/commit/ac0b3fe0) and might affect ecc key generation on platforms without a platform random number generator.
|
||||
*
|
||||
|
||||
Security Contact
|
||||
====
|
||||
Security Mail: sjcl@ovt.me
|
||||
OpenPGP-Key Fingerprint: 0D54 3E52 87B4 EC06 3FA9 0115 72ED A6C7 7AAF 48ED
|
||||
Keyserver: pool.sks-keyservers.net
|
||||
|
||||
Documentation
|
||||
====
|
||||
The documentation is available [here](http://bitwiseshiftleft.github.io/sjcl/doc/)
|
||||
12
src/js/sjcl/bower.json
Normal file
12
src/js/sjcl/bower.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "sjcl",
|
||||
"version": "1.0.0",
|
||||
"main": ["./sjcl.js"],
|
||||
"ignore": [
|
||||
"**/*",
|
||||
"!README.md",
|
||||
"!README/*",
|
||||
"!bower.json",
|
||||
"!sjcl.js"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
browserUtil = {};
|
||||
|
||||
browserUtil.isRhino = (typeof(window) === 'undefined');
|
||||
browserUtil.isNodeJS = (typeof(window) === 'undefined');
|
||||
|
||||
/**
|
||||
* Pause (for the graphics to update and the script timer to clear), then run the
|
||||
|
||||
88
src/js/sjcl/browserTest/entropy.html
Normal file
88
src/js/sjcl/browserTest/entropy.html
Normal file
@@ -0,0 +1,88 @@
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Entropy Generator Progress</title>
|
||||
<!-- ProgressBar source: http://stackoverflow.com/questions/7190898/progress-bar-with-html-and-css -->
|
||||
|
||||
<style>
|
||||
#progressbar {
|
||||
background-color: black;
|
||||
border-radius: 13px; /* (height of inner div) / 2 + padding */
|
||||
padding: 3px;
|
||||
}
|
||||
#progressbar > div {
|
||||
background-color: orange;
|
||||
width: 0%; /* Adjust with JavaScript */
|
||||
height: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="../sjcl.js">
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var busy = 0;
|
||||
var collecting = 0;
|
||||
|
||||
function showprogress () {
|
||||
var barwidth = document.getElementById ("progresswidth");
|
||||
var paranoia = parseInt (document.getElementById ("paranoialevel").value);
|
||||
var progress = 100 * sjcl.random.getProgress (paranoia);
|
||||
barwidth.style.width = progress+"%";
|
||||
if (!sjcl.random.isReady (paranoia)) {
|
||||
setTimeout ("showprogress()", 10, "JavaScript");
|
||||
} else {
|
||||
busy = 0;
|
||||
document.getElementById ("startbutton").style.disabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function startup () {
|
||||
if (collecting == 0) {
|
||||
sjcl.random.startCollectors ();
|
||||
collecting = 1;
|
||||
}
|
||||
if (busy == 0) {
|
||||
busy = 1;
|
||||
document.getElementById ("startbutton").style.disabled = 1;
|
||||
showprogress ();
|
||||
}
|
||||
}
|
||||
|
||||
function consume (numbits) {
|
||||
var collector = document.getElementById ("collector");
|
||||
collector.value = "retrieving random data";
|
||||
var paranoia = document.getElementById ("paranoialevel").value;
|
||||
var numwords = Math.ceil (numbits / 32);
|
||||
var bits = sjcl.random.randomWords (numwords, paranoia);
|
||||
collector.value = '';
|
||||
for (var i=0; i<numwords; i++) {
|
||||
var hi = (bits [i] >> 16) & 0x0000ffff;
|
||||
var lo = bits [i] & 0x0000ffff;
|
||||
collector.value = collector.value + hi.toString (16) + lo.toString (16);
|
||||
}
|
||||
startup ();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>Entropy Generator Progress</h1>
|
||||
|
||||
<p>Target: 192 bits, available at paranoia level 5.</p>
|
||||
|
||||
<p>Corresponding paranoia level from [0,1..10]: <input type="text" value="5" id="paranoialevel"/> <input type=button onclick="startup ()" id="startbutton" value=" Start >> "> (the idea being that you can see the progress bar advance gently from empty/black to full/yellow after you press this)</p>
|
||||
|
||||
<p><input type=button onclick="consume (192)" value=" Consume 192 bits >> "><input type=text id=collector size=50 value="" onkeypress="consume (192)"> (also consumes 192 bits with every keypress in the text field; use key repeat to consume swiftly)</p>
|
||||
|
||||
<div id="progressbar">
|
||||
<div id="progresswidth"></div>
|
||||
</div>
|
||||
|
||||
<p>Please move your mouse, play around and generally introduce entropy into your environment.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
44
src/js/sjcl/browserTest/nodeUtil.js
Normal file
44
src/js/sjcl/browserTest/nodeUtil.js
Normal file
@@ -0,0 +1,44 @@
|
||||
browserUtil = {
|
||||
isNodeJS: true,
|
||||
|
||||
pauseAndThen: function (cb) { cb(); },
|
||||
|
||||
cpsIterate: function (f, start, end, pause, callback) {
|
||||
function go() {
|
||||
var called = false;
|
||||
if (start >= end) {
|
||||
callback && callback();
|
||||
} else {
|
||||
f(start, function () {
|
||||
if (!called) { called = true; start++; go(); }
|
||||
});
|
||||
}
|
||||
}
|
||||
go (start);
|
||||
},
|
||||
|
||||
cpsMap: function (map, list, pause, callback) {
|
||||
browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
|
||||
0, list.length, pause, callback);
|
||||
},
|
||||
|
||||
loadScripts: function(scriptNames, callback) {
|
||||
for (i=0; i<scriptNames.length; i++) {
|
||||
load(scriptNames[i]);
|
||||
callback && callback();
|
||||
}
|
||||
},
|
||||
|
||||
write: function(type, message) {
|
||||
console.log(message);
|
||||
return { update: function (type2, message2) {
|
||||
if (type2 === 'pass') { console.log(" + " + message2); }
|
||||
else if (type2 === 'unimplemented') { console.log(" ? " + message2); }
|
||||
else { console.log(" - " + message2); }
|
||||
}};
|
||||
},
|
||||
|
||||
writeNewline: function () { console.log(""); },
|
||||
|
||||
status: function(message) {}
|
||||
};
|
||||
@@ -16,7 +16,7 @@ sub digitize {
|
||||
}
|
||||
|
||||
while (<>) {
|
||||
s/([^a-zA-Z0-9_])(\d+)/$1 . digitize $2/eg;
|
||||
s/([^a-zA-Z0-9_"])(\d+)/$1 . digitize $2/eg;
|
||||
print;
|
||||
}
|
||||
|
||||
|
||||
11
src/js/sjcl/configure
vendored
11
src/js/sjcl/configure
vendored
@@ -4,12 +4,13 @@ use strict;
|
||||
|
||||
my ($arg, $i, $j, $targ);
|
||||
|
||||
my @targets = qw/sjcl aes bitArray codecString codecHex codecBase64 codecBytes sha256 sha512 sha1 ccm cbc ocb2 gcm hmac pbkdf2 random convenience bn ecc srp/;
|
||||
my @targets = qw/sjcl aes bitArray codecString codecHex codecBase32 codecBase64 codecBytes sha256 sha512 sha1 ccm cbc ocb2 gcm hmac pbkdf2 random convenience bn ecc srp/;
|
||||
my %deps = ('aes'=>'sjcl',
|
||||
'bitArray'=>'sjcl',
|
||||
'codecString'=>'bitArray',
|
||||
'codecHex'=>'bitArray',
|
||||
'codecBase64'=>'bitArray',
|
||||
'codecBase32'=>'bitArray',
|
||||
'codecBytes'=>'bitArray',
|
||||
'sha256'=>'codecString',
|
||||
'sha512'=>'codecString',
|
||||
@@ -32,10 +33,10 @@ my %enabled = ();
|
||||
$enabled{$_} = 0 foreach (@targets);
|
||||
|
||||
# by default, all but codecBytes, srp, bn
|
||||
$enabled{$_} = 1 foreach (qw/aes bitArray codecString codecHex codecBase64 sha256 ccm ocb2 gcm hmac pbkdf2 random convenience/);
|
||||
$enabled{$_} = 1 foreach (qw/aes bitArray codecString codecHex codecBase32 codecBase64 sha256 ccm ocb2 gcm hmac pbkdf2 random convenience/);
|
||||
|
||||
# argument parsing
|
||||
while ($arg = shift @ARGV) {
|
||||
while (my $arg = shift @ARGV) {
|
||||
if ($arg =~ /^--?with-all$/) {
|
||||
foreach (@targets) {
|
||||
if ($enabled{$_} == 0) {
|
||||
@@ -97,7 +98,7 @@ my $config = '';
|
||||
my $pconfig;
|
||||
|
||||
# dependency analysis: forbidden
|
||||
foreach $i (@targets) {
|
||||
foreach my $i (@targets) {
|
||||
if ($enabled{$i} > 0) {
|
||||
foreach $j (split /,/, $deps{$i}) {
|
||||
if ($enabled{$j} == -1) {
|
||||
@@ -114,7 +115,7 @@ foreach $i (@targets) {
|
||||
}
|
||||
|
||||
# reverse
|
||||
foreach $i (reverse @targets) {
|
||||
foreach my $i (reverse @targets) {
|
||||
if ($enabled{$i} > 0) {
|
||||
foreach $j (split /,/, $deps{$i}) {
|
||||
if ($enabled{$j} < $enabled{$i}) {
|
||||
|
||||
@@ -74,7 +74,7 @@ sjcl.bitArray = {
|
||||
return a1.concat(a2);
|
||||
}
|
||||
|
||||
var out, i, last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last);
|
||||
var last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last);
|
||||
if (shift === 32) {
|
||||
return a1.concat(a2);
|
||||
} else {
|
||||
@@ -183,5 +183,19 @@ sjcl.bitArray = {
|
||||
*/
|
||||
_xor4: function(x,y) {
|
||||
return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]];
|
||||
},
|
||||
|
||||
/** byteswap a word array inplace.
|
||||
* (does not handle partial words)
|
||||
* @param {sjcl.bitArray} a word array
|
||||
* @return {sjcl.bitArray} byteswapped array
|
||||
*/
|
||||
byteswapM: function(a) {
|
||||
var i, v, m = 0xff00;
|
||||
for (i = 0; i < a.length; ++i) {
|
||||
v = a[i];
|
||||
a[i] = (v >>> 24) | ((v >>> 8) & m) | ((v & m) << 8) | (v << 24);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ sjcl.bn.prototype = {
|
||||
* Initializes this with it, either as a bn, a number, or a hex string.
|
||||
*/
|
||||
initWith: function(it) {
|
||||
var i=0, k, n, l;
|
||||
var i=0, k;
|
||||
switch(typeof it) {
|
||||
case "object":
|
||||
this.limbs = it.limbs.slice(0);
|
||||
@@ -328,7 +328,7 @@ sjcl.bn.prototype = {
|
||||
carry = (l-m)*ipv;
|
||||
}
|
||||
if (carry === -1) {
|
||||
limbs[i-1] -= this.placeVal;
|
||||
limbs[i-1] -= pv;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
@@ -370,7 +370,9 @@ sjcl.bn.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/** @this { sjcl.bn } */
|
||||
/** @memberOf sjcl.bn
|
||||
* @this { sjcl.bn }
|
||||
*/
|
||||
sjcl.bn.fromBits = function(bits) {
|
||||
var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype,
|
||||
l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix;
|
||||
@@ -394,7 +396,9 @@ sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1;
|
||||
* i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse.
|
||||
*/
|
||||
sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
/** @constructor */
|
||||
/** @constructor
|
||||
* @private
|
||||
*/
|
||||
function p(it) {
|
||||
this.initWith(it);
|
||||
/*if (this.limbs[this.modOffset]) {
|
||||
@@ -427,10 +431,11 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
ppr.modulus.cnormalize();
|
||||
|
||||
/** Approximate reduction mod p. May leave a number which is negative or slightly larger than p.
|
||||
* @this {sjcl.bn}
|
||||
* @memberof sjcl.bn
|
||||
* @this { sjcl.bn }
|
||||
*/
|
||||
ppr.reduce = function() {
|
||||
var i, k, l, mo = this.modOffset, limbs = this.limbs, aff, off = this.offset, ol = this.offset.length, fac = this.factor, ll;
|
||||
var i, k, l, mo = this.modOffset, limbs = this.limbs, off = this.offset, ol = this.offset.length, fac = this.factor, ll;
|
||||
|
||||
i = this.minOffset;
|
||||
while (limbs.length > mo) {
|
||||
@@ -452,7 +457,9 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @this {sjcl.bn} */
|
||||
/** @memberof sjcl.bn
|
||||
* @this { sjcl.bn }
|
||||
*/
|
||||
ppr._strongReduce = (ppr.fullMask === -1) ? ppr.reduce : function() {
|
||||
var limbs = this.limbs, i = limbs.length - 1, k, l;
|
||||
this.reduce();
|
||||
@@ -467,7 +474,8 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
};
|
||||
|
||||
/** mostly constant-time, very expensive full reduction.
|
||||
* @this {sjcl.bn}
|
||||
* @memberof sjcl.bn
|
||||
* @this { sjcl.bn }
|
||||
*/
|
||||
ppr.fullReduce = function() {
|
||||
var greater, i;
|
||||
@@ -501,7 +509,9 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
};
|
||||
|
||||
|
||||
/** @this {sjcl.bn} */
|
||||
/** @memberof sjcl.bn
|
||||
* @this { sjcl.bn }
|
||||
*/
|
||||
ppr.inverse = function() {
|
||||
return (this.power(this.modulus.sub(2)));
|
||||
};
|
||||
@@ -512,18 +522,24 @@ sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
|
||||
};
|
||||
|
||||
// a small Mersenne prime
|
||||
var sbp = sjcl.bn.pseudoMersennePrime;
|
||||
sjcl.bn.prime = {
|
||||
p127: sjcl.bn.pseudoMersennePrime(127, [[0,-1]]),
|
||||
p127: sbp(127, [[0,-1]]),
|
||||
|
||||
// Bernstein's prime for Curve25519
|
||||
p25519: sjcl.bn.pseudoMersennePrime(255, [[0,-19]]),
|
||||
p25519: sbp(255, [[0,-19]]),
|
||||
|
||||
// Koblitz primes
|
||||
p192k: sbp(192, [[32,-1],[12,-1],[8,-1],[7,-1],[6,-1],[3,-1],[0,-1]]),
|
||||
p224k: sbp(224, [[32,-1],[12,-1],[11,-1],[9,-1],[7,-1],[4,-1],[1,-1],[0,-1]]),
|
||||
p256k: sbp(256, [[32,-1],[9,-1],[8,-1],[7,-1],[6,-1],[4,-1],[0,-1]]),
|
||||
|
||||
// NIST primes
|
||||
p192: sjcl.bn.pseudoMersennePrime(192, [[0,-1],[64,-1]]),
|
||||
p224: sjcl.bn.pseudoMersennePrime(224, [[0,1],[96,-1]]),
|
||||
p256: sjcl.bn.pseudoMersennePrime(256, [[0,-1],[96,1],[192,1],[224,-1]]),
|
||||
p384: sjcl.bn.pseudoMersennePrime(384, [[0,-1],[32,1],[96,-1],[128,-1]]),
|
||||
p521: sjcl.bn.pseudoMersennePrime(521, [[0,-1]])
|
||||
p192: sbp(192, [[0,-1],[64,-1]]),
|
||||
p224: sbp(224, [[0,1],[96,-1]]),
|
||||
p256: sbp(256, [[0,-1],[96,1],[192,1],[224,-1]]),
|
||||
p384: sbp(384, [[0,-1],[32,1],[96,-1],[128,-1]]),
|
||||
p521: sbp(521, [[0,-1]])
|
||||
};
|
||||
|
||||
sjcl.bn.random = function(modulus, paranoia) {
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace
|
||||
* Dangerous: CBC mode with PKCS#5 padding.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
if (sjcl.beware === undefined) {
|
||||
sjcl.beware = {};
|
||||
}
|
||||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."
|
||||
] = function() {
|
||||
/** @namespace
|
||||
* Dangerous: CBC mode with PKCS#5 padding.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
sjcl.mode.cbc = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
@@ -100,7 +100,7 @@ sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity.
|
||||
|
||||
/* check and remove the pad */
|
||||
bi = output[i-1] & 255;
|
||||
if (bi == 0 || bi > 16) {
|
||||
if (bi === 0 || bi > 16) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
bo = bi * 0x1010101;
|
||||
|
||||
@@ -25,7 +25,7 @@ sjcl.mode.ccm = {
|
||||
* @return {bitArray} The encrypted data, an array of bytes.
|
||||
*/
|
||||
encrypt: function(prf, plaintext, iv, adata, tlen) {
|
||||
var L, i, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8;
|
||||
var L, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8;
|
||||
tlen = tlen || 64;
|
||||
adata = adata || [];
|
||||
|
||||
@@ -59,7 +59,7 @@ sjcl.mode.ccm = {
|
||||
decrypt: function(prf, ciphertext, iv, adata, tlen) {
|
||||
tlen = tlen || 64;
|
||||
adata = adata || [];
|
||||
var L, i,
|
||||
var L,
|
||||
w=sjcl.bitArray,
|
||||
ivl = w.bitLength(iv) / 8,
|
||||
ol = w.bitLength(ciphertext),
|
||||
@@ -101,7 +101,7 @@ sjcl.mode.ccm = {
|
||||
*/
|
||||
_computeTag: function(prf, plaintext, iv, adata, tlen, L) {
|
||||
// compute B[0]
|
||||
var q, mac, field = 0, offset = 24, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
|
||||
var mac, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
|
||||
|
||||
tlen /= 8;
|
||||
|
||||
@@ -161,7 +161,7 @@ sjcl.mode.ccm = {
|
||||
* @private
|
||||
*/
|
||||
_ctrMode: function(prf, data, iv, tag, tlen, L) {
|
||||
var enc, i, w=sjcl.bitArray, xor = w._xor4, ctr, b, l = data.length, bl=w.bitLength(data);
|
||||
var enc, i, w=sjcl.bitArray, xor = w._xor4, ctr, l = data.length, bl=w.bitLength(data);
|
||||
|
||||
// start the ctr
|
||||
ctr = w.concat([w.partial(8,L-1)],iv).concat([0,0,0]).slice(0,4);
|
||||
|
||||
64
src/js/sjcl/core/codecBase32.js
Normal file
64
src/js/sjcl/core/codecBase32.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Nils Kenneweg
|
||||
*/
|
||||
|
||||
/** @namespace Base32 encoding/decoding */
|
||||
sjcl.codec.base32 = {
|
||||
/** The base32 alphabet.
|
||||
* @private
|
||||
*/
|
||||
_chars: "0123456789abcdefghjkmnpqrstvwxyz",
|
||||
|
||||
/* bits in an array */
|
||||
BITS: 32,
|
||||
/* base to encode at (2^x) */
|
||||
BASE: 5,
|
||||
/* bits - base */
|
||||
REMAINING: 27,
|
||||
|
||||
/** Convert from a bitArray to a base32 string. */
|
||||
fromBits: function (arr, _noEquals) {
|
||||
var BITS = sjcl.codec.base32.BITS, BASE = sjcl.codec.base32.BASE, REMAINING = sjcl.codec.base32.REMAINING;
|
||||
var out = "", i, bits=0, c = sjcl.codec.base32._chars, ta=0, bl = sjcl.bitArray.bitLength(arr);
|
||||
|
||||
for (i=0; out.length * BASE <= bl; ) {
|
||||
out += c.charAt((ta ^ arr[i]>>>bits) >>> REMAINING);
|
||||
if (bits < BASE) {
|
||||
ta = arr[i] << (BASE-bits);
|
||||
bits += REMAINING;
|
||||
i++;
|
||||
} else {
|
||||
ta <<= BASE;
|
||||
bits -= BASE;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Convert from a base32 string to a bitArray */
|
||||
toBits: function(str) {
|
||||
var BITS = sjcl.codec.base32.BITS, BASE = sjcl.codec.base32.BASE, REMAINING = sjcl.codec.base32.REMAINING;
|
||||
var out = [], i, bits=0, c = sjcl.codec.base32._chars, ta=0, x;
|
||||
|
||||
for (i=0; i<str.length; i++) {
|
||||
x = c.indexOf(str.charAt(i));
|
||||
if (x < 0) {
|
||||
throw new sjcl.exception.invalid("this isn't base32!");
|
||||
}
|
||||
if (bits > REMAINING) {
|
||||
bits -= REMAINING;
|
||||
out.push(ta ^ x>>>bits);
|
||||
ta = x << (BITS-bits);
|
||||
} else {
|
||||
bits += BASE;
|
||||
ta ^= x << (BITS-bits);
|
||||
}
|
||||
}
|
||||
if (bits&56) {
|
||||
out.push(sjcl.bitArray.partial(bits&56, ta, 1));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
@@ -15,7 +15,9 @@ sjcl.codec.base64 = {
|
||||
/** Convert from a bitArray to a base64 string. */
|
||||
fromBits: function (arr, _noEquals, _url) {
|
||||
var out = "", i, bits=0, c = sjcl.codec.base64._chars, ta=0, bl = sjcl.bitArray.bitLength(arr);
|
||||
if (_url) c = c.substr(0,62) + '-_';
|
||||
if (_url) {
|
||||
c = c.substr(0,62) + '-_';
|
||||
}
|
||||
for (i=0; out.length * 6 < bl; ) {
|
||||
out += c.charAt((ta ^ arr[i]>>>bits) >>> 26);
|
||||
if (bits < 6) {
|
||||
@@ -35,7 +37,9 @@ sjcl.codec.base64 = {
|
||||
toBits: function(str, _url) {
|
||||
str = str.replace(/\s|=/g,'');
|
||||
var out = [], i, bits=0, c = sjcl.codec.base64._chars, ta=0, x;
|
||||
if (_url) c = c.substr(0,62) + '-_';
|
||||
if (_url) {
|
||||
c = c.substr(0,62) + '-_';
|
||||
}
|
||||
for (i=0; i<str.length; i++) {
|
||||
x = c.indexOf(str.charAt(i));
|
||||
if (x < 0) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
sjcl.codec.hex = {
|
||||
/** Convert from a bitArray to a hex string. */
|
||||
fromBits: function (arr) {
|
||||
var out = "", i, x;
|
||||
var out = "", i;
|
||||
for (i=0; i<arr.length; i++) {
|
||||
out += ((arr[i]|0)+0xF00000000000).toString(16).substr(4);
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
* @param {String} plaintext The data to encrypt.
|
||||
* @param {Object} [params] The parameters including tag, iv and salt.
|
||||
* @param {Object} [rp] A returned version with filled-in parameters.
|
||||
* @return {String} The ciphertext.
|
||||
* @return {Object} The cipher raw data.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
*/
|
||||
encrypt: function (password, plaintext, params, rp) {
|
||||
_encrypt: function (password, plaintext, params, rp) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
|
||||
var j = sjcl.json, p = j._add({ iv: sjcl.random.randomWords(4,0) },
|
||||
j.defaults), tmp, prp, adata;
|
||||
j._add(p, params);
|
||||
@@ -32,7 +32,7 @@
|
||||
if (typeof p.iv === "string") {
|
||||
p.iv = sjcl.codec.base64.toBits(p.iv);
|
||||
}
|
||||
|
||||
|
||||
if (!sjcl.mode[p.mode] ||
|
||||
!sjcl.cipher[p.cipher] ||
|
||||
(typeof password === "string" && p.iter <= 100) ||
|
||||
@@ -41,7 +41,7 @@
|
||||
(p.iv.length < 2 || p.iv.length > 4)) {
|
||||
throw new sjcl.exception.invalid("json encrypt: invalid parameters");
|
||||
}
|
||||
|
||||
|
||||
if (typeof password === "string") {
|
||||
tmp = sjcl.misc.cachedPbkdf2(password, p);
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
@@ -58,39 +58,52 @@
|
||||
adata = sjcl.codec.utf8String.toBits(adata);
|
||||
}
|
||||
prp = new sjcl.cipher[p.cipher](password);
|
||||
|
||||
|
||||
/* return the json data */
|
||||
j._add(rp, p);
|
||||
rp.key = password;
|
||||
|
||||
|
||||
/* do the encryption */
|
||||
p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts);
|
||||
|
||||
|
||||
//return j.encode(j._subtract(p, j.defaults));
|
||||
return p;
|
||||
},
|
||||
|
||||
/** Simple encryption function.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} plaintext The data to encrypt.
|
||||
* @param {Object} [params] The parameters including tag, iv and salt.
|
||||
* @param {Object} [rp] A returned version with filled-in parameters.
|
||||
* @return {String} The ciphertext serialized data.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
*/
|
||||
encrypt: function (password, plaintext, params, rp) {
|
||||
var j = sjcl.json, p = j._encrypt.apply(j, arguments);
|
||||
return j.encode(p);
|
||||
},
|
||||
|
||||
|
||||
/** Simple decryption function.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} ciphertext The ciphertext to decrypt.
|
||||
* @param {Object} ciphertext The cipher raw data to decrypt.
|
||||
* @param {Object} [params] Additional non-default parameters.
|
||||
* @param {Object} [rp] A returned object with filled parameters.
|
||||
* @return {String} The plaintext.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
* @throws {sjcl.exception.corrupt} if the ciphertext is corrupt.
|
||||
*/
|
||||
decrypt: function (password, ciphertext, params, rp) {
|
||||
_decrypt: function (password, ciphertext, params, rp) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),j.decode(ciphertext)), params, true), ct, tmp, prp, adata=p.adata;
|
||||
|
||||
var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),ciphertext), params, true), ct, tmp, prp, adata=p.adata;
|
||||
if (typeof p.salt === "string") {
|
||||
p.salt = sjcl.codec.base64.toBits(p.salt);
|
||||
}
|
||||
if (typeof p.iv === "string") {
|
||||
p.iv = sjcl.codec.base64.toBits(p.iv);
|
||||
}
|
||||
|
||||
|
||||
if (!sjcl.mode[p.mode] ||
|
||||
!sjcl.cipher[p.cipher] ||
|
||||
(typeof password === "string" && p.iter <= 100) ||
|
||||
@@ -100,7 +113,7 @@
|
||||
(p.iv.length < 2 || p.iv.length > 4)) {
|
||||
throw new sjcl.exception.invalid("json decrypt: invalid parameters");
|
||||
}
|
||||
|
||||
|
||||
if (typeof password === "string") {
|
||||
tmp = sjcl.misc.cachedPbkdf2(password, p);
|
||||
password = tmp.key.slice(0,p.ks/32);
|
||||
@@ -112,15 +125,33 @@
|
||||
adata = sjcl.codec.utf8String.toBits(adata);
|
||||
}
|
||||
prp = new sjcl.cipher[p.cipher](password);
|
||||
|
||||
|
||||
/* do the decryption */
|
||||
ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, adata, p.ts);
|
||||
|
||||
|
||||
/* return the json data */
|
||||
j._add(rp, p);
|
||||
rp.key = password;
|
||||
|
||||
return sjcl.codec.utf8String.fromBits(ct);
|
||||
|
||||
if (params.raw === 1) {
|
||||
return ct;
|
||||
} else {
|
||||
return sjcl.codec.utf8String.fromBits(ct);
|
||||
}
|
||||
},
|
||||
|
||||
/** Simple decryption function.
|
||||
* @param {String|bitArray} password The password or key.
|
||||
* @param {String} ciphertext The ciphertext to decrypt.
|
||||
* @param {Object} [params] Additional non-default parameters.
|
||||
* @param {Object} [rp] A returned object with filled parameters.
|
||||
* @return {String} The plaintext.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
* @throws {sjcl.exception.corrupt} if the ciphertext is corrupt.
|
||||
*/
|
||||
decrypt: function (password, ciphertext, params, rp) {
|
||||
var j = sjcl.json;
|
||||
return j._decrypt(password, j.decode(ciphertext), params, rp);
|
||||
},
|
||||
|
||||
/** Encode a flat structure into a JSON string.
|
||||
@@ -138,23 +169,23 @@
|
||||
}
|
||||
out += comma + '"' + i + '":';
|
||||
comma = ',';
|
||||
|
||||
|
||||
switch (typeof obj[i]) {
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
out += obj[i];
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
out += '"' + escape(obj[i]) + '"';
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
out += '"' + sjcl.codec.base64.fromBits(obj[i],0) + '"';
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new sjcl.exception.bug("json encode: unsupported type");
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
out += obj[i];
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
out += '"' + escape(obj[i]) + '"';
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
out += '"' + sjcl.codec.base64.fromBits(obj[i],0) + '"';
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new sjcl.exception.bug("json encode: unsupported type");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,13 +205,15 @@
|
||||
}
|
||||
var a = str.replace(/^\{|\}$/g, '').split(/,/), out={}, i, m;
|
||||
for (i=0; i<a.length; i++) {
|
||||
if (!(m=a[i].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))) {
|
||||
if (!(m=a[i].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i))) {
|
||||
throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||
}
|
||||
if (m[3]) {
|
||||
out[m[2]] = parseInt(m[3],10);
|
||||
} else {
|
||||
} else if (m[4]) {
|
||||
out[m[2]] = m[2].match(/^(ct|salt|iv)$/) ? sjcl.codec.base64.toBits(m[4]) : unescape(m[4]);
|
||||
} else if (m[5]) {
|
||||
out[m[2]] = m[5] === 'true';
|
||||
}
|
||||
}
|
||||
return out;
|
||||
@@ -213,13 +246,13 @@
|
||||
*/
|
||||
_subtract: function (plus, minus) {
|
||||
var out = {}, i;
|
||||
|
||||
|
||||
for (i in plus) {
|
||||
if (plus.hasOwnProperty(i) && plus[i] !== minus[i]) {
|
||||
out[i] = plus[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
@@ -262,7 +295,7 @@ sjcl.misc._pbkdf2Cache = {};
|
||||
|
||||
/** Cached PBKDF2 key derivation.
|
||||
* @param {String} password The password.
|
||||
* @param {Object} [params] The derivation params (iteration count and optional salt).
|
||||
* @param {Object} [obj] The derivation params (iteration count and optional salt).
|
||||
* @return {Object} The derived data in key, the salt in salt.
|
||||
*/
|
||||
sjcl.misc.cachedPbkdf2 = function (password, obj) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* base class for all ecc operations.
|
||||
*/
|
||||
sjcl.ecc = {};
|
||||
|
||||
/**
|
||||
@@ -152,7 +155,9 @@ sjcl.ecc.pointJac.prototype = {
|
||||
a = y2.mul(this.x.mul(4)),
|
||||
b = y2.square().mul(8),
|
||||
z2 = this.z.square(),
|
||||
c = this.x.sub(z2).mul(3).mul(this.x.add(z2)),
|
||||
c = this.curve.a.toString() == (new sjcl.bn(-3)).toString() ?
|
||||
this.x.sub(z2).mul(3).mul(this.x.add(z2)) :
|
||||
this.x.square().mul(3).add(z2.square().mul(this.curve.a)),
|
||||
x = c.square().subM(a).subM(a),
|
||||
y = a.sub(x).mul(c).subM(b),
|
||||
z = this.y.add(this.y).mul(this.z);
|
||||
@@ -162,7 +167,7 @@ sjcl.ecc.pointJac.prototype = {
|
||||
/**
|
||||
* Returns a copy of this point converted to affine coordinates.
|
||||
* @return {sjcl.ecc.point} The converted point.
|
||||
*/
|
||||
*/
|
||||
toAffine: function() {
|
||||
if (this.isIdentity || this.z.equals(0)) {
|
||||
return new sjcl.ecc.point(this.curve);
|
||||
@@ -250,7 +255,7 @@ sjcl.ecc.pointJac.prototype = {
|
||||
*/
|
||||
sjcl.ecc.curve = function(Field, r, a, b, x, y) {
|
||||
this.field = Field;
|
||||
this.r = Field.prototype.modulus.sub(r);
|
||||
this.r = new sjcl.bn(r);
|
||||
this.a = new Field(a);
|
||||
this.b = new Field(b);
|
||||
this.G = new sjcl.ecc.point(this, new Field(x), new Field(y));
|
||||
@@ -269,7 +274,7 @@ sjcl.ecc.curve.prototype.fromBits = function (bits) {
|
||||
sjcl.ecc.curves = {
|
||||
c192: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p192,
|
||||
"0x662107c8eb94364e4b2dd7ce",
|
||||
"0xffffffffffffffffffffffff99def836146bc9b1b4d22831",
|
||||
-3,
|
||||
"0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
|
||||
"0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
|
||||
@@ -277,7 +282,7 @@ sjcl.ecc.curves = {
|
||||
|
||||
c224: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p224,
|
||||
"0xe95c1f470fc1ec22d6baa3a3d5c4",
|
||||
"0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d",
|
||||
-3,
|
||||
"0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
|
||||
"0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
|
||||
@@ -285,7 +290,7 @@ sjcl.ecc.curves = {
|
||||
|
||||
c256: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p256,
|
||||
"0x4319055358e8617b0c46353d039cdaae",
|
||||
"0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
|
||||
-3,
|
||||
"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
|
||||
"0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
|
||||
@@ -293,71 +298,135 @@ sjcl.ecc.curves = {
|
||||
|
||||
c384: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p384,
|
||||
"0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
|
||||
-3,
|
||||
"0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
|
||||
"0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
|
||||
"0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
|
||||
"0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"),
|
||||
|
||||
k192: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p192k,
|
||||
"0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d",
|
||||
0,
|
||||
3,
|
||||
"0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d",
|
||||
"0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d"),
|
||||
|
||||
k224: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p224k,
|
||||
"0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7",
|
||||
0,
|
||||
5,
|
||||
"0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c",
|
||||
"0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5"),
|
||||
|
||||
k256: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p256k,
|
||||
"0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
|
||||
0,
|
||||
7,
|
||||
"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* Diffie-Hellman-like public-key system */
|
||||
sjcl.ecc._dh = function(cn) {
|
||||
sjcl.ecc[cn] = {
|
||||
/** @constructor */
|
||||
publicKey: function(curve, point) {
|
||||
this._curve = curve;
|
||||
this._curveBitLength = curve.r.bitLength();
|
||||
if (point instanceof Array) {
|
||||
this._point = curve.fromBits(point);
|
||||
} else {
|
||||
this._point = point;
|
||||
}
|
||||
|
||||
this.get = function() {
|
||||
var pointbits = this._point.toBits();
|
||||
var len = sjcl.bitArray.bitLength(pointbits);
|
||||
var x = sjcl.bitArray.bitSlice(pointbits, 0, len/2);
|
||||
var y = sjcl.bitArray.bitSlice(pointbits, len/2);
|
||||
return { x: x, y: y };
|
||||
}
|
||||
},
|
||||
|
||||
/** @constructor */
|
||||
secretKey: function(curve, exponent) {
|
||||
this._curve = curve;
|
||||
this._curveBitLength = curve.r.bitLength();
|
||||
this._exponent = exponent;
|
||||
|
||||
this.get = function() {
|
||||
return this._exponent.toBits();
|
||||
}
|
||||
},
|
||||
|
||||
/** @constructor */
|
||||
generateKeys: function(curve, paranoia, sec) {
|
||||
if (curve === undefined) {
|
||||
curve = 256;
|
||||
}
|
||||
if (typeof curve === "number") {
|
||||
curve = sjcl.ecc.curves['c'+curve];
|
||||
if (curve === undefined) {
|
||||
throw new sjcl.exception.invalid("no such curve");
|
||||
}
|
||||
}
|
||||
if (sec === undefined) {
|
||||
var sec = sjcl.bn.random(curve.r, paranoia);
|
||||
}
|
||||
var pub = curve.G.mult(sec);
|
||||
return { pub: new sjcl.ecc[cn].publicKey(curve, pub),
|
||||
sec: new sjcl.ecc[cn].secretKey(curve, sec) };
|
||||
/** our basicKey classes
|
||||
*/
|
||||
sjcl.ecc.basicKey = {
|
||||
/** ecc publicKey.
|
||||
* @constructor
|
||||
* @param {curve} curve the elliptic curve
|
||||
* @param {point} point the point on the curve
|
||||
*/
|
||||
publicKey: function(curve, point) {
|
||||
this._curve = curve;
|
||||
this._curveBitLength = curve.r.bitLength();
|
||||
if (point instanceof Array) {
|
||||
this._point = curve.fromBits(point);
|
||||
} else {
|
||||
this._point = point;
|
||||
}
|
||||
};
|
||||
|
||||
/** get this keys point data
|
||||
* @return x and y as bitArrays
|
||||
*/
|
||||
this.get = function() {
|
||||
var pointbits = this._point.toBits();
|
||||
var len = sjcl.bitArray.bitLength(pointbits);
|
||||
var x = sjcl.bitArray.bitSlice(pointbits, 0, len/2);
|
||||
var y = sjcl.bitArray.bitSlice(pointbits, len/2);
|
||||
return { x: x, y: y };
|
||||
};
|
||||
},
|
||||
|
||||
/** ecc secretKey
|
||||
* @constructor
|
||||
* @param {curve} curve the elliptic curve
|
||||
* @param exponent
|
||||
*/
|
||||
secretKey: function(curve, exponent) {
|
||||
this._curve = curve;
|
||||
this._curveBitLength = curve.r.bitLength();
|
||||
this._exponent = exponent;
|
||||
|
||||
/** get this keys exponent data
|
||||
* @return {bitArray} exponent
|
||||
*/
|
||||
this.get = function () {
|
||||
return this._exponent.toBits();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc._dh("elGamal");
|
||||
/** @private */
|
||||
sjcl.ecc.basicKey.generateKeys = function(cn) {
|
||||
return function generateKeys(curve, paranoia, sec) {
|
||||
curve = curve || 256;
|
||||
|
||||
if (typeof curve === "number") {
|
||||
curve = sjcl.ecc.curves['c'+curve];
|
||||
if (curve === undefined) {
|
||||
throw new sjcl.exception.invalid("no such curve");
|
||||
}
|
||||
}
|
||||
sec = sec || sjcl.bn.random(curve.r, paranoia);
|
||||
|
||||
var pub = curve.G.mult(sec);
|
||||
return { pub: new sjcl.ecc[cn].publicKey(curve, pub),
|
||||
sec: new sjcl.ecc[cn].secretKey(curve, sec) };
|
||||
};
|
||||
};
|
||||
|
||||
/** elGamal keys */
|
||||
sjcl.ecc.elGamal = {
|
||||
/** generate keys
|
||||
* @function
|
||||
* @param curve
|
||||
* @param {int} paranoia Paranoia for generation (default 6)
|
||||
* @param {secretKey} sec secret Key to use. used to get the publicKey for ones secretKey
|
||||
*/
|
||||
generateKeys: sjcl.ecc.basicKey.generateKeys("elGamal"),
|
||||
/** elGamal publicKey.
|
||||
* @constructor
|
||||
* @augments sjcl.ecc.basicKey.publicKey
|
||||
*/
|
||||
publicKey: function (curve, point) {
|
||||
sjcl.ecc.basicKey.publicKey.apply(this, arguments);
|
||||
},
|
||||
/** elGamal secretKey
|
||||
* @constructor
|
||||
* @augments sjcl.ecc.basicKey.secretKey
|
||||
*/
|
||||
secretKey: function (curve, exponent) {
|
||||
sjcl.ecc.basicKey.secretKey.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc.elGamal.publicKey.prototype = {
|
||||
/** Kem function of elGamal Public Key
|
||||
* @param paranoia paranoia to use for randomization.
|
||||
* @return {object} key and tag. unkem(tag) with the corresponding secret key results in the key returned.
|
||||
*/
|
||||
kem: function(paranoia) {
|
||||
var sec = sjcl.bn.random(this._curve.r, paranoia),
|
||||
tag = this._curve.G.mult(sec).toBits(),
|
||||
@@ -367,34 +436,58 @@ sjcl.ecc.elGamal.publicKey.prototype = {
|
||||
};
|
||||
|
||||
sjcl.ecc.elGamal.secretKey.prototype = {
|
||||
/** UnKem function of elGamal Secret Key
|
||||
* @param {bitArray} tag The Tag to decrypt.
|
||||
* @return {bitArray} decrypted key.
|
||||
*/
|
||||
unkem: function(tag) {
|
||||
return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
|
||||
},
|
||||
|
||||
/** Diffie-Hellmann function
|
||||
* @param {elGamal.publicKey} pk The Public Key to do Diffie-Hellmann with
|
||||
* @return {bitArray} diffie-hellmann result for this key combination.
|
||||
*/
|
||||
dh: function(pk) {
|
||||
return sjcl.hash.sha256.hash(pk._point.mult(this._exponent).toBits());
|
||||
}
|
||||
},
|
||||
|
||||
/** Diffie-Hellmann function, compatible with Java generateSecret
|
||||
* @param {elGamal.publicKey} pk The Public Key to do Diffie-Hellmann with
|
||||
* @return {bitArray} undigested X value, diffie-hellmann result for this key combination,
|
||||
* compatible with Java generateSecret().
|
||||
*/
|
||||
dhJavaEc: function(pk) {
|
||||
return pk._point.mult(this._exponent).x.toBits();
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc._dh("ecdsa");
|
||||
|
||||
sjcl.ecc.ecdsa.secretKey.prototype = {
|
||||
sign: function(hash, paranoia, fakeLegacyVersion, fixedKForTesting) {
|
||||
if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
|
||||
hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
|
||||
}
|
||||
var R = this._curve.r,
|
||||
l = R.bitLength(),
|
||||
k = fixedKForTesting || sjcl.bn.random(R.sub(1), paranoia).add(1),
|
||||
r = this._curve.G.mult(k).x.mod(R),
|
||||
ss = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)),
|
||||
s = fakeLegacyVersion ? ss.inverseMod(R).mul(k).mod(R)
|
||||
: ss.mul(k.inverseMod(R)).mod(R);
|
||||
return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
|
||||
}
|
||||
/** ecdsa keys */
|
||||
sjcl.ecc.ecdsa = {
|
||||
/** generate keys
|
||||
* @function
|
||||
* @param curve
|
||||
* @param {int} paranoia Paranoia for generation (default 6)
|
||||
* @param {secretKey} sec secret Key to use. used to get the publicKey for ones secretKey
|
||||
*/
|
||||
generateKeys: sjcl.ecc.basicKey.generateKeys("ecdsa")
|
||||
};
|
||||
|
||||
/** ecdsa publicKey.
|
||||
* @constructor
|
||||
* @augments sjcl.ecc.basicKey.publicKey
|
||||
*/
|
||||
sjcl.ecc.ecdsa.publicKey = function (curve, point) {
|
||||
sjcl.ecc.basicKey.publicKey.apply(this, arguments);
|
||||
};
|
||||
|
||||
/** specific functions for ecdsa publicKey. */
|
||||
sjcl.ecc.ecdsa.publicKey.prototype = {
|
||||
/** Diffie-Hellmann function
|
||||
* @param {bitArray} hash hash to verify.
|
||||
* @param {bitArray} rs signature bitArray.
|
||||
* @param {boolean} fakeLegacyVersion use old legacy version
|
||||
*/
|
||||
verify: function(hash, rs, fakeLegacyVersion) {
|
||||
if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
|
||||
hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
|
||||
@@ -418,3 +511,33 @@ sjcl.ecc.ecdsa.publicKey.prototype = {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/** ecdsa secretKey
|
||||
* @constructor
|
||||
* @augments sjcl.ecc.basicKey.publicKey
|
||||
*/
|
||||
sjcl.ecc.ecdsa.secretKey = function (curve, exponent) {
|
||||
sjcl.ecc.basicKey.secretKey.apply(this, arguments);
|
||||
};
|
||||
|
||||
/** specific functions for ecdsa secretKey. */
|
||||
sjcl.ecc.ecdsa.secretKey.prototype = {
|
||||
/** Diffie-Hellmann function
|
||||
* @param {bitArray} hash hash to sign.
|
||||
* @param {int} paranoia paranoia for random number generation
|
||||
* @param {boolean} fakeLegacyVersion use old legacy version
|
||||
*/
|
||||
sign: function(hash, paranoia, fakeLegacyVersion, fixedKForTesting) {
|
||||
if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
|
||||
hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
|
||||
}
|
||||
var R = this._curve.r,
|
||||
l = R.bitLength(),
|
||||
k = fixedKForTesting || sjcl.bn.random(R.sub(1), paranoia).add(1),
|
||||
r = this._curve.G.mult(k).x.mod(R),
|
||||
ss = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)),
|
||||
s = fakeLegacyVersion ? ss.inverseMod(R).mul(k).mod(R)
|
||||
: ss.mul(k.inverseMod(R)).mod(R);
|
||||
return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -120,7 +120,7 @@ sjcl.mode.gcm = {
|
||||
* @param {Number} tlen The length of the tag, in bits.
|
||||
*/
|
||||
_ctrMode: function(encrypt, prf, data, adata, iv, tlen) {
|
||||
var H, J0, S0, enc, i, ctr, tag, last, l, bl, abl, ivbl, w=sjcl.bitArray, xor=w._xor4;
|
||||
var H, J0, S0, enc, i, ctr, tag, last, l, bl, abl, ivbl, w=sjcl.bitArray;
|
||||
|
||||
// Calculate data lengths
|
||||
l = data.length;
|
||||
|
||||
@@ -27,13 +27,35 @@ sjcl.misc.hmac = function (key, Hash) {
|
||||
|
||||
this._baseHash[0].update(exKey[0]);
|
||||
this._baseHash[1].update(exKey[1]);
|
||||
this._resultHash = new Hash(this._baseHash[0]);
|
||||
};
|
||||
|
||||
/** HMAC with the specified hash function. Also called encrypt since it's a prf.
|
||||
* @param {bitArray|String} data The data to mac.
|
||||
*/
|
||||
sjcl.misc.hmac.prototype.encrypt = sjcl.misc.hmac.prototype.mac = function (data) {
|
||||
var w = new (this._hash)(this._baseHash[0]).update(data).finalize();
|
||||
return new (this._hash)(this._baseHash[1]).update(w).finalize();
|
||||
if (!this._updated) {
|
||||
this.update(data);
|
||||
return this.digest(data);
|
||||
} else {
|
||||
throw new sjcl.exception.invalid("encrypt on already updated hmac called!");
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.misc.hmac.prototype.reset = function () {
|
||||
this._resultHash = new this._hash(this._baseHash[0]);
|
||||
this._updated = false;
|
||||
};
|
||||
|
||||
sjcl.misc.hmac.prototype.update = function (data) {
|
||||
this._updated = true;
|
||||
this._resultHash.update(data);
|
||||
};
|
||||
|
||||
sjcl.misc.hmac.prototype.digest = function () {
|
||||
var w = this._resultHash.finalize(), result = new (this._hash)(this._baseHash[1]).update(w).finalize();
|
||||
|
||||
this.reset();
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -12,7 +12,7 @@
|
||||
* This is the method specified by RSA's PKCS #5 standard.
|
||||
*
|
||||
* @param {bitArray|String} password The password.
|
||||
* @param {bitArray} salt The salt. Should have lots of entropy.
|
||||
* @param {bitArray|String} salt The salt. Should have lots of entropy.
|
||||
* @param {Number} [count=1000] The number of iterations. Higher numbers make the function slower but more secure.
|
||||
* @param {Number} [length] The length of the derived key. Defaults to the
|
||||
output size of the hash function.
|
||||
@@ -30,6 +30,10 @@ sjcl.misc.pbkdf2 = function (password, salt, count, length, Prff) {
|
||||
password = sjcl.codec.utf8String.toBits(password);
|
||||
}
|
||||
|
||||
if (typeof salt === "string") {
|
||||
salt = sjcl.codec.utf8String.toBits(salt);
|
||||
}
|
||||
|
||||
Prff = Prff || sjcl.misc.hmac;
|
||||
|
||||
var prf = new Prff(password),
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
* @author Michael Brooks
|
||||
*/
|
||||
|
||||
/** @constructor
|
||||
* @class Random number generator
|
||||
*
|
||||
* @description
|
||||
* <b>Use sjcl.random as a singleton for this class!</b>
|
||||
* <p>
|
||||
* This random number generator is a derivative of Ferguson and Schneier's
|
||||
* generator Fortuna. It collects entropy from various events into several
|
||||
@@ -74,10 +75,11 @@ sjcl.prng = function(defaultParanoia) {
|
||||
this._PARANOIA_LEVELS = [0,48,64,96,128,192,256,384,512,768,1024];
|
||||
this._MILLISECONDS_PER_RESEED = 30000;
|
||||
this._BITS_PER_RESEED = 80;
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.prng.prototype = {
|
||||
/** Generate several random words, and return them in an array
|
||||
/** Generate several random words, and return them in an array.
|
||||
* A word consists of 32 bits (4 bytes)
|
||||
* @param {Number} nwords The number of words to generate.
|
||||
*/
|
||||
randomWords: function (nwords, paranoia) {
|
||||
@@ -102,7 +104,11 @@ sjcl.prng.prototype = {
|
||||
return out.slice(0,nwords);
|
||||
},
|
||||
|
||||
setDefaultParanoia: function (paranoia) {
|
||||
setDefaultParanoia: function (paranoia, allowZeroParanoia) {
|
||||
if (paranoia === 0 && allowZeroParanoia !== "Setting paranoia=0 will ruin your security; use it only for testing") {
|
||||
throw "Setting paranoia=0 will ruin your security; use it only for testing";
|
||||
}
|
||||
|
||||
this._defaultParanoia = paranoia;
|
||||
},
|
||||
|
||||
@@ -119,7 +125,7 @@ sjcl.prng.prototype = {
|
||||
i, tmp,
|
||||
t = (new Date()).valueOf(),
|
||||
robin = this._robins[source],
|
||||
oldReady = this.isReady(), err = 0;
|
||||
oldReady = this.isReady(), err = 0, objName;
|
||||
|
||||
id = this._collectorIds[source];
|
||||
if (id === undefined) { id = this._collectorIds[source] = this._collectorIdNext ++; }
|
||||
@@ -137,7 +143,7 @@ sjcl.prng.prototype = {
|
||||
break;
|
||||
|
||||
case "object":
|
||||
var objName = Object.prototype.toString.call(data);
|
||||
objName = Object.prototype.toString.call(data);
|
||||
if (objName === "[object Uint32Array]") {
|
||||
tmp = [];
|
||||
for (i = 0; i < data.length; i++) {
|
||||
@@ -149,7 +155,7 @@ sjcl.prng.prototype = {
|
||||
err = 1;
|
||||
}
|
||||
for (i=0; i<data.length && !err; i++) {
|
||||
if (typeof(data[i]) != "number") {
|
||||
if (typeof(data[i]) !== "number") {
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
@@ -234,14 +240,25 @@ sjcl.prng.prototype = {
|
||||
startCollectors: function () {
|
||||
if (this._collectorsStarted) { return; }
|
||||
|
||||
this._eventListener = {
|
||||
loadTimeCollector: this._bind(this._loadTimeCollector),
|
||||
mouseCollector: this._bind(this._mouseCollector),
|
||||
keyboardCollector: this._bind(this._keyboardCollector),
|
||||
accelerometerCollector: this._bind(this._accelerometerCollector),
|
||||
touchCollector: this._bind(this._touchCollector)
|
||||
};
|
||||
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener("load", this._loadTimeCollector, false);
|
||||
window.addEventListener("mousemove", this._mouseCollector, false);
|
||||
window.addEventListener("load", this._eventListener.loadTimeCollector, false);
|
||||
window.addEventListener("mousemove", this._eventListener.mouseCollector, false);
|
||||
window.addEventListener("keypress", this._eventListener.keyboardCollector, false);
|
||||
window.addEventListener("devicemotion", this._eventListener.accelerometerCollector, false);
|
||||
window.addEventListener("touchmove", this._eventListener.touchCollector, false);
|
||||
} else if (document.attachEvent) {
|
||||
document.attachEvent("onload", this._loadTimeCollector);
|
||||
document.attachEvent("onmousemove", this._mouseCollector);
|
||||
}
|
||||
else {
|
||||
document.attachEvent("onload", this._eventListener.loadTimeCollector);
|
||||
document.attachEvent("onmousemove", this._eventListener.mouseCollector);
|
||||
document.attachEvent("keypress", this._eventListener.keyboardCollector);
|
||||
} else {
|
||||
throw new sjcl.exception.bug("can't attach event");
|
||||
}
|
||||
|
||||
@@ -253,12 +270,17 @@ sjcl.prng.prototype = {
|
||||
if (!this._collectorsStarted) { return; }
|
||||
|
||||
if (window.removeEventListener) {
|
||||
window.removeEventListener("load", this._loadTimeCollector, false);
|
||||
window.removeEventListener("mousemove", this._mouseCollector, false);
|
||||
} else if (window.detachEvent) {
|
||||
window.detachEvent("onload", this._loadTimeCollector);
|
||||
window.detachEvent("onmousemove", this._mouseCollector);
|
||||
window.removeEventListener("load", this._eventListener.loadTimeCollector, false);
|
||||
window.removeEventListener("mousemove", this._eventListener.mouseCollector, false);
|
||||
window.removeEventListener("keypress", this._eventListener.keyboardCollector, false);
|
||||
window.removeEventListener("devicemotion", this._eventListener.accelerometerCollector, false);
|
||||
window.removeEventListener("touchmove", this._eventListener.touchCollector, false);
|
||||
} else if (document.detachEvent) {
|
||||
document.detachEvent("onload", this._eventListener.loadTimeCollector);
|
||||
document.detachEvent("onmousemove", this._eventListener.mouseCollector);
|
||||
document.detachEvent("keypress", this._eventListener.keyboardCollector);
|
||||
}
|
||||
|
||||
this._collectorsStarted = false;
|
||||
},
|
||||
|
||||
@@ -275,23 +297,30 @@ sjcl.prng.prototype = {
|
||||
/** remove an event listener for progress or seeded-ness */
|
||||
removeEventListener: function (name, cb) {
|
||||
var i, j, cbs=this._callbacks[name], jsTemp=[];
|
||||
|
||||
|
||||
/* I'm not sure if this is necessary; in C++, iterating over a
|
||||
* collection and modifying it at the same time is a no-no.
|
||||
*/
|
||||
|
||||
|
||||
for (j in cbs) {
|
||||
if (cbs.hasOwnProperty(j) && cbs[j] === cb) {
|
||||
if (cbs.hasOwnProperty(j) && cbs[j] === cb) {
|
||||
jsTemp.push(j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i=0; i<jsTemp.length; i++) {
|
||||
j = jsTemp[i];
|
||||
delete cbs[j];
|
||||
}
|
||||
},
|
||||
|
||||
_bind: function (func) {
|
||||
var that = this;
|
||||
return function () {
|
||||
func.apply(that, arguments);
|
||||
};
|
||||
},
|
||||
|
||||
/** Generate 4 random words, no reseed, no gate.
|
||||
* @private
|
||||
*/
|
||||
@@ -363,44 +392,131 @@ sjcl.prng.prototype = {
|
||||
this._reseed(reseedData);
|
||||
},
|
||||
|
||||
_keyboardCollector: function () {
|
||||
this._addCurrentTimeToEntropy(1);
|
||||
},
|
||||
|
||||
_mouseCollector: function (ev) {
|
||||
var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
|
||||
sjcl.random.addEntropy([x,y], 2, "mouse");
|
||||
var x, y;
|
||||
|
||||
try {
|
||||
x = ev.x || ev.clientX || ev.offsetX || 0;
|
||||
y = ev.y || ev.clientY || ev.offsetY || 0;
|
||||
} catch (err) {
|
||||
// Event originated from a secure element. No mouse position available.
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (x != 0 && y!= 0) {
|
||||
sjcl.random.addEntropy([x,y], 2, "mouse");
|
||||
}
|
||||
|
||||
this._addCurrentTimeToEntropy(0);
|
||||
},
|
||||
|
||||
_touchCollector: function(ev) {
|
||||
var touch = ev.touches[0] || ev.changedTouches[0];
|
||||
var x = touch.pageX || touch.clientX,
|
||||
y = touch.pageY || touch.clientY;
|
||||
|
||||
sjcl.random.addEntropy([x,y],1,"touch");
|
||||
|
||||
this._addCurrentTimeToEntropy(0);
|
||||
},
|
||||
|
||||
_loadTimeCollector: function (ev) {
|
||||
sjcl.random.addEntropy((new Date()).valueOf(), 2, "loadtime");
|
||||
_loadTimeCollector: function () {
|
||||
this._addCurrentTimeToEntropy(2);
|
||||
},
|
||||
|
||||
|
||||
_addCurrentTimeToEntropy: function (estimatedEntropy) {
|
||||
if (typeof window !== 'undefined' && window.performance && typeof window.performance.now === "function") {
|
||||
//how much entropy do we want to add here?
|
||||
sjcl.random.addEntropy(window.performance.now(), estimatedEntropy, "loadtime");
|
||||
} else {
|
||||
sjcl.random.addEntropy((new Date()).valueOf(), estimatedEntropy, "loadtime");
|
||||
}
|
||||
},
|
||||
_accelerometerCollector: function (ev) {
|
||||
var ac = ev.accelerationIncludingGravity.x||ev.accelerationIncludingGravity.y||ev.accelerationIncludingGravity.z;
|
||||
if(window.orientation){
|
||||
var or = window.orientation;
|
||||
if (typeof or === "number") {
|
||||
sjcl.random.addEntropy(or, 1, "accelerometer");
|
||||
}
|
||||
}
|
||||
if (ac) {
|
||||
sjcl.random.addEntropy(ac, 2, "accelerometer");
|
||||
}
|
||||
this._addCurrentTimeToEntropy(0);
|
||||
},
|
||||
|
||||
_fireEvent: function (name, arg) {
|
||||
var j, cbs=sjcl.random._callbacks[name], cbsTemp=[];
|
||||
/* TODO: there is a race condition between removing collectors and firing them */
|
||||
/* TODO: there is a race condition between removing collectors and firing them */
|
||||
|
||||
/* I'm not sure if this is necessary; in C++, iterating over a
|
||||
* collection and modifying it at the same time is a no-no.
|
||||
*/
|
||||
|
||||
|
||||
for (j in cbs) {
|
||||
if (cbs.hasOwnProperty(j)) {
|
||||
if (cbs.hasOwnProperty(j)) {
|
||||
cbsTemp.push(cbs[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (j=0; j<cbsTemp.length; j++) {
|
||||
cbsTemp[j](arg);
|
||||
cbsTemp[j](arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** an instance for the prng.
|
||||
* @see sjcl.prng
|
||||
*/
|
||||
sjcl.random = new sjcl.prng(6);
|
||||
|
||||
(function(){
|
||||
try {
|
||||
// get cryptographically strong entropy in Webkit
|
||||
var ab = new Uint32Array(32);
|
||||
crypto.getRandomValues(ab);
|
||||
sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues");
|
||||
} catch (e) {
|
||||
// no getRandomValues :-(
|
||||
// function for getting nodejs crypto module. catches and ignores errors.
|
||||
function getCryptoModule() {
|
||||
try {
|
||||
return require('crypto');
|
||||
}
|
||||
catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
try {
|
||||
var buf, crypt, ab;
|
||||
|
||||
// get cryptographically strong entropy depending on runtime environment
|
||||
if (typeof module !== 'undefined' && module.exports && (crypt = getCryptoModule()) && crypt.randomBytes) {
|
||||
buf = crypt.randomBytes(1024/8);
|
||||
buf = new Uint32Array(new Uint8Array(buf).buffer);
|
||||
sjcl.random.addEntropy(buf, 1024, "crypto.randomBytes");
|
||||
|
||||
} else if (typeof window !== 'undefined' && typeof Uint32Array !== 'undefined') {
|
||||
ab = new Uint32Array(32);
|
||||
if (window.crypto && window.crypto.getRandomValues) {
|
||||
window.crypto.getRandomValues(ab);
|
||||
} else if (window.msCrypto && window.msCrypto.getRandomValues) {
|
||||
window.msCrypto.getRandomValues(ab);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// get cryptographically strong entropy in Webkit
|
||||
sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues");
|
||||
|
||||
} else {
|
||||
// no getRandomValues :-(
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof window !== 'undefined' && window.console) {
|
||||
console.log("There was an error collecting entropy from the browser:");
|
||||
console.log(e);
|
||||
//we do not want the library to fail due to randomness not being maintained.
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
@@ -138,8 +138,7 @@ sjcl.hash.sha1.prototype = {
|
||||
_block:function (words) {
|
||||
var t, tmp, a, b, c, d, e,
|
||||
w = words.slice(0),
|
||||
h = this._h,
|
||||
k = this._key;
|
||||
h = this._h;
|
||||
|
||||
a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ sjcl.hash.sha512.prototype = {
|
||||
t1h += chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
|
||||
t1l += krl;
|
||||
t1h += krh + ((t1l >>> 0) < (krl >>> 0) ? 1 : 0);
|
||||
t1l += wrl;
|
||||
t1l = t1l + wrl|0; // FF32..FF34 perf issue https://bugzilla.mozilla.org/show_bug.cgi?id=1054972
|
||||
t1h += wrh + ((t1l >>> 0) < (wrl >>> 0) ? 1 : 0);
|
||||
|
||||
// t2 = sigma0 + maj
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
"use strict";
|
||||
/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
|
||||
/*global document, window, escape, unescape */
|
||||
/*global document, window, escape, unescape, module, require, Uint32Array */
|
||||
|
||||
/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
|
||||
var sjcl = {
|
||||
@@ -68,6 +68,11 @@ var sjcl = {
|
||||
}
|
||||
};
|
||||
|
||||
if(typeof module != 'undefined' && module.exports){
|
||||
if(typeof module !== 'undefined' && module.exports){
|
||||
module.exports = sjcl;
|
||||
}
|
||||
if (typeof define === "function") {
|
||||
define([], function () {
|
||||
return sjcl;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<h2>Key Derivation</h2>
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="salt"">Salt:</label>
|
||||
<label for="salt">Salt:</label>
|
||||
<a class="random floatright" href="javascript:randomize('salt',2,0)">random</a>
|
||||
</div>
|
||||
<input type="text" id="salt" class="wide hex" autocomplete="off" size="17" maxlength="35"/>
|
||||
|
||||
16
src/js/sjcl/package.json
Normal file
16
src/js/sjcl/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "sjcl",
|
||||
"version": "1.0.1",
|
||||
"description": "Stanford Javascript Crypto Library",
|
||||
"main": "sjcl.js",
|
||||
"author": "bitwiseshiftleft",
|
||||
"keywords": ["encryption", "high-level", "crypto"],
|
||||
"repository" : {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bitwiseshiftleft/sjcl.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": { "node": "*" }
|
||||
}
|
||||
@@ -1,48 +1,54 @@
|
||||
"use strict";function q(a){throw a;}var t=void 0,u=!1;var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
|
||||
"undefined"!=typeof module&&module.exports&&(module.exports=sjcl);
|
||||
sjcl.cipher.aes=function(a){this.j[0][0][0]||this.D();var b,c,d,e,f=this.j[0][4],g=this.j[1];b=a.length;var h=1;4!==b&&(6!==b&&8!==b)&&q(new sjcl.exception.invalid("invalid aes key size"));this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
|
||||
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});
|
||||
sjcl.cipher.aes=function(a){this.k[0][0][0]||this.D();var b,c,d,e,f=this.k[0][4],g=this.k[1];b=a.length;var h=1;4!==b&&(6!==b&&8!==b)&&q(new sjcl.exception.invalid("invalid aes key size"));this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
|
||||
255]]};
|
||||
sjcl.cipher.aes.prototype={encrypt:function(a){return y(this,a,0)},decrypt:function(a){return y(this,a,1)},j:[[[],[],[],[],[]],[[],[],[],[],[]]],D:function(){var a=this.j[0],b=this.j[1],c=a[4],d=b[4],e,f,g,h=[],l=[],k,n,m,p;for(e=0;0x100>e;e++)l[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=k||1,g=l[g]||1){m=g^g<<1^g<<2^g<<3^g<<4;m=m>>8^m&255^99;c[f]=m;d[m]=f;n=h[e=h[k=h[f]]];p=0x1010101*n^0x10001*e^0x101*k^0x1010100*f;n=0x101*h[m]^0x1010100*m;for(e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8}for(e=
|
||||
sjcl.cipher.aes.prototype={encrypt:function(a){return y(this,a,0)},decrypt:function(a){return y(this,a,1)},k:[[[],[],[],[],[]],[[],[],[],[],[]]],D:function(){var a=this.k[0],b=this.k[1],c=a[4],d=b[4],e,f,g,h=[],l=[],k,n,m,p;for(e=0;0x100>e;e++)l[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=k||1,g=l[g]||1){m=g^g<<1^g<<2^g<<3^g<<4;m=m>>8^m&255^99;c[f]=m;d[m]=f;n=h[e=h[k=h[f]]];p=0x1010101*n^0x10001*e^0x101*k^0x1010100*f;n=0x101*h[m]^0x1010100*m;for(e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8}for(e=
|
||||
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
|
||||
function y(a,b,c){4!==b.length&&q(new sjcl.exception.invalid("invalid aes block size"));var d=a.a[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,l,k,n=d.length/4-2,m,p=4,s=[0,0,0,0];h=a.j[c];a=h[0];var r=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^r[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],l=a[f>>>24]^r[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],k=a[g>>>24]^r[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^r[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=l,g=k;for(m=0;4>
|
||||
function y(a,b,c){4!==b.length&&q(new sjcl.exception.invalid("invalid aes block size"));var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,l,k,n=d.length/4-2,m,p=4,s=[0,0,0,0];h=a.k[c];a=h[0];var r=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^r[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],l=a[f>>>24]^r[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],k=a[g>>>24]^r[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^r[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=l,g=k;for(m=0;4>
|
||||
m;m++)s[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return s}
|
||||
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.O(a.slice(b/32),32-(b&31)).slice(1);return c===t?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.O(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
|
||||
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===t?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.P(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
|
||||
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return u;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
|
||||
c},O:function(a,b,c,d){var e;e=0;for(d===t&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},k:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}};
|
||||
c},P:function(a,b,c,d){var e;e=0;for(d===t&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},l:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
|
||||
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
|
||||
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
|
||||
sjcl.codec.base64={I:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.I,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.I,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++)h=f.indexOf(a.charAt(d)),
|
||||
0>h&&q(new sjcl.exception.invalid("this isn't base64!")),26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e);e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.a[0]||this.D();a?(this.q=a.q.slice(0),this.m=a.m.slice(0),this.g=a.g):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
|
||||
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.q=this.M.slice(0);this.m=[];this.g=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.m=sjcl.bitArray.concat(this.m,a);b=this.g;a=this.g=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)z(this,c.splice(0,16));return this},finalize:function(){var a,b=this.m,c=this.q,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.g/
|
||||
4294967296));for(b.push(this.g|0);b.length;)z(this,b.splice(0,16));this.reset();return c},M:[],a:[],D:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}var b=0,c=2,d;a:for(;64>b;c++){for(d=2;d*d<=c;d++)if(0===c%d)continue a;8>b&&(this.M[b]=a(Math.pow(c,0.5)));this.a[b]=a(Math.pow(c,1/3));b++}}};
|
||||
function z(a,b){var c,d,e,f=b.slice(0),g=a.q,h=a.a,l=g[0],k=g[1],n=g[2],m=g[3],p=g[4],s=g[5],r=g[6],v=g[7];for(c=0;64>c;c++)16>c?d=f[c]:(d=f[c+1&15],e=f[c+14&15],d=f[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+f[c&15]+f[c+9&15]|0),d=d+v+(p>>>6^p>>>11^p>>>25^p<<26^p<<21^p<<7)+(r^p&(s^r))+h[c],v=r,r=s,s=p,p=m+d|0,m=n,n=k,k=l,l=d+(k&n^m&(k^n))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;g[0]=g[0]+l|0;g[1]=g[1]+k|0;g[2]=g[2]+n|0;g[3]=g[3]+m|0;g[4]=g[4]+p|0;g[5]=g[5]+s|0;g[6]=
|
||||
sjcl.codec.base64={J:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.J,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.J,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++)h=f.indexOf(a.charAt(d)),
|
||||
0>h&&q(new sjcl.exception.invalid("this isn't base64!")),26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e);e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.D();a?(this.r=a.r.slice(0),this.o=a.o.slice(0),this.h=a.h):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
|
||||
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.r=this.N.slice(0);this.o=[];this.h=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.o=sjcl.bitArray.concat(this.o,a);b=this.h;a=this.h=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)z(this,c.splice(0,16));return this},finalize:function(){var a,b=this.o,c=this.r,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.h/
|
||||
4294967296));for(b.push(this.h|0);b.length;)z(this,b.splice(0,16));this.reset();return c},N:[],b:[],D:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}var b=0,c=2,d;a:for(;64>b;c++){for(d=2;d*d<=c;d++)if(0===c%d)continue a;8>b&&(this.N[b]=a(Math.pow(c,0.5)));this.b[b]=a(Math.pow(c,1/3));b++}}};
|
||||
function z(a,b){var c,d,e,f=b.slice(0),g=a.r,h=a.b,l=g[0],k=g[1],n=g[2],m=g[3],p=g[4],s=g[5],r=g[6],v=g[7];for(c=0;64>c;c++)16>c?d=f[c]:(d=f[c+1&15],e=f[c+14&15],d=f[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+f[c&15]+f[c+9&15]|0),d=d+v+(p>>>6^p>>>11^p>>>25^p<<26^p<<21^p<<7)+(r^p&(s^r))+h[c],v=r,r=s,s=p,p=m+d|0,m=n,n=k,k=l,l=d+(k&n^m&(k^n))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;g[0]=g[0]+l|0;g[1]=g[1]+k|0;g[2]=g[2]+n|0;g[3]=g[3]+m|0;g[4]=g[4]+p|0;g[5]=g[5]+s|0;g[6]=
|
||||
g[6]+r|0;g[7]=g[7]+v|0}
|
||||
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,l=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];7>l&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(f=2;4>f&&k>>>8*f;f++);f<15-l&&(f=15-l);c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.K(a,b,c,d,e,f);g=sjcl.mode.ccm.n(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),l=f.clamp(b,h-e),k=f.bitSlice(b,
|
||||
h-e),h=(h-e)/8;7>g&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));l=sjcl.mode.ccm.n(a,l,c,k,e,b);a=sjcl.mode.ccm.K(a,l.data,c,d,e,b);f.equal(l.tag,a)||q(new sjcl.exception.corrupt("ccm: tag doesn't match"));return l.data},K:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,l=h.k;e/=8;(e%2||4>e||16<e)&&q(new sjcl.exception.invalid("ccm: invalid tag length"));(0xffffffff<d.length||0xffffffff<b.length)&&q(new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"));
|
||||
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c]));g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(l(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(l(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,8*e)},n:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.k;var l=b.length,k=h.bitLength(b);c=h.concat([h.partial(8,
|
||||
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,l=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];7>l&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(f=2;4>f&&k>>>8*f;f++);f<15-l&&(f=15-l);c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.L(a,b,c,d,e,f);g=sjcl.mode.ccm.p(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),l=f.clamp(b,h-e),k=f.bitSlice(b,
|
||||
h-e),h=(h-e)/8;7>g&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));l=sjcl.mode.ccm.p(a,l,c,k,e,b);a=sjcl.mode.ccm.L(a,l.data,c,d,e,b);f.equal(l.tag,a)||q(new sjcl.exception.corrupt("ccm: tag doesn't match"));return l.data},L:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,l=h.l;e/=8;(e%2||4>e||16<e)&&q(new sjcl.exception.invalid("ccm: invalid tag length"));(0xffffffff<d.length||0xffffffff<b.length)&&q(new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"));
|
||||
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c]));g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(l(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(l(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,8*e)},p:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.l;var l=b.length,k=h.bitLength(b);c=h.concat([h.partial(8,
|
||||
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!l)return{tag:d,data:[]};for(g=0;g<l;g+=4)c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,k)}}};
|
||||
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));var g,h=sjcl.mode.ocb2.G,l=sjcl.bitArray,k=l.k,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=k(n,m),p=p.concat(k(c,a.encrypt(k(c,m)))),c=h(c);m=b.slice(g);b=l.bitLength(m);g=a.encrypt(k(c,[0,0,0,b]));m=l.clamp(k(m.concat([0,0,0]),g),b);n=k(n,k(m.concat([0,0,0]),g));n=a.encrypt(k(n,k(c,h(c))));d.length&&
|
||||
(n=k(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(l.concat(m,l.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));e=e||64;var g=sjcl.mode.ocb2.G,h=sjcl.bitArray,l=h.k,k=[0,0,0,0],n=g(a.encrypt(c)),m,p,s=sjcl.bitArray.bitLength(b)-e,r=[];d=d||[];for(c=0;c+4<s/32;c+=4)m=l(n,a.decrypt(l(n,b.slice(c,c+4)))),k=l(k,m),r=r.concat(m),n=g(n);p=s-32*c;m=a.encrypt(l(n,[0,0,0,p]));m=l(m,h.clamp(b.slice(c),p).concat([0,0,0]));
|
||||
k=l(k,m);k=a.encrypt(l(k,l(n,g(n))));d.length&&(k=l(k,f?d:sjcl.mode.ocb2.pmac(a,d)));h.equal(h.clamp(k,e),h.bitSlice(b,s))||q(new sjcl.exception.corrupt("ocb: tag doesn't match"));return r.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.G,e=sjcl.bitArray,f=e.k,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);return a.encrypt(f(d(f(h,
|
||||
d(h))),g))},G:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
|
||||
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.n(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.n(u,a,f,d,c,e);g.equal(a.tag,b)||q(new sjcl.exception.corrupt("gcm: tag doesn't match"));return a.data},U:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.k;e=[0,0,0,0];f=b.slice(0);
|
||||
for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},f:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.U(b,a);return b},n:function(a,b,c,d,e,f){var g,h,l,k,n,m,p,s,r=sjcl.bitArray;m=c.length;p=r.bitLength(c);s=r.bitLength(d);h=r.bitLength(e);g=b.encrypt([0,
|
||||
0,0,0]);96===h?(e=e.slice(0),e=r.concat(e,[1])):(e=sjcl.mode.gcm.f(g,[0,0,0,0],e),e=sjcl.mode.gcm.f(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.f(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.f(g,h,c));for(k=0;k<m;k+=4)n[3]++,l=b.encrypt(n),c[k]^=l[0],c[k+1]^=l[1],c[k+2]^=l[2],c[k+3]^=l[3];c=r.clamp(c,p);a&&(d=sjcl.mode.gcm.f(g,h,c));a=[Math.floor(s/0x100000000),s&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.f(g,d,a);l=b.encrypt(e);d[0]^=l[0];
|
||||
d[1]^=l[1];d[2]^=l[2];d[3]^=l[3];return{tag:r.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.L=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.o=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.o[0].update(c[0]);this.o[1].update(c[1])};sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){a=(new this.L(this.o[0])).update(a).finalize();return(new this.L(this.o[1])).update(a).finalize()};
|
||||
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;(0>d||0>c)&&q(sjcl.exception.invalid("invalid params to pbkdf2"));"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,l,k=[],n=sjcl.bitArray;for(l=1;32*k.length<(d||1);l++){e=f=a.encrypt(n.concat(b,[l]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}k=k.concat(e)}d&&(k=n.clamp(k,d));return k};
|
||||
sjcl.prng=function(a){this.b=[new sjcl.hash.sha256];this.h=[0];this.F=0;this.t={};this.C=0;this.J={};this.N=this.c=this.i=this.T=0;this.a=[0,0,0,0,0,0,0,0];this.e=[0,0,0,0];this.A=t;this.B=a;this.p=u;this.z={progress:{},seeded:{}};this.l=this.S=0;this.u=1;this.w=2;this.Q=0x10000;this.H=[0,48,64,96,128,192,0x100,384,512,768,1024];this.R=3E4;this.P=80};
|
||||
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;d===this.l&&q(new sjcl.exception.notReady("generator isn't seeded"));if(d&this.w){d=!(d&this.u);e=[];var f=0,g;this.N=e[0]=(new Date).valueOf()+this.R;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.b.length&&!(e=e.concat(this.b[g].finalize()),f+=this.h[g],this.h[g]=0,!d&&this.F&1<<g);g++);this.F>=1<<this.b.length&&(this.b.push(new sjcl.hash.sha256),this.h.push(0));this.c-=f;f>this.i&&(this.i=f);this.F++;
|
||||
this.a=sjcl.hash.sha256.hash(this.a.concat(e));this.A=new sjcl.cipher.aes(this.a);for(d=0;4>d&&!(this.e[d]=this.e[d]+1|0,this.e[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.Q&&A(this),e=B(this),c.push(e[0],e[1],e[2],e[3]);A(this);return c.slice(0,a)},setDefaultParanoia:function(a){this.B=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.t[c],h=this.isReady(),l=0;d=this.J[c];d===t&&(d=this.J[c]=this.T++);g===t&&(g=this.t[c]=0);this.t[c]=(this.t[c]+1)%this.b.length;switch(typeof a){case "number":b===
|
||||
t&&(b=1);this.b[g].update([d,this.C++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{"[object Array]"!==c&&(l=1);for(c=0;c<a.length&&!l;c++)"number"!=typeof a[c]&&(l=1)}if(!l){if(b===t)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e>>>=1;this.b[g].update([d,this.C++,2,b,f,a.length].concat(a))}break;case "string":b===t&&(b=a.length);this.b[g].update([d,this.C++,3,b,f,a.length]);this.b[g].update(a);
|
||||
break;default:l=1}l&&q(new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"));this.h[g]+=b;this.c+=b;h===this.l&&(this.isReady()!==this.l&&C("seeded",Math.max(this.i,this.c)),C("progress",this.getProgress()))},isReady:function(a){a=this.H[a!==t?a:this.B];return this.i&&this.i>=a?this.h[0]>this.P&&(new Date).valueOf()>this.N?this.w|this.u:this.u:this.c>=a?this.w|this.l:this.l},getProgress:function(a){a=this.H[a?a:this.B];return this.i>=a?1:this.c>a?1:this.c/
|
||||
a},startCollectors:function(){this.p||(window.addEventListener?(window.addEventListener("load",this.r,u),window.addEventListener("mousemove",this.s,u)):document.attachEvent?(document.attachEvent("onload",this.r),document.attachEvent("onmousemove",this.s)):q(new sjcl.exception.bug("can't attach event")),this.p=!0)},stopCollectors:function(){this.p&&(window.removeEventListener?(window.removeEventListener("load",this.r,u),window.removeEventListener("mousemove",this.s,u)):window.detachEvent&&(window.detachEvent("onload",
|
||||
this.r),window.detachEvent("onmousemove",this.s)),this.p=u)},addEventListener:function(a,b){this.z[a][this.S++]=b},removeEventListener:function(a,b){var c,d,e=this.z[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},s:function(a){sjcl.random.addEntropy([a.x||a.clientX||a.offsetX||0,a.y||a.clientY||a.offsetY||0],2,"mouse")},r:function(){sjcl.random.addEntropy((new Date).valueOf(),2,"loadtime")}};
|
||||
function C(a,b){var c,d=sjcl.random.z[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function A(a){a.a=B(a).concat(B(a));a.A=new sjcl.cipher.aes(a.a)}function B(a){for(var b=0;4>b&&!(a.e[b]=a.e[b]+1|0,a.e[b]);b++);return a.A.encrypt(a.e)}sjcl.random=new sjcl.prng(6);try{var D=new Uint32Array(32);crypto.getRandomValues(D);sjcl.random.addEntropy(D,1024,"crypto['getRandomValues']")}catch(E){}
|
||||
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},encrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.d({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.d(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
|
||||
4<f.iv.length)&&q(new sjcl.exception.invalid("json encrypt: invalid parameters"));"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.d(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return e.encode(f)},
|
||||
decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.d(e.d(e.d({},e.defaults),e.decode(b)),c,!0);var f;c=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)&&q(new sjcl.exception.invalid("json decrypt: invalid parameters"));
|
||||
"string"===typeof a?(f=sjcl.misc.cachedPbkdf2(a,b),a=f.key.slice(0,b.ks/32),b.salt=f.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof c&&(c=sjcl.codec.utf8String.toBits(c));f=new sjcl.cipher[b.cipher](a);c=sjcl.mode[b.mode].decrypt(f,b.ct,b.iv,c,b.ts);e.d(d,b);d.key=a;return sjcl.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b))switch(b.match(/^[a-z0-9]+$/i)||
|
||||
q(new sjcl.exception.invalid("json encode: invalid property name")),c+=d+'"'+b+'":',d=",",typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:q(new sjcl.exception.bug("json encode: unsupported type"))}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");a.match(/^\{.*\}$/)||q(new sjcl.exception.invalid("json decode: this isn't json!"));a=a.replace(/^\{|\}$/g,"").split(/,/);var b=
|
||||
{},c,d;for(c=0;c<a.length;c++)(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))||q(new sjcl.exception.invalid("json decode: this isn't json!")),b[d[2]]=d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]);return b},d:function(a,b,c){a===t&&(a={});if(b===t)return a;for(var d in b)b.hasOwnProperty(d)&&(c&&(a[d]!==t&&a[d]!==b[d])&&q(new sjcl.exception.invalid("required parameter overridden")),a[d]=b[d]);return a},X:function(a,
|
||||
b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},W:function(a,b){var c={},d;for(d=0;d<b.length;d++)a[b[d]]!==t&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.V={};
|
||||
sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.V,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===t?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
|
||||
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));var g,h=sjcl.mode.ocb2.H,l=sjcl.bitArray,k=l.l,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=k(n,m),p=p.concat(k(c,a.encrypt(k(c,m)))),c=h(c);m=b.slice(g);b=l.bitLength(m);g=a.encrypt(k(c,[0,0,0,b]));m=l.clamp(k(m.concat([0,0,0]),g),b);n=k(n,k(m.concat([0,0,0]),g));n=a.encrypt(k(n,k(c,h(c))));d.length&&
|
||||
(n=k(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(l.concat(m,l.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));e=e||64;var g=sjcl.mode.ocb2.H,h=sjcl.bitArray,l=h.l,k=[0,0,0,0],n=g(a.encrypt(c)),m,p,s=sjcl.bitArray.bitLength(b)-e,r=[];d=d||[];for(c=0;c+4<s/32;c+=4)m=l(n,a.decrypt(l(n,b.slice(c,c+4)))),k=l(k,m),r=r.concat(m),n=g(n);p=s-32*c;m=a.encrypt(l(n,[0,0,0,p]));m=l(m,h.clamp(b.slice(c),p).concat([0,0,0]));
|
||||
k=l(k,m);k=a.encrypt(l(k,l(n,g(n))));d.length&&(k=l(k,f?d:sjcl.mode.ocb2.pmac(a,d)));h.equal(h.clamp(k,e),h.bitSlice(b,s))||q(new sjcl.exception.corrupt("ocb: tag doesn't match"));return r.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.H,e=sjcl.bitArray,f=e.l,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);return a.encrypt(f(d(f(h,
|
||||
d(h))),g))},H:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
|
||||
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.p(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.p(u,a,f,d,c,e);g.equal(a.tag,b)||q(new sjcl.exception.corrupt("gcm: tag doesn't match"));return a.data},Z:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.l;e=[0,0,0,0];f=b.slice(0);
|
||||
for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},g:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.Z(b,a);return b},p:function(a,b,c,d,e,f){var g,h,l,k,n,m,p,s,r=sjcl.bitArray;m=c.length;p=r.bitLength(c);s=r.bitLength(d);h=r.bitLength(e);g=b.encrypt([0,
|
||||
0,0,0]);96===h?(e=e.slice(0),e=r.concat(e,[1])):(e=sjcl.mode.gcm.g(g,[0,0,0,0],e),e=sjcl.mode.gcm.g(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.g(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.g(g,h,c));for(k=0;k<m;k+=4)n[3]++,l=b.encrypt(n),c[k]^=l[0],c[k+1]^=l[1],c[k+2]^=l[2],c[k+3]^=l[3];c=r.clamp(c,p);a&&(d=sjcl.mode.gcm.g(g,h,c));a=[Math.floor(s/0x100000000),s&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.g(g,d,a);l=b.encrypt(e);d[0]^=l[0];
|
||||
d[1]^=l[1];d[2]^=l[2];d[3]^=l[3];return{tag:r.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.M=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.n=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.n[0].update(c[0]);this.n[1].update(c[1]);this.G=new b(this.n[0])};
|
||||
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){this.Q&&q(new sjcl.exception.invalid("encrypt on already updated hmac called!"));this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.G=new this.M(this.n[0]);this.Q=u};sjcl.misc.hmac.prototype.update=function(a){this.Q=!0;this.G.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.G.finalize(),a=(new this.M(this.n[1])).update(a).finalize();this.reset();return a};
|
||||
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;(0>d||0>c)&&q(sjcl.exception.invalid("invalid params to pbkdf2"));"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,l,k=[],n=sjcl.bitArray;for(l=1;32*k.length<(d||1);l++){e=f=a.encrypt(n.concat(b,[l]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}k=k.concat(e)}d&&(k=n.clamp(k,d));return k};
|
||||
sjcl.prng=function(a){this.c=[new sjcl.hash.sha256];this.i=[0];this.F=0;this.s={};this.C=0;this.K={};this.O=this.d=this.j=this.W=0;this.b=[0,0,0,0,0,0,0,0];this.f=[0,0,0,0];this.A=t;this.B=a;this.q=u;this.w={progress:{},seeded:{}};this.m=this.V=0;this.t=1;this.u=2;this.S=0x10000;this.I=[0,48,64,96,128,192,0x100,384,512,768,1024];this.T=3E4;this.R=80};
|
||||
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;d===this.m&&q(new sjcl.exception.notReady("generator isn't seeded"));if(d&this.u){d=!(d&this.t);e=[];var f=0,g;this.O=e[0]=(new Date).valueOf()+this.T;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.c.length&&!(e=e.concat(this.c[g].finalize()),f+=this.i[g],this.i[g]=0,!d&&this.F&1<<g);g++);this.F>=1<<this.c.length&&(this.c.push(new sjcl.hash.sha256),this.i.push(0));this.d-=f;f>this.j&&(this.j=f);this.F++;
|
||||
this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.A=new sjcl.cipher.aes(this.b);for(d=0;4>d&&!(this.f[d]=this.f[d]+1|0,this.f[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.S&&A(this),e=B(this),c.push(e[0],e[1],e[2],e[3]);A(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b&&q("Setting paranoia=0 will ruin your security; use it only for testing");this.B=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),
|
||||
g=this.s[c],h=this.isReady(),l=0;d=this.K[c];d===t&&(d=this.K[c]=this.W++);g===t&&(g=this.s[c]=0);this.s[c]=(this.s[c]+1)%this.c.length;switch(typeof a){case "number":b===t&&(b=1);this.c[g].update([d,this.C++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{"[object Array]"!==c&&(l=1);for(c=0;c<a.length&&!l;c++)"number"!==typeof a[c]&&(l=1)}if(!l){if(b===t)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,
|
||||
e>>>=1;this.c[g].update([d,this.C++,2,b,f,a.length].concat(a))}break;case "string":b===t&&(b=a.length);this.c[g].update([d,this.C++,3,b,f,a.length]);this.c[g].update(a);break;default:l=1}l&&q(new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"));this.i[g]+=b;this.d+=b;h===this.m&&(this.isReady()!==this.m&&C("seeded",Math.max(this.j,this.d)),C("progress",this.getProgress()))},isReady:function(a){a=this.I[a!==t?a:this.B];return this.j&&this.j>=a?this.i[0]>this.R&&
|
||||
(new Date).valueOf()>this.O?this.u|this.t:this.t:this.d>=a?this.u|this.m:this.m},getProgress:function(a){a=this.I[a?a:this.B];return this.j>=a?1:this.d>a?1:this.d/a},startCollectors:function(){this.q||(this.a={loadTimeCollector:D(this,this.aa),mouseCollector:D(this,this.ba),keyboardCollector:D(this,this.$),accelerometerCollector:D(this,this.U)},window.addEventListener?(window.addEventListener("load",this.a.loadTimeCollector,u),window.addEventListener("mousemove",this.a.mouseCollector,u),window.addEventListener("keypress",
|
||||
this.a.keyboardCollector,u),window.addEventListener("devicemotion",this.a.accelerometerCollector,u)):document.attachEvent?(document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector)):q(new sjcl.exception.bug("can't attach event")),this.q=!0)},stopCollectors:function(){this.q&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,u),window.removeEventListener("mousemove",
|
||||
this.a.mouseCollector,u),window.removeEventListener("keypress",this.a.keyboardCollector,u),window.removeEventListener("devicemotion",this.a.accelerometerCollector,u)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.q=u)},addEventListener:function(a,b){this.w[a][this.V++]=b},removeEventListener:function(a,b){var c,d,e=this.w[a],f=[];for(d in e)e.hasOwnProperty(d)&&
|
||||
e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},$:function(){E(1)},ba:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&sjcl.random.addEntropy([b,c],2,"mouse");E(0)},aa:function(){E(2)},U:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&sjcl.random.addEntropy(b,1,"accelerometer")}a&&sjcl.random.addEntropy(a,
|
||||
2,"accelerometer");E(0)}};function C(a,b){var c,d=sjcl.random.w[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function E(a){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?sjcl.random.addEntropy(window.performance.now(),a,"loadtime"):sjcl.random.addEntropy((new Date).valueOf(),a,"loadtime")}function A(a){a.b=B(a).concat(B(a));a.A=new sjcl.cipher.aes(a.b)}
|
||||
function B(a){for(var b=0;4>b&&!(a.f[b]=a.f[b]+1|0,a.f[b]);b++);return a.A.encrypt(a.f)}function D(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
|
||||
a:try{var F,G,H,I;if(I="undefined"!==typeof module){var J;if(J=module.exports){var K;try{K=require("crypto")}catch(L){K=null}J=(G=K)&&G.randomBytes}I=J}if(I)F=G.randomBytes(128),F=new Uint32Array((new Uint8Array(F)).buffer),sjcl.random.addEntropy(F,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){H=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(H);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(H);
|
||||
else break a;sjcl.random.addEntropy(H,1024,"crypto['getRandomValues']")}}catch(M){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(M))}
|
||||
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},Y:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.e({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.e(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||4<
|
||||
f.iv.length)&&q(new sjcl.exception.invalid("json encrypt: invalid parameters"));"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.e(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,
|
||||
b,c,d){var e=sjcl.json,f=e.Y.apply(e,arguments);return e.encode(f)},X:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.e(e.e(e.e({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)&&q(new sjcl.exception.invalid("json decrypt: invalid parameters"));
|
||||
"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f=sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.e(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.X(a,e.decode(b),c,d)},encode:function(a){var b,
|
||||
c="{",d="";for(b in a)if(a.hasOwnProperty(b))switch(b.match(/^[a-z0-9]+$/i)||q(new sjcl.exception.invalid("json encode: invalid property name")),c+=d+'"'+b+'":',d=",",typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:q(new sjcl.exception.bug("json encode: unsupported type"))}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");a.match(/^\{.*\}$/)||q(new sjcl.exception.invalid("json decode: this isn't json!"));
|
||||
a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++)(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))||q(new sjcl.exception.invalid("json decode: this isn't json!")),b[d[2]]=d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]);return b},e:function(a,b,c){a===t&&(a={});if(b===t)return a;for(var d in b)b.hasOwnProperty(d)&&(c&&(a[d]!==t&&a[d]!==b[d])&&q(new sjcl.exception.invalid("required parameter overridden")),
|
||||
a[d]=b[d]);return a},ea:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},da:function(a,b){var c={},d;for(d=0;d<b.length;d++)a[b[d]]!==t&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.ca={};
|
||||
sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.ca,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===t?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
|
||||
|
||||
115
src/js/sjcl/test/bitArray_test.js
Normal file
115
src/js/sjcl/test/bitArray_test.js
Normal file
@@ -0,0 +1,115 @@
|
||||
(function() {
|
||||
|
||||
function word2hex(w) {
|
||||
return "0x" + ((w|0)+0xF00000000000).toString(16).substr(4);
|
||||
}
|
||||
|
||||
var b0 = sjcl.bitArray.partial(1, 0);
|
||||
var b1 = sjcl.bitArray.partial(1, 1);
|
||||
|
||||
function concatbits(s) {
|
||||
var j, b, a = [];
|
||||
for (j = 0; j < s.length; ++j) {
|
||||
b = (s[j] == '1' ? b1 : b0);
|
||||
a = sjcl.bitArray.concat(a, [b]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
new sjcl.test.TestCase("bitArray single bits", function (cb) {
|
||||
if (!sjcl.bitArray) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
this.require((b0|0) === (0x00000000|0), "bitstring '0': " + word2hex(b0));
|
||||
this.require((b1|0) === (0x80000000|0), "bitstring '1': " + word2hex(b1));
|
||||
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
new sjcl.test.TestCase("bitArray concat small bitstrings", function (cb) {
|
||||
if (!sjcl.bitArray) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
var i, kat = sjcl.test.vector.bitArray.bits, tv, a, b, bitlen, t;
|
||||
for (i=0; i<kat.length; i++) {
|
||||
tv = kat[i];
|
||||
a = concatbits(tv[0]);
|
||||
bitlen = sjcl.bitArray.bitLength(a);
|
||||
t = "bitstring '" + tv[0] + "': ";
|
||||
this.require(1 === a.length, t + "array length is 1: " + a.length);
|
||||
this.require(bitlen === tv[0].length, t + "length " + bitlen + " matches input length " + tv[0].length);
|
||||
b = sjcl.bitArray.partial(tv[0].length, tv[1]);
|
||||
this.require(a[0] === b, t + "array matches shifted number: " + word2hex(a[0]) + " == " + word2hex(b));
|
||||
b = 0 | (a[0] >>> (32 - tv[0].length)); // unsigned shift, convert to signed word
|
||||
this.require(b === (tv[1]|0), t + "array entry shifted is number: " + word2hex(b) + " == " + word2hex(tv[1]));
|
||||
}
|
||||
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
|
||||
new sjcl.test.TestCase("bitArray concat, slicing, shifting and clamping", function (cb) {
|
||||
if (!sjcl.bitArray) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
var i, j, kat = sjcl.test.vector.bitArray.slices, tv, a, a1, b, bitlen, t;
|
||||
for (i=0; i<kat.length; i++) {
|
||||
tv = kat[i];
|
||||
a = [];
|
||||
b = [];
|
||||
|
||||
bitlen = 0;
|
||||
for (j=0; j<tv[0].length; j++) {
|
||||
b[j] = concatbits(tv[0][j]);
|
||||
a = sjcl.bitArray.concat(a, b[j]);
|
||||
bitlen += tv[0][j].length;
|
||||
}
|
||||
|
||||
// shift last array entry and set partial length on it
|
||||
a1 = tv[1]; a1 = a1.slice(0, a1.length);
|
||||
bitlen &= 31;
|
||||
if (0 !== bitlen) a1[a1.length-1] = sjcl.bitArray.partial(bitlen, a1[a1.length-1]);
|
||||
|
||||
this.require(sjcl.bitArray.equal(a, a1), "concat: [" + a + "] == [" + a1 + "]");
|
||||
|
||||
t = 0;
|
||||
for (j=0; j<tv[0].length; j++) {
|
||||
bitlen = sjcl.bitArray.bitLength(b[j]);
|
||||
this.require(bitlen === tv[0][j].length, "bitstring length");
|
||||
a1 = sjcl.bitArray.bitSlice(a, t, t + bitlen);
|
||||
this.require(sjcl.bitArray.equal(b[j], a1), "slice after concat: [" + b[j] + "] == [" + a1 + "]");
|
||||
t += bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
new sjcl.test.TestCase("bitArray byteswap", function (cb) {
|
||||
if (!sjcl.bitArray) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
var i, kat = sjcl.test.vector.bitArray.byteswap, tv, a;
|
||||
for (i=0; i<kat.length; i++) {
|
||||
tv = kat[i];
|
||||
|
||||
a = tv[1];
|
||||
this.require(sjcl.bitArray.equal(tv[0], sjcl.bitArray.byteswapM(a.slice(0, a.length))));
|
||||
}
|
||||
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
})();
|
||||
163
src/js/sjcl/test/bitArray_vectors.js
Normal file
163
src/js/sjcl/test/bitArray_vectors.js
Normal file
@@ -0,0 +1,163 @@
|
||||
sjcl.test.vector.bitArray = {};
|
||||
|
||||
// random test cases generated with ruby String#to_i(radix) and Fixnum#to_s(radix)
|
||||
|
||||
// bitstrings (<= 32 bits) encoding a number
|
||||
sjcl.test.vector.bitArray.bits = [
|
||||
[ "00" , 0|0x0 ],
|
||||
[ "01" , 0|0x1 ],
|
||||
[ "10" , 0|0x2 ],
|
||||
[ "11" , 0|0x3 ],
|
||||
[ "000" , 0|0x0 ],
|
||||
[ "011" , 0|0x3 ],
|
||||
[ "101" , 0|0x5 ],
|
||||
[ "110" , 0|0x6 ],
|
||||
[ "0100" , 0|0x4 ],
|
||||
[ "0101" , 0|0x5 ],
|
||||
[ "1000" , 0|0x8 ],
|
||||
[ "1100" , 0|0xc ],
|
||||
[ "00101" , 0|0x5 ],
|
||||
[ "01010" , 0|0xa ],
|
||||
[ "10011" , 0|0x13 ],
|
||||
[ "11010" , 0|0x1a ],
|
||||
[ "001100" , 0|0xc ],
|
||||
[ "001110" , 0|0xe ],
|
||||
[ "010100" , 0|0x14 ],
|
||||
[ "100111" , 0|0x27 ],
|
||||
[ "0001011" , 0|0xb ],
|
||||
[ "0001101" , 0|0xd ],
|
||||
[ "1000100" , 0|0x44 ],
|
||||
[ "1101011" , 0|0x6b ],
|
||||
[ "00100001" , 0|0x21 ],
|
||||
[ "00100111" , 0|0x27 ],
|
||||
[ "00101000" , 0|0x28 ],
|
||||
[ "10101111" , 0|0xaf ],
|
||||
[ "000100000" , 0|0x20 ],
|
||||
[ "100100011" , 0|0x123 ],
|
||||
[ "100111001" , 0|0x139 ],
|
||||
[ "111010011" , 0|0x1d3 ],
|
||||
[ "0001001011" , 0|0x4b ],
|
||||
[ "0001100110" , 0|0x66 ],
|
||||
[ "0010110111" , 0|0xb7 ],
|
||||
[ "1011101111" , 0|0x2ef ],
|
||||
[ "01000010110" , 0|0x216 ],
|
||||
[ "01001101000" , 0|0x268 ],
|
||||
[ "10111101001" , 0|0x5e9 ],
|
||||
[ "11111100000" , 0|0x7e0 ],
|
||||
[ "000101010001" , 0|0x151 ],
|
||||
[ "010101111111" , 0|0x57f ],
|
||||
[ "101010001110" , 0|0xa8e ],
|
||||
[ "110101100010" , 0|0xd62 ],
|
||||
[ "0010001111010" , 0|0x47a ],
|
||||
[ "1000000001100" , 0|0x100c ],
|
||||
[ "1100011000000" , 0|0x18c0 ],
|
||||
[ "1110011000011" , 0|0x1cc3 ],
|
||||
[ "00111101111110" , 0|0xf7e ],
|
||||
[ "01101011001001" , 0|0x1ac9 ],
|
||||
[ "10111000111101" , 0|0x2e3d ],
|
||||
[ "11101010011110" , 0|0x3a9e ],
|
||||
[ "010111101010110" , 0|0x2f56 ],
|
||||
[ "100011010110000" , 0|0x46b0 ],
|
||||
[ "110001001100100" , 0|0x6264 ],
|
||||
[ "111011000100110" , 0|0x7626 ],
|
||||
[ "0100101111001100" , 0|0x4bcc ],
|
||||
[ "1000000001101100" , 0|0x806c ],
|
||||
[ "1001000100110110" , 0|0x9136 ],
|
||||
[ "1101010000100011" , 0|0xd423 ],
|
||||
[ "01001001001101110" , 0|0x926e ],
|
||||
[ "01111001111000010" , 0|0xf3c2 ],
|
||||
[ "10011011011000011" , 0|0x136c3 ],
|
||||
[ "10101011001110000" , 0|0x15670 ],
|
||||
[ "010000000101000110" , 0|0x10146 ],
|
||||
[ "011000100101110001" , 0|0x18971 ],
|
||||
[ "101100100110110111" , 0|0x2c9b7 ],
|
||||
[ "101110100100101111" , 0|0x2e92f ],
|
||||
[ "0010101100101000000" , 0|0x15940 ],
|
||||
[ "1011010010000101010" , 0|0x5a42a ],
|
||||
[ "1011100111011011000" , 0|0x5ced8 ],
|
||||
[ "1111011110011111110" , 0|0x7bcfe ],
|
||||
[ "00101000011011111111" , 0|0x286ff ],
|
||||
[ "01111001100011000100" , 0|0x798c4 ],
|
||||
[ "11111001001110101011" , 0|0xf93ab ],
|
||||
[ "11111001111001101001" , 0|0xf9e69 ],
|
||||
[ "000110100000110010101" , 0|0x34195 ],
|
||||
[ "011110000101101101111" , 0|0xf0b6f ],
|
||||
[ "101111010011001100110" , 0|0x17a666 ],
|
||||
[ "111101001011110010001" , 0|0x1e9791 ],
|
||||
[ "1001111100011011100001" , 0|0x27c6e1 ],
|
||||
[ "1011110101000101010110" , 0|0x2f5156 ],
|
||||
[ "1100000100011110001011" , 0|0x30478b ],
|
||||
[ "1100001010010110111111" , 0|0x30a5bf ],
|
||||
[ "01001111001101000111101" , 0|0x279a3d ],
|
||||
[ "10110011101111110000001" , 0|0x59df81 ],
|
||||
[ "11000001101100110100011" , 0|0x60d9a3 ],
|
||||
[ "11011000010110110010110" , 0|0x6c2d96 ],
|
||||
[ "010011110100100110010100" , 0|0x4f4994 ],
|
||||
[ "011101110001100111111110" , 0|0x7719fe ],
|
||||
[ "011110001010011011100011" , 0|0x78a6e3 ],
|
||||
[ "111100010001011101111110" , 0|0xf1177e ],
|
||||
[ "0010110000010110001000010" , 0|0x582c42 ],
|
||||
[ "0100100011001001101110000" , 0|0x919370 ],
|
||||
[ "1000111001010110111010110" , 0|0x11cadd6 ],
|
||||
[ "1111001100101000010010101" , 0|0x1e65095 ],
|
||||
[ "00110010011100010101111111" , 0|0xc9c57f ],
|
||||
[ "00111101011011010100111110" , 0|0xf5b53e ],
|
||||
[ "01100000111011111010011100" , 0|0x183be9c ],
|
||||
[ "11010001100110101111010111" , 0|0x3466bd7 ],
|
||||
[ "010000001111100110000110011" , 0|0x207cc33 ],
|
||||
[ "011010010000110000101011111" , 0|0x348615f ],
|
||||
[ "011010110001110110001110010" , 0|0x358ec72 ],
|
||||
[ "110110100001001001001110000" , 0|0x6d09270 ],
|
||||
[ "0101000000000001000011100101" , 0|0x50010e5 ],
|
||||
[ "0110011001001100011111111100" , 0|0x664c7fc ],
|
||||
[ "1001011010000001100110111101" , 0|0x96819bd ],
|
||||
[ "1011011101000000111000000010" , 0|0xb740e02 ],
|
||||
[ "00100111111011011111010101101" , 0|0x4fdbead ],
|
||||
[ "00110000011001110110101110010" , 0|0x60ced72 ],
|
||||
[ "10111110111000010010010111101" , 0|0x17dc24bd ],
|
||||
[ "11010001000001110010101000010" , 0|0x1a20e542 ],
|
||||
[ "001001010001010111111101010111" , 0|0x9457f57 ],
|
||||
[ "100110011101100000110111111010" , 0|0x26760dfa ],
|
||||
[ "100111000100011001010011111011" , 0|0x271194fb ],
|
||||
[ "111011110110101110110111010101" , 0|0x3bdaedd5 ],
|
||||
[ "0111100111010100101010000111100" , 0|0x3cea543c ],
|
||||
[ "1000010011010100111001110000100" , 0|0x426a7384 ],
|
||||
[ "1001110000000100001011010001010" , 0|0x4e02168a ],
|
||||
[ "1101000000000110110010011010100" , 0|0x680364d4 ],
|
||||
[ "00000011100100001011101011100111", 0|0x390bae7 ],
|
||||
[ "10011110110111111000010010010011", 0|0x9edf8493 ],
|
||||
[ "11000101100000110001011010111100", 0|0xc58316bc ],
|
||||
[ "11111010101110011001010001011000", 0|0xfab99458 ]
|
||||
];
|
||||
|
||||
// concat some bitstrings into an array (the last array entry here is not "high" shifted yet)
|
||||
sjcl.test.vector.bitArray.slices = [
|
||||
// lengths: 17, 16, 15, 14, 13
|
||||
[ ["00100010111010110", "0010000111100001", "101111111100010", "10111011110000", "1100100100001" ], [0|0x22eb10f0, 0|0xdfe2bbc3, 0|0x121] ],
|
||||
[ ["00001010100110010", "0000100011110001", "111110101100100", "10110111000101", "0000100111011" ], [0|0x0a990478, 0|0xfd64b714, 0|0x13b] ],
|
||||
[ ["10110101101100001", "0000110110010100", "110100011010100", "01011010010111", "0101101011011" ], [0|0xb5b086ca, 0|0x68d45a5d, 0|0x35b] ],
|
||||
[ ["01010010001010110", "1110010000100111", "001010110101110", "10110111101000", "0100000010100" ], [0|0x522b7213, 0|0x95aeb7a1, 0|0x014] ],
|
||||
[ ["10011001001100110", "0100100011100010", "000110011001001", "00101101101000", "0001111101100" ], [0|0x99332471, 0|0x0cc92da0, 0|0x3ec] ],
|
||||
[ ["01111100000110000", "1000101001000010", "110101001111111", "01001010110110", "0111100000001" ], [0|0x7c184521, 0|0x6a7f4ad9, 0|0x701] ],
|
||||
[ ["00110011010100110", "0100101101110000", "110101110100100", "00111010010110", "0110011011100" ], [0|0x335325b8, 0|0x6ba43a59, 0|0x4dc] ],
|
||||
[ ["11111110011100100", "1111101001010011", "001000100110010", "01101101100001", "0001011101011" ], [0|0xfe727d29, 0|0x91326d84, 0|0x2eb] ],
|
||||
[ ["00100011001001000", "1001010100000100", "010111001100111", "11011111000000", "0100111101110" ], [0|0x23244a82, 0|0x2e67df01, 0|0x1ee] ],
|
||||
[ ["10111111100000010", "0111110011010001", "001000101001110", "11101010011001", "0101111101110" ], [0|0xbf813e68, 0|0x914eea65, 0|0x3ee] ],
|
||||
// lengths: 17, 15, 32, 10, 20
|
||||
[ ["00001111000110001", "110100011111001", "10010110001110010011011000011111", "1001101101", "01110010001111001110" ], [0|0x0f18e8f9, 0|0x9639361f, 0|0x26d723ce] ],
|
||||
[ ["11011111010101100", "101010100101100", "11101101011001011011010111101011", "0010110010", "11110011110110000010" ], [0|0xdf56552c, 0|0xed65b5eb, 0|0x0b2f3d82] ],
|
||||
[ ["10100100001000101", "100111001100011", "00111100101000110010000011101001", "1001110001", "11000000001111111110" ], [0|0xa422ce63, 0|0x3ca320e9, 0|0x271c03fe] ],
|
||||
[ ["01110001111111010", "000101001101110", "00001100011010100100001011111001", "1011111010", "00011001110111111001" ], [0|0x71fd0a6e, 0|0x0c6a42f9, 0|0x2fa19df9] ],
|
||||
[ ["01001100010011001", "000111011000100", "10100000110101110110011110001100", "0011000001", "11001101010101011100" ], [0|0x4c4c8ec4, 0|0xa0d7678c, 0|0x0c1cd55c] ],
|
||||
[ ["01010010100110110", "110111110001000", "10011100001100010100000110000000", "1100111101", "00010001110100111101" ], [0|0x529b6f88, 0|0x9c314180, 0|0x33d11d3d] ],
|
||||
[ ["11010100011101101", "110101011011010", "01000110000011001111101110100001", "0001001110", "01001100010010001010" ], [0|0xd476eada, 0|0x460cfba1, 0|0x04e4c48a] ],
|
||||
[ ["11000001010001101", "001111011110111", "10000010100111010111011000100001", "0011000011", "11011110110000101000" ], [0|0xc1469ef7, 0|0x829d7621, 0|0x0c3dec28] ],
|
||||
[ ["11000101100010100", "000110111111110", "11111011110010001100001100010000", "0000101010", "10000011010011100011" ], [0|0xc58a0dfe, 0|0xfbc8c310, 0|0x02a834e3] ],
|
||||
[ ["11111111110100101", "110101000011001", "10101010010100111010100010110100", "0010011000", "10100110001000000010" ], [0|0xffd2ea19, 0|0xaa53a8b4, 0|0x098a6202] ]
|
||||
];
|
||||
|
||||
sjcl.test.vector.bitArray.byteswap = [
|
||||
[ [ 0xdab1a44e, 0x73fdc3de, 0xed6e6f00, 0x5d221b85, 0xadb987a4, 0xc20eda76, 0xa0d40d0c, 0xd1da9657, 0xd85eebf0, 0xd3f9c06d, 0xca1e39b0, 0xccd7eaeb, 0xb1dd6bd0, 0x7315a9e6, 0x77cfcac4, 0xf7914c19, 0x1bc15354, 0x935afabc, 0x3ee9d375, 0xd18a095f]
|
||||
, [ 0x4ea4b1da, 0xdec3fd73, 0x006f6eed, 0x851b225d, 0xa487b9ad, 0x76da0ec2, 0x0c0dd4a0, 0x5796dad1, 0xf0eb5ed8, 0x6dc0f9d3, 0xb0391eca, 0xebead7cc, 0xd06bddb1, 0xe6a91573, 0xc4cacf77, 0x194c91f7, 0x5453c11b, 0xbcfa5a93, 0x75d3e93e, 0x5f098ad1]
|
||||
]
|
||||
];
|
||||
@@ -7,7 +7,7 @@ new sjcl.test.TestCase("ECC convenience test", function (cb) {
|
||||
|
||||
try {
|
||||
var keys = sjcl.ecc.elGamal.generateKeys(192,0);
|
||||
|
||||
|
||||
var ciphertext = sjcl.encrypt(keys.pub, "hello world");
|
||||
var plaintext = sjcl.decrypt(keys.sec, ciphertext);
|
||||
|
||||
|
||||
@@ -5,11 +5,23 @@ new sjcl.test.TestCase("HMAC official test vectors", function (cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
var i, kat = sjcl.test.vector.hmac, tv, h=sjcl.codec.hex, out;
|
||||
var i, kat = sjcl.test.vector.hmac, tv, h=sjcl.codec.hex, out, data, mac;
|
||||
for (i=0; i<kat.length; i++) {
|
||||
tv = kat[i];
|
||||
out = h.fromBits((new sjcl.misc.hmac(h.toBits(tv.key))).mac(h.toBits(tv.data)));
|
||||
data = h.toBits(tv.data);
|
||||
mac = new sjcl.misc.hmac(h.toBits(tv.key));
|
||||
|
||||
out = h.fromBits(mac.mac(data));
|
||||
this.require (out.substr(0,tv.mac.length) == tv.mac, "hmac #"+i);
|
||||
|
||||
out = h.fromBits(mac.mac(data));
|
||||
this.require (out.substr(0,tv.mac.length) == tv.mac, "hmac reset #"+i);
|
||||
|
||||
mac.update(sjcl.bitArray.bitSlice(data, 0, sjcl.bitArray.bitLength(data)/2));
|
||||
mac.update(sjcl.bitArray.bitSlice(data, sjcl.bitArray.bitLength(data)/2));
|
||||
|
||||
out = h.fromBits(mac.digest());
|
||||
this.require (out.substr(0,tv.mac.length) == tv.mac, "hmac reset #"+i);
|
||||
}
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Official HMAC test vectors. */
|
||||
//Nilos: http://tools.ietf.org/html/draft-nystrom-smime-hmac-sha-02 for
|
||||
sjcl.test.vector.hmac = [
|
||||
{ key: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||
data: "4869205468657265",
|
||||
|
||||
126
src/js/sjcl/test/json_test.js
Normal file
126
src/js/sjcl/test/json_test.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Asserts that an object can be encoded to an expected string.
|
||||
*/
|
||||
new sjcl.test.TestCase("JSON Encode Test", function (cb) {
|
||||
if(!sjcl.json) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
//Build up a standard object for encoding, this includes a nice wide variety of properties.
|
||||
var obj = new Object();
|
||||
obj.int = 4;
|
||||
obj.nint = -5;
|
||||
obj.str = 'string';
|
||||
obj.iv = [ -95577995, -949876189, 1443400017, 697058741 ];
|
||||
obj.truth = true;
|
||||
obj.lie = false;
|
||||
|
||||
try {
|
||||
var str = sjcl.json.encode(obj);
|
||||
this.require(!(!str)); //Check for non-'falsey'
|
||||
}
|
||||
catch (e) {
|
||||
//The standard object should encode just fine, so this is out of place. Fail.
|
||||
this.fail(e);
|
||||
}
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Asserts that a JSON string can be decoded to an expected object.
|
||||
*/
|
||||
new sjcl.test.TestCase("JSON Decode Test", function (cb) {
|
||||
if(!sjcl.json) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
var str = ''; var i;
|
||||
str = '{"int":4,"nint":-5,"str":"string","iv":"/////wAAAAAAAAABAAAAAg==","truth":true,"lie":false}';
|
||||
|
||||
try {
|
||||
var obj = sjcl.json.decode(str);
|
||||
this.require(obj.int === 4);
|
||||
this.require(obj.nint === -5);
|
||||
this.require(obj.str === 'string');
|
||||
this.require(obj.truth === true);
|
||||
this.require(obj.lie === false);
|
||||
for(i in obj.iv) {
|
||||
this.require(obj.iv[i] == (i-1)); //Array in iv is [-1,0,1,2]
|
||||
}
|
||||
} catch (e) { this.fail(e); }
|
||||
|
||||
str = '{ "int" : 4, "nint" : -5,"str":"string", "iv": "/////wAAAAAAAAABAAAAAg==","truth": true,"lie": false }';
|
||||
try {
|
||||
var obj = sjcl.json.decode(str);
|
||||
this.require(obj.int === 4);
|
||||
this.require(obj.nint === -5);
|
||||
this.require(obj.str === 'string');
|
||||
this.require(obj.truth === true);
|
||||
this.require(obj.lie === false);
|
||||
for(i in obj.iv) {
|
||||
this.require(obj.iv[i] == (i-1)); //Array in iv is [-1,0,1,2]
|
||||
}
|
||||
} catch (e) { this.fail(e); }
|
||||
|
||||
//Tests passed, return.
|
||||
cb && cb();
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Asserts that an Object can be Encoded to a string that can be decoded to an equivalent object
|
||||
* as well as the converse.
|
||||
*/
|
||||
new sjcl.test.TestCase("JSON Commutative Test", function (cb) {
|
||||
if(!sjcl.json) {
|
||||
this.unimplemented();
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
|
||||
var obj1 = new Object();
|
||||
obj1.int = 4;
|
||||
obj1.nint = -5;
|
||||
obj1.str = 'string';
|
||||
obj1.iv = [ -95577995, -949876189, 1443400017, 697058741 ];
|
||||
obj1.truth = true;
|
||||
obj1.lie = false;
|
||||
|
||||
var str1 = '';
|
||||
var str2 = '';
|
||||
var obj2;
|
||||
try {
|
||||
str1 = sjcl.json.encode(obj1);
|
||||
obj2 = sjcl.json.decode(str1);
|
||||
str2 = sjcl.json.encode(obj2);
|
||||
}
|
||||
catch (e) {
|
||||
this.fail(e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.require(str1 === str2);
|
||||
this.require(obj1.int == obj2.int);
|
||||
this.require(obj1.str == obj2.str);
|
||||
this.require(obj1.lie == obj2.lie);
|
||||
this.require(obj1.nint == obj2.nint);
|
||||
this.require(obj1.truth == obj2.truth);
|
||||
|
||||
var i;
|
||||
for(i in obj1.iv)
|
||||
{
|
||||
this.require(obj1.iv[i] == obj2.iv[i]);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.fail(e);
|
||||
}
|
||||
|
||||
//Tests passed.
|
||||
cb && cb();
|
||||
});
|
||||
16
src/js/sjcl/test/run_tests_node.js
Normal file
16
src/js/sjcl/test/run_tests_node.js
Normal file
@@ -0,0 +1,16 @@
|
||||
var fs = require('fs');
|
||||
var vm = require('vm');
|
||||
|
||||
var load = function(path) {
|
||||
vm.runInThisContext(fs.readFileSync(path));
|
||||
};
|
||||
|
||||
// Assume we're run using `make test`.
|
||||
// That means argv[0] is `node` and argv[1] is this file.
|
||||
process.argv.slice(2).map(load);
|
||||
|
||||
sjcl.test.run(undefined, function(){
|
||||
if(!browserUtil.allPassed) {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var Account = require('../src/js/ripple/account').Account;
|
||||
var Account = require('ripple-lib').Account;
|
||||
|
||||
describe('Account', function(){
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var BigInteger = require('../src/js/jsbn/jsbn').BigInteger;
|
||||
var Amount = utils.load_module('amount').Amount;
|
||||
var UInt160 = utils.load_module('uint160').UInt160;
|
||||
var config = utils.get_config();
|
||||
var assert = require('assert');
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var UInt160 = require('ripple-lib').UInt160;
|
||||
var load_config = require('ripple-lib').config.load;
|
||||
var config = require('./config-example');
|
||||
|
||||
load_config(config);
|
||||
|
||||
|
||||
describe('Amount', function() {
|
||||
describe('Negatives', function() {
|
||||
@@ -87,7 +89,7 @@ describe('Amount', function() {
|
||||
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.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');
|
||||
@@ -101,14 +103,38 @@ describe('Amount', function() {
|
||||
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');
|
||||
});
|
||||
it('to human rounding edge case, precision 2, 1', function() {
|
||||
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');
|
||||
});
|
||||
it('to human rounding edge case, precision 2, 3', function() {
|
||||
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');
|
||||
});
|
||||
it('to human rounding edge case, precision 3, 2', function() {
|
||||
assert.strictEqual(Amount.from_human("0.999 XAU").to_human({precision:2}), '1.00');
|
||||
});
|
||||
});
|
||||
describe('from_human', function() {
|
||||
it('empty string', function() {
|
||||
assert.strictEqual(Amount.from_human('').to_text_full(), 'NaN');
|
||||
});
|
||||
it('missing value', 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');
|
||||
});
|
||||
it('1 XRP human', function() {
|
||||
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');
|
||||
});
|
||||
@@ -263,14 +289,11 @@ describe('Amount', function() {
|
||||
});
|
||||
});
|
||||
describe('UInt160', function() {
|
||||
it('Parse 0', function () {
|
||||
assert.deepEqual(new BigInteger(), UInt160.from_generic('0')._value);
|
||||
});
|
||||
it('Parse 0 export', function () {
|
||||
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json());
|
||||
});
|
||||
it('Parse 1', function () {
|
||||
assert.deepEqual(new BigInteger([1]), UInt160.from_generic('1')._value);
|
||||
assert.deepEqual(UInt160.ACCOUNT_ONE, UInt160.from_generic('1').set_version(0).to_json());
|
||||
});
|
||||
it('Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export', function () {
|
||||
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json());
|
||||
@@ -313,9 +336,9 @@ describe('Amount', function() {
|
||||
});
|
||||
describe('Amount parsing', function() {
|
||||
it('Parse invalid string', function() {
|
||||
assert.strictEqual(Amount.from_json('x').to_text(), '0');
|
||||
assert.strictEqual(typeof Amount.from_json('x').to_text(true), 'number');
|
||||
assert(isNaN(Amount.from_json('x').to_text(true)));
|
||||
assert.strictEqual(Amount.from_json('x').to_text(), 'NaN');
|
||||
assert.strictEqual(typeof Amount.from_json('x').to_text(), 'string');
|
||||
assert(isNaN(Amount.from_json('x').to_text()));
|
||||
});
|
||||
it('parse dem', function() {
|
||||
assert.strictEqual(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
@@ -339,22 +362,26 @@ describe('Amount', 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());
|
||||
@@ -383,23 +410,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());
|
||||
@@ -767,7 +788,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));
|
||||
});
|
||||
@@ -796,8 +817,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));
|
||||
});
|
||||
@@ -955,7 +976,7 @@ describe('Amount', function() {
|
||||
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_text_full(), '0.0001/XRP');
|
||||
});
|
||||
it('Multiply USD with XAU (dem)', function () {
|
||||
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_text_full(), '19900.00316303882/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_text_full(), '19900.00316303883/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
it('Multiply 0 XRP with 0 XRP human', function () {
|
||||
assert.strictEqual('0/XRP', Amount.from_json('0').product_human(Amount.from_json('0')).to_human_full());
|
||||
@@ -1027,7 +1048,7 @@ describe('Amount', function() {
|
||||
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_human_full(), '0.0001/XRP');
|
||||
});
|
||||
it('Multiply USD with XAU (dem) human', function () {
|
||||
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_human_full(), '19,900.00316303882/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_human_full(), '19,900.00316303883/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1062,6 +1083,11 @@ 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()
|
||||
});
|
||||
});
|
||||
it('BTC/XRP', function () {
|
||||
assert.strictEqual(Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'BTC'}).to_text_full(), '44,970/XRP');
|
||||
});
|
||||
@@ -1165,11 +1191,11 @@ describe('Amount', function() {
|
||||
|
||||
describe('amount limits', function() {
|
||||
it ('max JSON wire limite', function() {
|
||||
assert.strictEqual(Amount.bi_xns_max.toString(), '9000000000000000000');
|
||||
assert.strictEqual(Amount.bi_xns_max.toString(), '100000000000000000');
|
||||
});
|
||||
|
||||
it ('max JSON wire limite', function() {
|
||||
assert.strictEqual(Amount.bi_xns_min.toString(), '-9000000000000000000');
|
||||
assert.strictEqual(Amount.bi_xns_min.toString(), '-100000000000000000');
|
||||
});
|
||||
|
||||
it('max mantissa value', function() {
|
||||
@@ -1181,29 +1207,29 @@ describe('Amount', function() {
|
||||
});
|
||||
|
||||
it ('from_json minimum XRP', function() {
|
||||
console.log('max', Amount.bi_xns_max.toString());
|
||||
var amt = Amount.from_json('-9000000000000000000');
|
||||
assert.strictEqual(amt.to_json(), '-9000000000000000000');
|
||||
var amt = Amount.from_json('-100000000000000000');
|
||||
assert.strictEqual(amt.to_json(), '-100000000000000000');
|
||||
});
|
||||
|
||||
it ('from_json maximum XRP', function() {
|
||||
var amt = Amount.from_json('-9000000000000000000');
|
||||
assert.strictEqual(amt.to_json(), '-9000000000000000000');
|
||||
var amt = Amount.from_json('100000000000000000');
|
||||
assert.strictEqual(amt.to_json(), '100000000000000000');
|
||||
});
|
||||
|
||||
it ('from_json less than minimum XRP', function() {
|
||||
var amt = Amount.from_json('-9000000000000000001');
|
||||
assert.strictEqual(amt.to_json(), '0');
|
||||
assert.throws(function() {
|
||||
Amount.from_json('-100000000000000001');
|
||||
});
|
||||
});
|
||||
|
||||
it ('from_json more than maximum XRP', function() {
|
||||
var amt = Amount.from_json('9000000000000000001');
|
||||
assert.strictEqual(amt.to_json(), '0');
|
||||
assert.throws(function() {
|
||||
Amount.from_json('100000000000000001');
|
||||
});
|
||||
});
|
||||
|
||||
it ('from_json minimum IOU', function() {
|
||||
var amt = Amount.from_json('-1e-81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
|
||||
assert.strictEqual(amt.to_text(), '-1000000000000000e-96');
|
||||
assert.strictEqual(amt.to_text(), Amount.min_value);
|
||||
});
|
||||
@@ -1216,7 +1242,6 @@ describe('Amount', function() {
|
||||
|
||||
it ('from_json maximum IOU', function() {
|
||||
var amt = Amount.from_json('9999999999999999e80/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
|
||||
assert.strictEqual(amt.to_text(), '9999999999999999e80');
|
||||
});
|
||||
|
||||
@@ -1228,13 +1253,11 @@ describe('Amount', function() {
|
||||
|
||||
it ('from_json normalize mantissa to valid max range, lost significant digits', function() {
|
||||
var amt = Amount.from_json('99999999999999999999999999999999/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
|
||||
assert.strictEqual(amt.to_text(), '9999999999999999e16');
|
||||
});
|
||||
|
||||
it ('from_json normalize mantissa to min valid range, lost significant digits', function() {
|
||||
var amt = Amount.from_json('-0.0000000000000000000000001/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
|
||||
assert.strictEqual(amt.to_text(), '-1000000000000000e-40');
|
||||
});
|
||||
});
|
||||
|
||||
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,19 +0,0 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Seed = utils.load_module('seed').Seed;
|
||||
var config = require('./testutils').get_config();
|
||||
|
||||
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,7 +1,8 @@
|
||||
/*eslint-disable */
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var currency = utils.load_module('currency').Currency;
|
||||
var timeUtil = utils.load_module('utils').time;
|
||||
var currency = require('ripple-lib').Currency;
|
||||
var timeUtil = require('ripple-lib').utils.time;
|
||||
|
||||
describe('Currency', function() {
|
||||
describe('json_rewrite', function() {
|
||||
@@ -55,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"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
797
test/fixtures/binary-account-transaction.json
vendored
Normal file
797
test/fixtures/binary-account-transaction.json
vendored
Normal file
@@ -0,0 +1,797 @@
|
||||
{
|
||||
"OfferCreate": {
|
||||
"binary": {
|
||||
"ledger_index": 10983428,
|
||||
"meta": "201C00000000F8E311006F561C0662854F6571DD28392C1AF031757BDF2BC0E62C190ABE0BC22C46A2E443FDE824000263F550107B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE0064400000032A0D8DB065D4838D7EA4C6800000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D1811473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1E51100645642EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DFE722000000005842EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DF821473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1E4110064567B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400E72200000000365F04CE166242F400587B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F40001110000000000000000000000000000000000000000021100000000000000000000000000000000000000000311000000000000000000000000425443000000000004110A20B3C85F482532A9578DBB3950B85CA06594D1E1E1E3110064567B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00E8365F04D40AEE52AE00587B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE000311000000000000000000000000425443000000000004110A20B3C85F482532A9578DBB3950B85CA06594D1E1E1E411006F56CDD61BD2DF2ADF53D0C05C171E2C8D48337BFE63868497BC30C5DCF2D0A03AFFE7220000000024000263E72500A79550330000000000000000340000000000000000550F60460F66E991AE6D77C50435E7FF8915453D411B6E43B38AC6410113B06CDC50107B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400644000000326266D2065D4838D7EA4C6800000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D1811473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1E51100612500A7974E55329262FE69DD4F191AF0CE075489E7B7BDD273EC5528531D8184E1A73E76B7D356E0A052DA53A0D6F6C16422D206D4E38862ED7A13AE90ED0EF5ED09353C2A7A94E624000263F56240000005F01B0F39E1E7220000000024000263F62D000000096240000005F01AE829811473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1F1031000",
|
||||
"tx_blob": "120007228000000024000263F52019000263E764400000032A0D8DB065D4838D7EA4C6800000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D1684000000000002710732103CDF7533BF6B6DE8C1AEFC1F2F776F8EDAE08D88C6E1F9B69535D9CDDF3071029744630440220153DDCA438981E498EF3AF383845F74B2CC20602FD1E20546A067C68D026DE6502207E4ECB4A23FFBC274CE0C2D08131F26FDDB6240B2A701C8E49410E0F18595053811473DFB1F8FDE93B1E301897694F0DDE56516BDC40",
|
||||
"validated": true
|
||||
},
|
||||
"parsed": {
|
||||
"validated": true,
|
||||
"meta": {
|
||||
"TransactionIndex": 0,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "1C0662854F6571DD28392C1AF031757BDF2BC0E62C190ABE0BC22C46A2E443FD",
|
||||
"NewFields": {
|
||||
"Sequence": 156661,
|
||||
"BookDirectory": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00",
|
||||
"TakerPays": "13590433200",
|
||||
"TakerGets": {
|
||||
"value": "1",
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "42EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DF",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"RootIndex": "42EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DF",
|
||||
"Owner": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"ExchangeRate": "5F04CE166242F400",
|
||||
"RootIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400",
|
||||
"TakerPaysCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsCurrency": "0000000000000000000000004254430000000000",
|
||||
"TakerGetsIssuer": "0A20B3C85F482532A9578DBB3950B85CA06594D1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00",
|
||||
"NewFields": {
|
||||
"ExchangeRate": "5F04D40AEE52AE00",
|
||||
"RootIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00",
|
||||
"TakerGetsCurrency": "0000000000000000000000004254430000000000",
|
||||
"TakerGetsIssuer": "0A20B3C85F482532A9578DBB3950B85CA06594D1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "CDD61BD2DF2ADF53D0C05C171E2C8D48337BFE63868497BC30C5DCF2D0A03AFF",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 156647,
|
||||
"PreviousTxnLgrSeq": 10982736,
|
||||
"BookNode": "0000000000000000",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "0F60460F66E991AE6D77C50435E7FF8915453D411B6E43B38AC6410113B06CDC",
|
||||
"BookDirectory": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400",
|
||||
"TakerPays": "13524954400",
|
||||
"TakerGets": {
|
||||
"value": "1",
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 10983246,
|
||||
"PreviousTxnID": "329262FE69DD4F191AF0CE075489E7B7BDD273EC5528531D8184E1A73E76B7D3",
|
||||
"LedgerIndex": "E0A052DA53A0D6F6C16422D206D4E38862ED7A13AE90ED0EF5ED09353C2A7A94",
|
||||
"PreviousFields": {
|
||||
"Sequence": 156661,
|
||||
"Balance": "25503141689"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 156662,
|
||||
"OwnerCount": 9,
|
||||
"Balance": "25503131689",
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx": {
|
||||
"TransactionType": "OfferCreate",
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 156661,
|
||||
"OfferSequence": 156647,
|
||||
"TakerPays": "13590433200",
|
||||
"TakerGets": {
|
||||
"value": "1",
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"Fee": "10000",
|
||||
"SigningPubKey": "03CDF7533BF6B6DE8C1AEFC1F2F776F8EDAE08D88C6E1F9B69535D9CDDF3071029",
|
||||
"TxnSignature": "30440220153DDCA438981E498EF3AF383845F74B2CC20602FD1E20546A067C68D026DE6502207E4ECB4A23FFBC274CE0C2D08131F26FDDB6240B2A701C8E49410E0F18595053",
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4",
|
||||
"hash": "3CC8ED34260911194E8E30543D70A6DF04D3DABC746A546DAED32D22496B478C",
|
||||
"inLedger": 10983428,
|
||||
"ledger_index": 10983428
|
||||
}
|
||||
}
|
||||
},
|
||||
"PartialPayment": {
|
||||
"binary": {
|
||||
"ledger_index": 11234994,
|
||||
"meta": "201C000000126012D4038D7EA4C680010000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6AF8E51100612500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A75653539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03E6240000016962400000C7C1B0629EE1E72200000000240000016A2D0000001662400000C7C1B033BE8114E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E51100722500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7565A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DEE66294CDB50C7C41DBBA0000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E722000200003700000000000000433800000000000000006294CD472C93E8BFBD0000000000000000000000004A5059000000000000000000000000000000000000000000000000016680000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD46780000000000000000000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E511006F2500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7566CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BBE664D5844871834DEC610000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D4E3860923E65C0000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1E1E72200020000240000DFA82A1C51809E33000000000000000034000000000000062D50103B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F964D5844855628F5EC90000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D4E3851FD80BB80000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1811488F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A756785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26E662940E35FA931A000000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E7220002000037000000000000027D380000000000000000629411C37937E080010000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D503E871B540C0000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6AE1E1E51100722500AB6E1455E6190463C940CFE3D75B031D95768F55F8F5E163EEB460AE6ED003784FDBC06B567A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0E6629544C2582DF5BB4000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E72200220000370000000000000288380000000000000000629544C255D8B8AA400000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D5438D7EA4C68000000000000000000000000000555344000000000088F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A756ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACFE662D5C3F42A882475860000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E7220011000020123B9ACA0037000000000000000038000000000000004662D5C3F42D583783AE0000000000000000000000004A50590000000000000000000000000000000000000000000000000166D5CAA87BEE5380000000000000000000000000004A5059000000000088F647BBEC01AE19BE070B8B91063D14CE77F5236780000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD4E1E1F1031000",
|
||||
"tx_blob": "12000022800200002400000169201B00AB6EB461D4838D7EA4C680000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6A684000000000002EE069D4844ABF137B17EA0000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337732102AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D374463044022010E0D6884B36694342958C4872D7BADB825F36E6972757870665DD49580949A30220475F4CEA2904D23148AF51F194973AC73BDB986DA94BD9DEF51A5BBB9D7426108114E81DCB25DAA1DDEFF45145D334C56F12EA63C3378314625E2F1F09A0D769E05C04FAA64F0D2013306C6A011201E5C92828261DBAAC933B6309C6F5C72AF020AFD43000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD41000000000000000000000000000000000000000003000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4100000000000000000000000000000000000000000300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD3FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD300",
|
||||
"validated": true
|
||||
},
|
||||
"parsed": {
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Balance": "857948042174",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 22,
|
||||
"Sequence": 362
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "53539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03",
|
||||
"PreviousFields": {
|
||||
"Balance": "857948054174",
|
||||
"Sequence": 361
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-37.37431482875837"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000043"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "5A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DE",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-38.5823992616441"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F9",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 475103390,
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "000000000000062D",
|
||||
"Sequence": 57256,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.97996"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12054.31469825737"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "6CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BB",
|
||||
"PreviousFields": {
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.98998"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12055.52278269025"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.05000000000000001"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "110"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000027D"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.04"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1339.573870832192"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "1000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000288"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "7A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1339.583890832192"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "E6190463C940CFE3D75B031D95768F55F8F5E163EEB460AE6ED003784FDBC06B",
|
||||
"PreviousTxnLgrSeq": 11234836
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111290.052087083"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000046",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "300000"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"LowQualityIn": 1000000000
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACF",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111288.8440026502"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
}
|
||||
],
|
||||
"DeliveredAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01000000000000001"
|
||||
},
|
||||
"TransactionIndex": 18,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01000000000000001"
|
||||
}
|
||||
},
|
||||
"tx": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "1"
|
||||
},
|
||||
"Destination": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147614720,
|
||||
"LastLedgerSequence": 11234996,
|
||||
"Paths": [
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "1.208084432885738"
|
||||
},
|
||||
"Sequence": 361,
|
||||
"SigningPubKey": "02AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D3",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3044022010E0D6884B36694342958C4872D7BADB825F36E6972757870665DD49580949A30220475F4CEA2904D23148AF51F194973AC73BDB986DA94BD9DEF51A5BBB9D742610",
|
||||
"hash": "F1E35F73FC81BE1599FBEE184F39AC4168E4C181C7ED000137E9E3C62E18D8C6",
|
||||
"inLedger": 11234994,
|
||||
"ledger_index": 11234994
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
},
|
||||
"Payment": {
|
||||
"binary": {
|
||||
"ledger_index": 11234797,
|
||||
"meta": "201C00000003F8E51100612500AA666C55BDB03864DA53C51FE3981DAE091A72289F732FC8A5F3D16F74E7D2036246FA8D5653539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03E6240000016862400000C7C1B0917EE1E7220000000024000001692D0000001662400000C7C1B0629E8114E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E51100722500A0DB72559926ED5C3974070FCA9B3566B7FBF3BCB7C29FCD8A4435781A4AAAE5778576E5565A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DEE66294CE22EC649AF7B70000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E722000200003700000000000000433800000000000000006294CDB50C7C41DBBA0000000000000000000000004A5059000000000000000000000000000000000000000000000000016680000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD46780000000000000000000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E511006F2500AB6CF9556E81745BB5DA1EB60C3FDB988EC5CDFE55AD493482F39A54A6AB66E149DB364B566CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BBE664D584488DA40C79F90000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D5038D7EA4C6800000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1E1E72200020000240000DFA82A1C51809E33000000000000000034000000000000062D50103B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F964D5844871834DEC610000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D4E3860923E65C0000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1811488F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500A9FF9E5567550A7B0E398944B5528F678BCCA8A53C1356AF9C4FC8EE863B1CC83965C61A56785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26E662940AA87BEE53800000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E7220002000037000000000000027D38000000000000000062940E35FA931A00000000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D503E871B540C0000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6AE1E1E51100722500AB689E55ADE928FA078F53F269317B4FD8BF46C8953D381573BB80231BAC2EB3196DD74A567A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0E66295451D7C249ADC4000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E722002200003700000000000002883800000000000000006295451D79CF5DCB400000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D5438D7EA4C68000000000000000000000000000555344000000000088F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500AB4C9D55ECABF9CF633CF8FA6578A2C6430B3B9BA9611B8A31BC1730D222A6DD413B0CF156ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACFE662D5C3F427B811675E0000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E7220011000020123B9ACA0037000000000000000038000000000000004662D5C3F42A882475860000000000000000000000004A50590000000000000000000000000000000000000000000000000166D5CAA87BEE5380000000000000000000000000004A5059000000000088F647BBEC01AE19BE070B8B91063D14CE77F5236780000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD4E1E1F1031000",
|
||||
"tx_blob": "12000022800200002400000168201B00AB6DEF61D4038D7EA4C680000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6A684000000000002EE069D491C37937E080000000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337732102AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D37446304402204529AC13FDE2AF411F83DFCCCA1A41534C36A73EC56C00B822EF36B037F8D146022013A1EBC759497D9BB352263C50B49A3E8BD83FA174F6F66B1F095E820026E3588114E81DCB25DAA1DDEFF45145D334C56F12EA63C3378314625E2F1F09A0D769E05C04FAA64F0D2013306C6A011201E5C92828261DBAAC933B6309C6F5C72AF020AFD43000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD41000000000000000000000000000000000000000003000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4100000000000000000000000000000000000000000300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD3FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD300",
|
||||
"validated": true
|
||||
},
|
||||
"parsed": {
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Balance": "857948054174",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 22,
|
||||
"Sequence": 361
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "53539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03",
|
||||
"PreviousFields": {
|
||||
"Balance": "857948066174",
|
||||
"Sequence": 360
|
||||
},
|
||||
"PreviousTxnID": "BDB03864DA53C51FE3981DAE091A72289F732FC8A5F3D16F74E7D2036246FA8D",
|
||||
"PreviousTxnLgrSeq": 11167340
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-38.5823992616441"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000043"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "5A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DE",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-39.79048369452983"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "9926ED5C3974070FCA9B3566B7FBF3BCB7C29FCD8A4435781A4AAAE5778576E5",
|
||||
"PreviousTxnLgrSeq": 10541938
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F9",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 475103390,
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "000000000000062D",
|
||||
"Sequence": 57256,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.98998"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12055.52278269025"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "6CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BB",
|
||||
"PreviousFields": {
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "100"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12056.73086712313"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "6E81745BB5DA1EB60C3FDB988EC5CDFE55AD493482F39A54A6AB66E149DB364B",
|
||||
"PreviousTxnLgrSeq": 11234553
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.04"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "110"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000027D"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.03"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "67550A7B0E398944B5528F678BCCA8A53C1356AF9C4FC8EE863B1CC83965C61A",
|
||||
"PreviousTxnLgrSeq": 11141022
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1439.783890832192"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "1000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000288"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "7A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1439.793910832192"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "ADE928FA078F53F269317B4FD8BF46C8953D381573BB80231BAC2EB3196DD74A",
|
||||
"PreviousTxnLgrSeq": 11233438
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111288.8440026502"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000046",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "300000"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"LowQualityIn": 1000000000
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACF",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111287.6359182174"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "ECABF9CF633CF8FA6578A2C6430B3B9BA9611B8A31BC1730D222A6DD413B0CF1",
|
||||
"PreviousTxnLgrSeq": 11226269
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 3,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01"
|
||||
}
|
||||
},
|
||||
"tx": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01"
|
||||
},
|
||||
"Destination": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147614720,
|
||||
"LastLedgerSequence": 11234799,
|
||||
"Paths": [
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "5"
|
||||
},
|
||||
"Sequence": 360,
|
||||
"SigningPubKey": "02AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D3",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "304402204529AC13FDE2AF411F83DFCCCA1A41534C36A73EC56C00B822EF36B037F8D146022013A1EBC759497D9BB352263C50B49A3E8BD83FA174F6F66B1F095E820026E358",
|
||||
"hash": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"inLedger": 11234797,
|
||||
"ledger_index": 11234797
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
}
|
||||
95
test/fixtures/binary-ledger-data.json
vendored
Normal file
95
test/fixtures/binary-ledger-data.json
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"RippleState": {
|
||||
"binary": {
|
||||
"data": "110072220002000025000B657837000000000000003B3800000000000000005587591A63051645F37B85D1FBA55EE69B1C96BFF16904F5C99F03FB93D42D03756280000000000000000000000000000000000000004254430000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D167D4C38D7EA4C680000000000000000000000000004254430000000000C795FDF8A637BCAAEDAD1C434033506236C82A2D",
|
||||
"index": "000103996A3BAD918657F86E12A67D693E8FC8A814DA4B958A244B5F14D93E58"
|
||||
},
|
||||
"parsed": {
|
||||
"Balance": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rKUK9omZqVEnraCipKNFb5q4tuNTeqEDZS",
|
||||
"value": "10"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000003B",
|
||||
"PreviousTxnID": "87591A63051645F37B85D1FBA55EE69B1C96BFF16904F5C99F03FB93D42D0375",
|
||||
"PreviousTxnLgrSeq": 746872,
|
||||
"index": "000103996A3BAD918657F86E12A67D693E8FC8A814DA4B958A244B5F14D93E58"
|
||||
}
|
||||
},
|
||||
"AccountRoot": {
|
||||
"binary": {
|
||||
"data": "1100612200000000240000000125000DA4192D0000000055CA2EADCF53FEEFE2FF6B47D683A1E33413BC876C7C87669618365C91BD12A42262400000003B9ACA008114D018AF490EB4E476D735159CDEA798B6AF670FF7",
|
||||
"index": "0002D81201E576CF3E0120E2CC35C03E08E22452F498B8C874CD1DF9D3DC305B"
|
||||
},
|
||||
"parsed": {
|
||||
"Account": "rKyK3pQtCTMz6nt6Yxtx8vgju6hLyLWpwh",
|
||||
"Balance": "1000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"OwnerCount": 0,
|
||||
"PreviousTxnID": "CA2EADCF53FEEFE2FF6B47D683A1E33413BC876C7C87669618365C91BD12A422",
|
||||
"PreviousTxnLgrSeq": 893977,
|
||||
"Sequence": 1,
|
||||
"index": "0002D81201E576CF3E0120E2CC35C03E08E22452F498B8C874CD1DF9D3DC305B"
|
||||
}
|
||||
},
|
||||
"Offer": {
|
||||
"binary": {
|
||||
"data": "11006F2200000000240002A44625000F26213300000000000000003400000000000000C0555CCD6C8CD4E7BB1E508F05B831A9B4B634E02862435D5E3E3EEF3AB1690331395010FE4D53B02BC5D46DE095166E0667A0F3797F8A782F8A203B570EBC4086D53E0064D5459C5A55C77D00000000000000000000000000494C53000000000092D705968936C419CE614BF264B5EEB1CEA47FF465D48D871095D18000000000000000000000000000425443000000000092D705968936C419CE614BF264B5EEB1CEA47FF481141C40DA3AAC605E30B6CC5891EA6CDDFA0C996CE8",
|
||||
"index": "002B4106648895A68068DF34FC55AAD9BC1DC135FD737A318C582D706EA505A1"
|
||||
},
|
||||
"parsed": {
|
||||
"Account": "rs2PcQ9HX8afGGPsvUxEmTsrKs5D34kwwK",
|
||||
"BookDirectory": "FE4D53B02BC5D46DE095166E0667A0F3797F8A782F8A203B570EBC4086D53E00",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000000C0",
|
||||
"PreviousTxnID": "5CCD6C8CD4E7BB1E508F05B831A9B4B634E02862435D5E3E3EEF3AB169033139",
|
||||
"PreviousTxnLgrSeq": 992801,
|
||||
"Sequence": 173126,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rNPRNzBB92BVpAhhZr4iXDTveCgV5Pofm9",
|
||||
"value": "3.80768"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "ILS",
|
||||
"issuer": "rNPRNzBB92BVpAhhZr4iXDTveCgV5Pofm9",
|
||||
"value": "1579.28668368"
|
||||
},
|
||||
"index": "002B4106648895A68068DF34FC55AAD9BC1DC135FD737A318C582D706EA505A1"
|
||||
}
|
||||
},
|
||||
"DirectoryNode": {
|
||||
"binary": {
|
||||
"data": "110064220000000058001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF18214D5A7C190E367A150A2E4A04DE62E08766B8B48C2011360FE8118802AF3344FDC1DEB95D12F8E7C548928C19FEFE8CF7BD14D28E8F0E9EA3B70BB091D385EB6AFF31C52F05498BB70268FC4BEEDDC6B86770A85D74CEA71E676F574B44A1030EBA09A9A29C939550FAF2849171B3422EB521365F9052D00",
|
||||
"index": "001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF1"
|
||||
},
|
||||
"parsed": {
|
||||
"Flags": 0,
|
||||
"Indexes": [
|
||||
"FE8118802AF3344FDC1DEB95D12F8E7C548928C19FEFE8CF7BD14D28E8F0E9EA",
|
||||
"3B70BB091D385EB6AFF31C52F05498BB70268FC4BEEDDC6B86770A85D74CEA71",
|
||||
"E676F574B44A1030EBA09A9A29C939550FAF2849171B3422EB521365F9052D00"
|
||||
],
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"Owner": "rL76tmsh1Pgy57B4KMqjqWL7mGhwG24xgv",
|
||||
"RootIndex": "001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF1",
|
||||
"index": "001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF1"
|
||||
}
|
||||
}
|
||||
}
|
||||
1228
test/fixtures/binary-transaction.json
vendored
Normal file
1228
test/fixtures/binary-transaction.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
303
test/fixtures/metadata-with-hex-accounts.json
vendored
Normal file
303
test/fixtures/metadata-with-hex-accounts.json
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rNGySgyyEdRJ6MKmzsZwyhhVeFKdENRGQ6",
|
||||
"BookDirectory": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FC79E1600",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "0000000000000031",
|
||||
"PreviousTxnID": "83CA9AB231B0B4DA8ACF6305A6D7B00AB83404A1FDB8F8BCF7108EB87E0A8196",
|
||||
"PreviousTxnLgrSeq": 10555009,
|
||||
"Sequence": 12370,
|
||||
"TakerGets": "44978350398",
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "1056.990784602728"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "0496450E3F46368FB011B8B524605A906C0854441D30420457A81EA89BE649BE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rabVnHuo1eq747GbnLDAJfE9GpsGwcL9Hy",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rGa3Tb6vaMVU5RQMjxk4nsMGSArbu8epGG",
|
||||
"value": "5"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "2DECFAC23B77D5AEA6116C15F5C6D4669EBAEE9E7EE050A40FE2B1E47B6A9419",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "3"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "6F35AD78AA196389D15F4BAF054122070506633C1506EF16A48877E2593CCE2D",
|
||||
"PreviousTxnLgrSeq": 10555014
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1228.52678703286"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rabVnHuo1eq747GbnLDAJfE9GpsGwcL9Hy",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000076",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rPofp4ruTavGuFnb9AYN2vRPBFxHB7RRsH",
|
||||
"value": "50000"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "4AB2FFDEE65E025AAB54305A161C80D32082574BB0502311F29227089C696388",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1225.52678703286"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "65C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4C",
|
||||
"PreviousTxnLgrSeq": 10554856
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "rP5VvumKn5qqn4RYTMGipmPE9965ARVQNT",
|
||||
"RootIndex": "65E53030C59CD541BB6A8B631F13FA9BBF6F6E28B63D41AA363F23313B34B094"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "65E53030C59CD541BB6A8B631F13FA9BBF6F6E28B63D41AA363F23313B34B094"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rNGySgyyEdRJ6MKmzsZwyhhVeFKdENRGQ6",
|
||||
"Balance": "335297994919",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 12,
|
||||
"Sequence": 12379
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "6ACA1AAB7CD8877EA63E0C282A37FC212AD24640743F019AC2DD8674E003B741",
|
||||
"PreviousFields": {
|
||||
"OwnerCount": 13
|
||||
},
|
||||
"PreviousTxnID": "83CA9AB231B0B4DA8ACF6305A6D7B00AB83404A1FDB8F8BCF7108EB87E0A8196",
|
||||
"PreviousTxnLgrSeq": 10555009
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-15.68270575272517"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rGa3Tb6vaMVU5RQMjxk4nsMGSArbu8epGG",
|
||||
"value": "5000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000004A"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-12.68270575272517"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "6F35AD78AA196389D15F4BAF054122070506633C1506EF16A48877E2593CCE2D",
|
||||
"PreviousTxnLgrSeq": 10555014
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"IndexPrevious": "000000000000002C",
|
||||
"Owner": "rNGySgyyEdRJ6MKmzsZwyhhVeFKdENRGQ6",
|
||||
"RootIndex": "A93C6B313E260AC7C7734DF44F4461075E2C937C936C2B81DA2C9F69D4A0B0F2"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "8D8FB3359BBA810ED5C5894088F2415E322811181ADCC5BB087E829207DFBBEB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rP5VvumKn5qqn4RYTMGipmPE9965ARVQNT",
|
||||
"Balance": "25116082528",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 5,
|
||||
"Sequence": 2197
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "8F55B7E947241AD38FD6D47374BF8E7CA7DF177C8B79712B4CAC5E91FD5023FF",
|
||||
"PreviousFields": {
|
||||
"OwnerCount": 6
|
||||
},
|
||||
"PreviousTxnID": "0327747C391C678CA2AC46F422E1E8D307A41E9C0ED5DB2677B51CEBE41BD243",
|
||||
"PreviousTxnLgrSeq": 10554892
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rauAjp7gUp8xqHnPFDSo72Nc6aMx2k9yDk",
|
||||
"Balance": "233929959",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 14,
|
||||
"Sequence": 31927
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "A27BB98F7C9D32F404B364622645F80480F87C8A91BB13CA9F6E569144C2A5A8",
|
||||
"PreviousFields": {
|
||||
"Balance": "233941959",
|
||||
"Sequence": 31926
|
||||
},
|
||||
"PreviousTxnID": "65C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4C",
|
||||
"PreviousTxnLgrSeq": 10554856
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4D08594FC79E1600",
|
||||
"Flags": 0,
|
||||
"RootIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FC79E1600",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "0520B3C85F482532A9578DBB3950B85CA03594D1"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FC79E1600"
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4D08594FE7353EDE",
|
||||
"Flags": 0,
|
||||
"RootIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FE7353EDE",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "0520B3C85F482532A9578DBB3950B85CA03594D1"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FE7353EDE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-2818.268620725051"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rauAjp7gUp8xqHnPFDSo72Nc6aMx2k9yDk",
|
||||
"value": "50000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "00000000000001B0"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "FAD28E839AF29C6CCB8DA6DC71510A5BF8A9C34062C128071C7D22E2469B8288",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-2821.274620725051"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "65C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4C",
|
||||
"PreviousTxnLgrSeq": 10554856
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rP5VvumKn5qqn4RYTMGipmPE9965ARVQNT",
|
||||
"BookDirectory": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FE7353EDE",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "0327747C391C678CA2AC46F422E1E8D307A41E9C0ED5DB2677B51CEBE41BD243",
|
||||
"PreviousTxnLgrSeq": 10554892,
|
||||
"Sequence": 2196,
|
||||
"TakerGets": "4255320000",
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "100"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "FB2E442ED1A5BCA1E237BA133807AE17AED1A7E4B9F404906308ADB01A57609D"
|
||||
}
|
||||
}
|
||||
],
|
||||
"DeliveredAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rabVnHuo1eq747GbnLDAJfE9GpsGwcL9Hy",
|
||||
"value": "3"
|
||||
},
|
||||
"TransactionIndex": 5,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
}
|
||||
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'
|
||||
}
|
||||
};
|
||||
};
|
||||
788
test/fixtures/pathfind.json
vendored
Normal file
788
test/fixtures/pathfind.json
vendored
Normal file
@@ -0,0 +1,788 @@
|
||||
{
|
||||
"id": 2,
|
||||
"type": "path_find",
|
||||
"alternatives": [
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rwBWBFZrbLzHoe3PhwWYv89iHJdxAFrxcB",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rULnR9YhAkj9HrcxAcudzBhaXRSqT7zJkq",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": "64235"
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "BTC",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.000003810807915357615"
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "CHF",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.004290898000000001"
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "CNY",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.006251153484651535"
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "DYM",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.001503"
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "EUR",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.0008032032"
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.12872694"
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths_computed": [
|
||||
[
|
||||
{
|
||||
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"source_amount": {
|
||||
"currency": "MXN",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "0.008172391857506362"
|
||||
}
|
||||
}
|
||||
],
|
||||
"destination_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"destination_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0.001"
|
||||
},
|
||||
"source_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||
}
|
||||
123
test/fixtures/payment-iou.json
vendored
Normal file
123
test/fixtures/payment-iou.json
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"engine_result": "tesSUCCESS",
|
||||
"engine_result_code": 0,
|
||||
"engine_result_message": "The transaction was applied.",
|
||||
"ledger_hash": "F3F1416BF2E813396AB01FAA38E9F1023AC4D2368D94B0D52B2BC603CEEC01C3",
|
||||
"ledger_index": 10459371,
|
||||
"status": "closed",
|
||||
"type": "transaction",
|
||||
"validated": true,
|
||||
"metadata": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1.525330905250352"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "00000000000001E8",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc",
|
||||
"value": "1000000000"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "2F323020B4288ACD4066CC64C89DAD2E4D5DFC2D44571942A51C005BF79D6E25",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1.535330905250352"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "DC061E6F47B1B6E9A496A31B1AF87194B4CB24B2EBF8A59F35E31E12509238BD",
|
||||
"PreviousTxnLgrSeq": 10459364
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0.02"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "00000000000001E8",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K",
|
||||
"value": "1000000000"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "AAE13AF5192EFBFD49A8EEE5869595563FEB73228C0B38FED9CC3D20EE74F399",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0.01"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "DC061E6F47B1B6E9A496A31B1AF87194B4CB24B2EBF8A59F35E31E12509238BD",
|
||||
"PreviousTxnLgrSeq": 10459364
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc",
|
||||
"Balance": "239555992",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 38
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "E9A39B0BA8703D5FFD05D9EAD01EE6C0E7A15CF33C2C6B7269107BD2BD535818",
|
||||
"PreviousFields": {
|
||||
"Balance": "239567992",
|
||||
"Sequence": 37
|
||||
},
|
||||
"PreviousTxnID": "DC061E6F47B1B6E9A496A31B1AF87194B4CB24B2EBF8A59F35E31E12509238BD",
|
||||
"PreviousTxnLgrSeq": 10459364
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 2,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx_json": {
|
||||
"Account": "rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0.01"
|
||||
},
|
||||
"Destination": "rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 10459379,
|
||||
"Sequence": 37,
|
||||
"SigningPubKey": "03F16A52EBDCA6EBF5D99828E1E6918C64D45E6F136476A8F4757512FE553D18F0",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3044022031D6AB55CDFD17E06DA0BAD6D6B7DC9B5CA8FFF50405F2FCD3ED8D3893B1835E02200524CC1E7D70AE3F00C9F94405C55EE179C363F534905168AE8B5BA01CF568A0",
|
||||
"date": 471644150,
|
||||
"hash": "34671C179737CC89E0F8BBAA83C313885ED1733488FC0F3088BAE16A3D9A5B1B"
|
||||
}
|
||||
}
|
||||
171
test/fixtures/transaction-offercreate.json
vendored
Normal file
171
test/fixtures/transaction-offercreate.json
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"engine_result": "tesSUCCESS",
|
||||
"engine_result_code": 0,
|
||||
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||
"ledger_hash": "60A87F43A4A95AF446AE9391CEFC4FD41E24CA632286EBACA8B1337791009D2A",
|
||||
"ledger_index": 11409475,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-2008.589162146675"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQBgvk1GMACRzpSBrHJNQ6rNfgdzUv2SaX",
|
||||
"value": "1000000000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000028B"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "10E1B93C71D6FC528B36BFDAD005DFDA8BA4C6EC691ADE225ACD91A18BBBC2BA",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-2003.931566739001"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "308FD18F3D42F83F5C7043F2DEAA4B8DDCAF20F564D180D606F00F3E575FEEC5",
|
||||
"PreviousTxnLgrSeq": 11409459
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rHvo925Q1zmDJbzze6a5L3DfXdvhrwh1oJ",
|
||||
"Balance": "222138630497",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 5,
|
||||
"Sequence": 1040
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "3FB24E2BA13AE12802781D03F263CE28569BF487C766812485E3C286ED990CFC",
|
||||
"PreviousFields": {
|
||||
"Balance": "221810037141"
|
||||
},
|
||||
"PreviousTxnID": "736CEAD2BE2C49285BBC3ADCD1EA42FBB0D1A292E1A03C344234F664FC6EC523",
|
||||
"PreviousTxnLgrSeq": 11409463
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rQBgvk1GMACRzpSBrHJNQ6rNfgdzUv2SaX",
|
||||
"Balance": "473511395546",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 5,
|
||||
"Sequence": 4094
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "4179A2DBAF895E9D0618A8C0FB2FFDBEAE92E74C275C7992D538484AE20B2140",
|
||||
"PreviousFields": {
|
||||
"Balance": "473839998902",
|
||||
"Sequence": 4093
|
||||
},
|
||||
"PreviousTxnID": "308FD18F3D42F83F5C7043F2DEAA4B8DDCAF20F564D180D606F00F3E575FEEC5",
|
||||
"PreviousTxnLgrSeq": 11409459
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rHvo925Q1zmDJbzze6a5L3DfXdvhrwh1oJ",
|
||||
"BookDirectory": "4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C19107C30E031F0",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "0000000000000000",
|
||||
"Sequence": 1039,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||
"value": "190.5072902688483"
|
||||
},
|
||||
"TakerPays": "13440289328"
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "AAD85C591B95855B524675AE73EAEC90D5E4BF32425D36A5B449914ADE33EDD9",
|
||||
"PreviousFields": {
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||
"value": "195.1648856765226"
|
||||
},
|
||||
"TakerPays": "13768882684"
|
||||
},
|
||||
"PreviousTxnID": "736CEAD2BE2C49285BBC3ADCD1EA42FBB0D1A292E1A03C344234F664FC6EC523",
|
||||
"PreviousTxnLgrSeq": 11409463
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-459.5348867698966"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rHvo925Q1zmDJbzze6a5L3DfXdvhrwh1oJ",
|
||||
"value": "1000000000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000296"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "CDE76B186BBB028CA4C8A0C6D22085AD1DF8F692920150189343831E2C0C647D",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-464.2017973683862"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "5AF91C90CE8AE78FB8ACFFE2AB626936AB2CA4A8D66C25D087A41D4B75C16F39",
|
||||
"PreviousTxnLgrSeq": 11409443
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 10,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"status": "closed",
|
||||
"transaction": {
|
||||
"Account": "rQBgvk1GMACRzpSBrHJNQ6rNfgdzUv2SaX",
|
||||
"Fee": "10000",
|
||||
"Flags": 524288,
|
||||
"Sequence": 4093,
|
||||
"SigningPubKey": "020D6BF674E9ABF3BD8C08BA7CCFA878DC283729240CEC096FC1EE23DA823472C0",
|
||||
"TakerGets": "328593356",
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||
"value": "3.943120281680337"
|
||||
},
|
||||
"TransactionType": "OfferCreate",
|
||||
"TxnSignature": "3045022100FC89A7B7573754B33DA7556D861AC180CFEDD1F72DE9436384540745E3B2DBB4022074EDA52B2BE636A002743A49B791FD362B70B0DAFB8CC0AF3C49EDC261D0EA58",
|
||||
"date": 475884270,
|
||||
"hash": "FC7A9D19B40B7BCC66E3A38536E7DB888925BF935440307F6A4F55818E141BAC",
|
||||
"owner_funds": "473466395546"
|
||||
},
|
||||
"type": "transaction",
|
||||
"validated": true
|
||||
}
|
||||
19
test/fixtures/transaction-proposed.json
vendored
Normal file
19
test/fixtures/transaction-proposed.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"engine_result": "tesSUCCESS",
|
||||
"engine_result_code": 0,
|
||||
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||
"ledger_current_index": 114177,
|
||||
"status": "proposed",
|
||||
"transaction": {
|
||||
"Account": "rUPotLj5CNKaP4bQANcecEuT8hai3VpxfB",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 114177,
|
||||
"Sequence": 3862,
|
||||
"SigningPubKey": "FA16E9F38DF11402953A5B030C1AE8A88C47E348170C3B8EC6C8D775E797168F09",
|
||||
"TransactionType": "AccountSet",
|
||||
"hash": "815AF3AC669F513C039C0AB9F31D30703343A4D39EA7AA8D26F515B56B74D728"
|
||||
},
|
||||
"type": "transaction",
|
||||
"validated": false
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user