Compare commits

..

7 Commits

Author SHA1 Message Date
Chris Clark
2f6af4797f Bump version to 0.17.3 and bump ripple-binary-codec to 0.1.4 2016-09-29 11:24:27 -07:00
Chris Clark
5985d9022e Add orderToReplace option 2016-09-29 11:24:27 -07:00
Chris Clark
8abc87c27c Update flow 2016-09-29 11:24:27 -07:00
Chris Clark
f0feaca785 Fix typos in docs 2016-09-29 11:24:27 -07:00
Matthew Fettig
f811bd6c2d fix missing deliveredAmount data from getLedger requests 2016-09-29 11:24:26 -07:00
Chris Clark
eeb6e6b39d Disable sauce tests because they usually timeout 2016-09-29 11:24:26 -07:00
Chris Clark
327a8dc451 Fix code coverage tool 2016-09-29 11:24:26 -07:00
1052 changed files with 31128 additions and 90806 deletions

4
.babelrc Normal file
View File

@@ -0,0 +1,4 @@
{
"presets": ["es2015", "stage-1"],
"plugins": ["syntax-flow", "transform-flow-strip-types"]
}

19
.flowconfig Normal file
View File

@@ -0,0 +1,19 @@
[ignore]
.*/ripple-lib/src/.*
.*/ripple-lib/dist/.*
.*/ripple-lib/test/fixtures/.*
.*/node_modules/flow-bin/.*
.*/node_modules/webpack/.*
.*/node_modules/babel-core/.*
.*/node_modules/babel-eslint/.*
.*/node_modules/babel-preset-es2015/.*
.*/node_modules/babel-preset-stage-1/.*
.*/node_modules/babel-register/.*
[include]
./node_modules/
[libs]
[options]
module.system=node

View File

@@ -1,8 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: monthly
time: "15:00"
open-pull-requests-limit: 10

View File

@@ -1,50 +0,0 @@
## High Level Overview of Change
<!--
Please include a summary/list of the changes.
If too broad, please consider splitting into multiple PRs.
If a relevant Asana task, please link it here.
-->
### Context of Change
<!--
Please include the context of a change.
If a bug fix, when was the bug introduced? What was the behavior?
If a new feature, why was this architecture chosen? What were the alternatives?
If a refactor, how is this better than the previous implementation?
If there is a design document for this feature, please link it here.
-->
### Type of Change
<!--
Please check relevant options, delete irrelevant ones.
-->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Refactor (non-breaking change that only restructures code)
- [ ] Tests (You added tests for code that already exists, or your new feature included in this PR)
- [ ] Documentation Updates
- [ ] Release
## Before / After
<!--
If just refactoring / back-end changes, this can be just an in-English description of the change at a technical level.
If a UI change, screenshots should be included.
-->
## Test Plan
<!--
Please describe the tests that you ran to verify your changes and provide instructions so that others can reproduce.
-->
<!--
## Future Tasks
For future tasks related to PR.
-->

View File

@@ -1,67 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ develop, master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ develop ]
schedule:
- cron: '44 5 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -1,103 +0,0 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ develop, master, 2.0 ]
pull_request:
workflow_dispatch:
jobs:
build-and-lint:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install -g npm@7
- run: npm ci
- run: npm run build
- run: npm run lint
unit:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install -g npm@7
- run: npm ci
- run: npm run build
- run: npm test
integration:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
services:
rippled:
image: natenichols/rippled-standalone:latest
ports:
- 6006:6006
options:
--health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install -g npm@7
- run: npm ci
- run: npm run build
- run: npm run test:integration
env:
HOST: localhost
PORT: ${{ job.services.rippled.ports['6006'] }}
browser:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x] # This just needs to be compatible w/ puppeteer
services:
rippled:
image: natenichols/rippled-standalone:latest
ports:
- 6006:6006
options:
--health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install -g npm@7
- run: npm ci
- run: npm run build
- run: npm run test:browser

21
.gitignore vendored
View File

@@ -1,9 +1,5 @@
# .gitignore
# Ignore package locks other than npm.
yarn.lock
npm-shrinkwrap.json
# Ignore vim swap files.
*.swp
@@ -55,22 +51,13 @@ test/config.js
# Ignore npm-debug
npm-debug.log
# Ignore dist folder, built from tsc
# Ignore dist folder, build for bower
dist/
# TypeScript incremental compilation cache
*.tsbuildinfo
# Ignore flow output directory
out/
# Ignore perf test cache
scripts/cache
.eslintrc
# nyc (istanbul)
.nyc_output
# browser tests
testCompiledForWeb
# lerna debug
lerna-debug.log
eslintrc

4
.npmignore Normal file
View File

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

1
.nvmrc
View File

@@ -1 +0,0 @@
v12

View File

@@ -1,6 +0,0 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

38
.vscode/settings.json vendored
View File

@@ -1,38 +0,0 @@
{
"editor.tabSize": 2,
"cSpell.words": [
"secp256k1"
],
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"eslint.alwaysShowStatus": true,
"eslint.lintTask.enable": true,
"eslint.codeAction.showDocumentation": {
"enable": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/.hg/store/**": true
},
}

View File

@@ -1,163 +0,0 @@
# Applications using xrpl.js
A curated list of some of the projects and apps that leverage `xrpl.js` in some way.
**Have one to add?** Please edit this file and open a PR!
## Notice (disclaimer)
These sites are independent of Ripple and have not been authorized, endorsed, sponsored or otherwise approved by Ripple or its affiliates.
Warning: Use at your own risk.
## Exchanges
- **[The World Exchange](https://www.theworldexchange.net/)**
Trade, issue, and send directly on the XRP Ledger. A user interface for the XRPL's decentralized exchange.
- **[Bitso](https://bitso.com/)**
Exchange allowing clients to buy and sell XRP, based in Mexico.
## Explorers
- **[xrpintel - XRP Intelligence](https://xrpintel.com/)**
Monitor the XRP Network in real time and explore historical statistics.
- **[XRP Charts](https://xrpcharts.ripple.com/)** (xrpcharts.ripple.com)
XRP Charts provides information based on public data, including trade volume, top markets, metrics, transactions, and more.
- **[Ripple Live](https://gatehub.net/live)** (gatehub.net/live)
Visualize XRP network transactions.
- **[XRPL Dev. Dashboard](https://xrp.fans/)** (xrp.fans)
Debugging dashboard for `rippled-ws-client-pool`, transaction and query explorer, and transaction signing and submission tool.
- **[XRP Value](http://xrpvalue.com/)**
Real-time XRP price, trades, and orderbook data from the XRP Ledger.
- **[Bithomp - XRP Explorer](https://bithomp.com/explorer/)**
Look up information by entering an address, transaction hash, username, or PayID.
- **[Bithomp - XRPL validators](https://bithomp.com/validators)**
List of XRPL validators, nodes, and testnet validators.
- **[XRP Scan - XRP Ledger explorer](https://xrpscan.com)**
XRP Ledger explorer, metrics and analytics.
- **[xrplorer](https://xrplorer.com)**
XRP Ledger explorer, API, metrics, and analytics using a graph database that is synchronized live with the XRPL.
## Data monitoring
- **[zerptracker](https://zerptracker.com)**
Monitor the XRPL using powerful JSONPath expressions, and receive notifications via email, SMS, webhooks, and more.
- **[Utility-Scan](https://utility-scan.com)**
Attempts to detect RippleNet on-demand liquidity (ODL) transactions through known fiat corridors and report these transactions in real time.
- **[XRPL Rosetta](https://xrpl-rosetta-oepox.ondigitalocean.app)**
3D Globe written in three.js connected to a Node.js websocket server that is listening to exchanges and the XRPL. The visualization aims to show trading, ODL, and liquidity at exchanges, intra-exchange volume, and flows.
## Wallets and wallet tools
- **[XUMM](https://xumm.app/)**
Users can use the xumm application to track their accounts, balances and transactions. The true power of xumm is the platform available for developers.
- **[Xpring Wallet](https://xpring.io)** (uses `ripple-keypairs`)
Non-custodial XRP wallet.
- **[XRP Toolkit](https://www.xrptoolkit.com)**
A web interface to the XRP Ledger, supporting both hardware and software wallets.
- **[Toast Wallet](https://toastwallet.com/)**
A free, open source XRP Wallet for iOS, Android, Windows, Mac and Linux.
- **[Toastify Ledger](https://github.com/WietseWind/toastify-ledger)** (uses `ripple-keypairs`)
Add a Regular Key to a mnemonic XRP Wallet (e.g. Ledger Nano S) to use the account with a Family Seed (secret).
- **[Bithomp-submit](https://github.com/Bithomp/bithomp-submit)** (GitHub)
A tool to submit an offline-signed XRPL transaction.
- **[Kyte](https://kyteapp.co/)** (kyteapp.co) ([Source](https://github.com/WietseWind/Zerp-Wallet)) (Deprecated)
Web-based XRP wallet.
- **[XRP Vanity Address Generator](https://github.com/WietseWind/xrp-vanity-generator)** (Node.js)
A vanity address is a wallet address containing a few characters you like at the beginning or the end of the wallet address.
- **[XRP Account Mnemonic Recovery](https://github.com/WietseWind/xrp-mnemonic-recovery)** (uses `ripple-keypairs`)
Recover a 24 word mnemonic if one word is wrong or one word is missing.
## Send and request payments
- **[XRP Tip Bot](https://www.xrptipbot.com/)**
A bot that enables users on reddit, Twitter and Discord to send XRP to each other through reddit comments and Twitter tweets.
- **[XRP Text](https://xrptext.com/)**
Send XRP using SMS text messages.
- **[XRParrot](https://xrparrot.com/)** (uses `ripple-address-codec`)
Easy EUR (SEPA) to XRP transfer (currency conversion).
- **[XRP Payment](https://xrpayments.co/)** (xrpayments.co)
Tool for generating a XRP payment request URI in a QR code, with currency converter.
## Development tools
- **[XRP Faucets for Testnet and Devnet](https://xrpl.org/xrp-testnet-faucet.html)**
Get some test funds for development on the test network. The faucet uses `xrpl.js`.
## Code samples and libraries
- **[ilp-plugin-xrp-paychan](https://github.com/interledgerjs/ilp-plugin-xrp-paychan)**
Send ILP payments using XRP and payment channels (PayChan).
- **[RunKit: WietseWind](https://runkit.com/wietsewind/)**
XRP Ledger code samples for Node.js.
- **[GitHub Gist: WietseWind](https://gist.github.com/WietseWind)**
XRP Ledger code samples for Node.js and the web (mostly).
- **[rippled-ws-client-sign](https://github.com/WietseWind/rippled-ws-client-sign)**
Sign transactions, with support for MultiSign.
- **[ILP-enabled power switch](https://xrpcommunity.blog/raspberry-pi-interledger-xp-powerswitch-howto/)** ([video](https://www.youtube.com/watch?v=c-eS0HQUuJg)) (uses [`moneyd-uplink-xrp`](https://github.com/interledgerjs/moneyd-uplink-xrp))
For about $30 in parts (Raspberry Pi, 3.3V Relay board and a few wires) you can build your own power switch that will switch on if a streaming ILP payment comes in. When the payment stream stops, the power turns off.
## Related apps that do not appear to use xrpl.js
- **[XRP Stats](https://ledger.exposed/)** (ledger.exposed)
Rich list, live ledger stats and XRP distribution. Visualize escrows and flow of funds.

View File

@@ -1,149 +0,0 @@
# Contributing
## Set up your dev environment
### Requirements
We use Node v14 for development - that is the version that our linters require.
You must also use `npm` v7. You can check your `npm` version with:
```bash
npm -v
```
If your `npm` version is too old, use this command to update it:
```bash
npm -g i npm@7
```
### Set up
1. Clone the repository
2. `cd` into the repository
3. Install dependencies with `npm install`
### Build
```bash
npm run build
```
## Run the linter
```bash
npm install
npm run build
npm run lint
```
## Running Tests
For integration and browser tests, we use a `rippled` node in standalone mode to test xrpl.js code against. To set this up, you can either run `rippled` locally, or set up the Docker container `natenichols/rippled-standalone:latest` for this purpose. The latter will require you to [install Docker](https://docs.docker.com/get-docker/).
### Unit Tests
```bash
npm install
npm run build
npm test
```
### Integration Tests
```bash
npm install
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
docker run -p 6006:6006 -it natenichols/rippled-standalone:latest
npm run build
npm run test:integration
```
### Browser Tests
There are two ways to run browser tests.
One is in the browser - run `npm run build:browserTests` and open `test/localIntegrationRunner.html` in your browser.
The other is in the command line (this is what we use for CI) -
```bash
npm run build
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
docker run -p 6006:6006 -it natenichols/rippled-standalone:latest
npm run test:browser
```
## Generate reference docs
You can see the complete reference documentation at [`xrpl.js` docs](js.xrpl.org). You can also generate them locally using `typedoc`:
```bash
npm run docgen
```
## Adding and removing packages
`xrpl.js` uses `lerna` and `npm`'s workspaces features to manage a monorepo.
Adding and removing packages requires a slightly different process than normal
as a result.
### Adding or removing development dependencies
`xrpl.js` strives to use the same development dependencies in all packages.
You may add and remove dev dependencies like normal:
```bash
### adding a new dependency
npm install --save-dev abbrev
### removing a dependency
npm uninstall --save-dev abbrev
```
### Adding or removing runtime dependencies
You need to specify which package is changing using the `-w` flag:
```bash
### adding a new dependency to `xrpl`
npm install abbrev -w xrpl
### adding a new dependency to `ripple-keypairs`
npm install abbrev -w ripple-keypairs
### removing a dependency
npm uninstall abbrev -w xrpl
```
## Release process
### Editing the Code
* Your changes should have unit and/or integration tests.
* Your changes should pass the linter.
* Your code should pass all the tests on Github (which check the linter, unit and integration tests on Node 12/14/16, and browser tests).
* Open a PR against `develop` and ensure that all CI passes.
* Get a full code review from one of the maintainers.
* Merge your changes.
### Release
1. Ensure that all tests passed on the last CI that ran on `develop`.
2. Open a PR to update the docs if docs were modified.
3. Create a branch off `develop` that ensures that `HISTORY.md` is updated appropriately for each package.
* Use `shasum -a 256 build/*` to get the SHA-256 checksums. Add these to `HISTORY.md` as well.
4. Merge this branch into `develop`.
5. If this is not a beta release: Merge `develop` into `master` (`--ff-only`) and push to github. This is important because we have docs telling developers to use master to get the latest release.
6. Create a new Github release/tag off of this branch.
7. Run `npm publish --dry-run` and make sure everything looks good.
8. Publish the release to `npm`.
* If this is a beta release, run `npm publish --tag beta`. This allows someone else to install this version of the package with `npm install xrpl@beta`.
* If this is a stable release, run `npm publish`.
* This will require entering `npm` login info.
9. Send an email to [xrpl-announce](https://groups.google.com/g/xrpl-announce).
## Mailing Lists
We have a low-traffic mailing list for announcements of new `xrpl.js` releases. (About 1 email every couple of weeks)
+ [Subscribe to xrpl-announce](https://groups.google.com/g/xrpl-announce)
If you're using the XRP Ledger in production, you should run a [rippled server](https://github.com/ripple/rippled) and subscribe to the ripple-server mailing list as well.
+ [Subscribe to ripple-server](https://groups.google.com/g/ripple-server)

209
Gulpfile.js Normal file
View File

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

View File

@@ -1,3 +1,518 @@
# xrpl.js (ripple-lib) Release History
##0.16.5
**Changes**
+ [Filter insufficient source funds paths from pathfind results](https://github.com/ripple/ripple-lib/pull/688)
##0.16.4
**Changes**
+ [Update ws to 1.0.1](https://github.com/ripple/ripple-lib/pull/682)
##0.16.2
**Changes**
+ [Bump ripple-binary-codec dependency version to 0.1.1 to fix issue with computeLedgerHash for transactions with DeliverMin]
##0.16.1
**Changes**
+ [FIX: Use assert not assert-diff](https://github.com/ripple/ripple-lib/commit/f6ebe325193e7208c5ee8d8e84a7504714f0009e)
##0.16.0
**Breaking Changes**
+ [Fix types of XRP values in getServerInfo response](https://github.com/ripple/ripple-lib/commit/99d08065e4bda3dda6ae1f183adbd11abc70a9b7)
+ [Change error event format and fix crash due to error event on webscocket](https://github.com/ripple/ripple-lib/commit/9cd72595f0efc062d77b9d625695d6030c524cc6)
**Changes**
+ [Fix generateAddress docs and add error event listener to boilerplate](https://github.com/ripple/ripple-lib/commit/809d981987a2890fac3a73a40a05c598b9040334)
+ [Allow setting maxLedgerVersion to null to specify no maximum](https://github.com/ripple/ripple-lib/commit/82613e7e8b360d1ae1552eab4559ab4763c06d7e)
+ [Add support for client certificates](https://github.com/ripple/ripple-lib/commit/5f5e48e4140345d166b8c1a3ee0847b0d9e2d893)
+ [getFee returns a string not float](https://github.com/ripple/ripple-lib/commit/7bf2da6014c87e164542e69356efeaabb575a157)
+ [Fix parsing of quality for getTrustlines](https://github.com/ripple/ripple-lib/commit/86ff315ef2a39dfdc2ce97e0e1c4aa73f04e363b)
+ [Fix DeliverMin value when specifying minAmount](Fix DeliverMin value when specifying minAmount)
+ [http server example](https://github.com/ripple/ripple-lib/commit/76866ab901ea46a2dd73181605e0f7f4220043d4)
##0.15.2
**Changes**
+ [Fix support for proxy credentials in proxy URL and fix error when there are more than 10 outstanding requests](https://github.com/ripple/ripple-lib/commit/0990ad4a6f1d59ca9d2cb859b4e2d71693f3fc4b)
##0.15.1
**Changes**
+ [Fix babel-polyfill require](https://github.com/ripple/ripple-lib/commit/062148674c3b1293ab82c28e25615ddd530339fa)
+ [Fix samples](https://github.com/ripple/ripple-lib/commit/5d5cf868a2ddb1b1cd40e4a4f0a782d0066c2055)
+ [add unit tests for RippleAPIBroadcast](https://github.com/ripple/ripple-lib/commit/ddf8fe5b1a9c750490dca98fb9ffaaf8017f87e0)
##0.15.0
**Breaking Changes**
+ ["servers" parameter changed to single "server"](https://github.com/ripple/ripple-lib/commit/7061e9afe46f0682254d098adeff3dd7157521a1)
**Changes**
+ [fix handling memos in prepareSettings](https://github.com/ripple/ripple-lib/commit/c9704137b7b538e8dbf31c483bcdcf2dcfd7cd75)
+ [Docs: SusPay warnings, offline mode, and other tweaks](https://github.com/ripple/ripple-lib/commit/4b4fc36ebd93f1360781a65f2869bd2c4f0a5093)
+ [Fix prepareOrderCancellation documentation](https://github.com/ripple/ripple-lib/commit/5e720891f579fd73d43c64e5ec519d9121023c10)
##0.14.0
**Breaking Changes**
+ [prepareOrderCancellation now takes orderCancellation specification](https://github.com/ripple/ripple-lib/commit/7f33d8a71e56289e5a5e0ead1c74f75ebcde72bc)
+ [Rename "ledgerClosed" event to "ledger" and change format](https://github.com/ripple/ripple-lib/commit/8a3d4a64db5fbf560ebf87dc62e0212513c5e18a)
**Changes**
+ [Fix proxy support and add support for proxy authorization](https://github.com/ripple/ripple-lib/commit/14b840f3feca758e0384b746c94e36d8bf59b8c2)
+ [Fix trace option](https://github.com/ripple/ripple-lib/commit/af620755c53556c55eed12de4b0013ef5a349ce2)
+ [Allow memos on all transaction types](https://github.com/ripple/ripple-lib/commit/b5081344da8e66fbd3a5113cc3313325ef72a494)
+ [Add documentation for RippleAPI options](https://github.com/ripple/ripple-lib/commit/a76b554cadb9f9f918b06f8386bc29355682a1a4)
+ [Docs: more on basic types, tx types](https://github.com/ripple/ripple-lib/commit/fdbac63f466b4fd3be701d4878800d856692e26e)
+ [Docs: revised introductory material](https://github.com/ripple/ripple-lib/commit/ef2515507dbd3c6a426ab5b31332a1bdf72d5b2d)
+ [boost coverage to almost 100%](https://github.com/ripple/ripple-lib/commit/995606b1e6f3643af34d9fd442ccd31f320b03eb)
##0.13.2
**Changes**
+ [Fix: Specify send_max when pathfinding with a source amount](https://github.com/ripple/ripple-lib/commit/75142139184625c8b9fcc480b1825d9985337813)
##0.13.1
+ [Add documentation for API events](https://github.com/ripple/ripple-lib/commit/25d1ac0c5f95cad32ea4ceebb))
**Changes**
+ [Fix: Add babel-polyfill](https://github.com/ripple/ripple-lib/commit/8a53abc32f6ec6c7d50cd182492d6fb511b86704)
+ [Fix: Bump version on ripple-hashes](https://github.com/ripple/ripple-lib/commit/12e5765c64aea31b3c2fb65ff989cf01e6368f58)
##0.13.0
**Breaking Changes**
+ Add new RippleAPI interface and delete old API
- [RippleAPI README and samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples)
- [Method documentation](https://rawgit.com/ripple/ripple-lib/develop/docs/api.html)
**Changes**
+ [Removed timeout method of Request and added default timeout](https://github.com/ripple/ripple-lib/commit/634fe5683a9082e57682ff7d5c4fb9483b4af818)
+ [Add Remote.closeCurrentPathFind function, so current pathfind can be properly closed](https://github.com/ripple/ripple-lib/commit/e99010f363fc7cbe7fd547d3ca5b32ea083c44e6)
+ [Implement Balance Sheet API](https://github.com/ripple/ripple-lib/pull/579)
+ [Fix bugs in orderbook subscription](https://github.com/ripple/ripple-lib/commit/7404795dc64a85216148de7bc3ca7da7b33f4490)
+ [Fix crash due to rippled slowDown error](https://github.com/ripple/ripple-lib/commit/84838b2e9f6969b593b8462a62a6b8f516ada937)
+ [Fix: Emit error events and return error on pathfind](https://github.com/ripple/ripple-lib/commit/1ccbaf677631a1944eb05d90f7afc5f3690a03dd)
+ [Deprecate core and remove snake case method copying](https://github.com/ripple/ripple-lib/commit/fb8dc44ec1d49bb05cd0cdbe6dd4ab211195868a)
+ [Fix RangeSet for validated_ledger as single ledger](https://github.com/ripple/ripple-lib/commit/9f9e76f8b933201651af59307135f67cfa7d60e8)
+ [Fix bug where the paths would be set with an empty array](https://github.com/ripple/ripple-lib/commit/83874ec0962da311b76f2385623e51c68bc39035)
+ [Fix reserve calculation](https://github.com/ripple/ripple-lib/commit/52879febb92d876f01f2e4d70871baa07af631fb)
##0.12.9
+ [OrderBook performance optimizations](https://github.com/ripple/ripple-lib/commit/3e17d91edf36745f6b6c09b0ad88971b7775f6ab)
##0.12.7 and 0.12.8
+ [Improve performance of orderbook](https://github.com/ripple/ripple-lib/commit/c745faaaf0956ca98448a754b4fe97fb50574fc7)
+ [Remove Firefox warning about prototype overwrite](https://github.com/ripple/ripple-lib/commit/0c62fa21123b220b066871e1c41a3b4fe6f51885)
+ [Fix compare bug in Amount class](https://github.com/ripple/ripple-lib/commit/806547dd154e1b0bf252e8a74ad3ac6aa8a97660)
##0.12.6
+ [Fix webpack require failure due to "./" notation](https://github.com/ripple/ripple-lib/commit/8d9746d7b10be203ee613df523c2522012ff1baf)
##0.12.15
+ [Add offer autobridging](https://github.com/ripple/ripple-lib/commit/c7bbce83719c1e8c6a4fae5ca850e7515db1a4a5)
+ [Prevent crash when listening for "model" events on the OrderBook class](https://github.com/ripple/ripple-lib/commit/5824c3cb7cb6bd834d6e037f69943aebf3d83351)
+ [Fix empty order edgecase](https://github.com/ripple/ripple-lib/commit/64809d9ae23dc24f47accd4b4788b48f49880d3e)
+ [Fix AutobridgeCalculator (RT-3445)](https://github.com/ripple/ripple-lib/commit/1fff5ea6dcbcee856536df26f3b9cf1aec3c3b55)
+ [Update sjcl and delete custom ripemd160, montgomery, and jacobi](https://github.com/ripple/ripple-lib/commit/50cda426eb83599c38c0b725e1524a01fc415da2)
+ [Fix transaction summary for transactions that fail with remoteError](https://github.com/ripple/ripple-lib/commit/5e714f6143464d7912f42537acaa553b88eaf6dc)
+ [Fix serializedobject append for excessively large bytes length](https://github.com/ripple/ripple-lib/commit/e93f1ab6f4aaad347450aee75a169af0faa2121c)
+ [Switch to sjcl npm module](https://github.com/ripple/ripple-lib/commit/9a502580fd89ec6a9aa55f4e5847f6a4a2cb5bba)
+ [Add babel transpiler](https://github.com/ripple/ripple-lib/commit/398f8d001f758bf575b959537a17e79e4042d17b)
+ [Remove unused float.js and wallet.js](https://github.com/ripple/ripple-lib/commit/d4a4b5f4fbbf09677a59ce81bace35c6426a2fda)
+ [Remove config singleton to reduce global state](https://github.com/ripple/ripple-lib/commit/c655c2a20ee5d150a4b5a1b6717b9fb81f636025)
##0.12.4
+ [Improve entropy security](https://github.com/ripple/ripple-lib/commit/c7ba822320880037796f57876d1abb4e525648ed)
+ [Remove unused crypt.js file](https://github.com/ripple/ripple-lib/commit/1f68eba1461bca03a4d22872450d15ae5a185334)
##0.12.3
+ [Add getLedgerSequence to Remote](https://github.com/ripple/ripple-lib/commit/d09548d04d3238fca653d482ec1d5faa7254559a)
+ [Improve randomness when generating ECDSA signatures](https://github.com/ripple/ripple-lib/commit/fe7e30b737ead6e71adfa466f5835ba546feab31)
+ [Improve SerializedObject.append performance](https://github.com/ripple/ripple-lib/commit/f7c35b118ebba549a64bcaa1a0629385ec6dbf6f)
+ [Add `Amount.scale`. Multiply an amounts value by a scale factor](https://github.com/ripple/ripple-lib/commit/74dac97b368493056474468520f05671f458a69f)
##0.12.2
+ [Check that stack trace is available, fixes logging in browser](https://github.com/ripple/ripple-lib/commit/53cae3a66d48e88e8a6bbb96d6489ce7b9e22975)
##0.12.1
**Breaking Changes**
+ [Removed support for parsing native amounts in floating point format](https://github.com/ripple/ripple-lib/commit/e80cd1ff55deae9cd5b0ae85be957f86856b887e)
**Changes**
+ [Fix taker pays funded calculation](https://github.com/ripple/ripple-lib/commit/5af824f5cf46c7b9caa58ee0a757bf854d26c8dc)
+ [Fix order funded amount calculation](https://github.com/ripple/ripple-lib/commit/b2cdb1a6aed968b1f306e8dadbd4b7ca37e5aa03)
+ [Fix handling of quality in order book](https://github.com/ripple/ripple-lib/commit/2a5a8b498da60df738ba18d5c265f34771e8a1af)
+ [Fix currency parsing of non-alphanumeric and no-currency currencies](https://github.com/ripple/ripple-lib/commit/2166bb2e88eae8d5f1aba77338f69e8a9edf6a6f)
+ [Add Amount.strict_mode for toggling range validation](https://github.com/ripple/ripple-lib/commit/b5ed8f59a7dab1a17491618b8d9193646c314fb4)
+ [Add filename and line number to log, use log.warn() for deprecations](https://github.com/ripple/ripple-lib/commit/90329d3d73f1a76675063655b407513e32dc048b)
+ [Add GlobalFreeze and NoFreeze flags](https://github.com/ripple/ripple-lib/commit/e2ed2bdbf6f01c7d4d690c2cf0b83fba94558dd7)
+ [Fix handling of falsy parameters in requestLedger](https://github.com/ripple/ripple-lib/commit/6023efed41b7812b3bab660a1c0dc9f0a21000b9)
+ [Fix Base:decode](https://github.com/ripple/ripple-lib/commit/719f39c01c6941d9a650aa94f95617793dd53ea0)
+ [Fix Amount: clone in ratio_human, product_human](https://github.com/ripple/ripple-lib/commit/19e17a8431550cf156b1ad669a19dedfe4e28e4a)
+ [Fix Amount.to_human for very small numbers](https://github.com/ripple/ripple-lib/commit/6abfa759aa09d68074ac558d96c4b126a7cd1719)
+ [Refactor base conversion](https://github.com/ripple/ripple-lib/commit/f2b63fa4a80663eb29472bc6bb1aea8159f1f205)
+ [Update binary transaction format](https://github.com/ripple/ripple-lib/commit/8e134918fb4c22983320a3102f955e4568bb1dfb)
+ [Add DefaultRipple account flag](https://github.com/ripple/ripple-lib/commit/3e249902c4cf25b4da5e75048c84ae391be83b10)
+ [Remove `Features` field requirement in `SetFee` transaction format](https://github.com/ripple/ripple-lib/commit/a20a649013646710c078d4ce1e210f87c7fe74fe)
+ [Remove `RegularKey` field requirement in `SetRegularKey` transaction format](https://github.com/ripple/ripple-lib/commit/c275174f27877ba8f389eb4efe969feb514d6e46)
##0.12.0
**Breaking Changes**
+ 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)
+ [Add paging behavior for account requests, `account_lines` and `account_offers`](https://github.com/ripple/ripple-lib/commit/722f4e175dbbf378e51b49142d0285f87acb22d7)
+ [Add max_fee setter to transactions to set max fee the submitter is willing to pay] (https://github.com/ripple/ripple-lib/commit/24587fab9c8ad3840d7aa345a7037b48839e09d7)
+ [Fix: cap IOU Amounts to their max and min value] (https://github.com/ripple/ripple-lib/commit/f05941fbc46fdb7c6fe7ad72927af02d527ffeed)
Example on how to use paging with `account_offers`:
```
// A valid `ledger_index` or `ledger_hash` is required to provide a reliable result.
// Results can change between ledger closes, so the provided ledger will be used as base.
var options = {
account: < rippleAccount >,
limit: < Number between 10 and 400 >,
ledger: < valid ledger_index or ledger_hash >
}
// The `marker` comes back in an account request if there are more results than are returned
// in the current response. The amount of results per response are determined by the `limit`.
if (marker) {
options.marker = < marker >;
}
var request = remote.requestAccountOffers(options);
```
[Full working example](https://github.com/geertweening/ripple-lib-scripts/blob/master/account_offers_paging.js)
##0.9.1
+ Switch account requests to use ledgerSelect rather than ledgerChoose ([278df90](https://github.com/ripple/ripple-lib/commit/278df9025a20228de22379a53c76ca12d40fa591))
+ **Deprecated** setting `ident` and `account_index` on account requests ([278df90](https://github.com/ripple/ripple-lib/commit/278df9025a20228de22379a53c76ca12d40fa591))
+ Change initial account transaction sequence to 1 ([a3c1d06](https://github.com/ripple/ripple-lib/commit/a3c1d06eba883dc84fe2bfe700e4309795c84cac))
+ Fix: instance transaction withoute remote ([d3b6b81](https://github.com/ripple/ripple-lib/commit/d3b6b8127c7b01e416b400c25abf1719bdd008ca))
+ Fix: account root request ledger argument ([bc1f9f8](https://github.com/ripple/ripple-lib/commit/bc1f9f8a286b187d36ebaf552694e31e73742293))
+ Fix: rsign.js local signing and example ([d3b6b81](https://github.com/ripple/ripple-lib/commit/d3b6b8127c7b01e416b400c25abf1719bdd008ca) and [f1004c6](https://github.com/ripple/ripple-lib/commit/f1004c6db2a0ce59bbabbb8f2b355a9fd9995fd8))
##0.9.0
+ Add routes to the vault client for KYC attestations ([ed2da574](https://github.com/ripple/ripple-lib/commit/ed2da57475acf5e9d2cf3373858f4274832bd83f))
+ Currency: add `show_interest` flag to show or hide interest in `Currency.to_human()` and `Currency.to_json()` [Example use in tests](https://github.com/ripple/ripple-lib/blob/947ec3edc2e7c8f1ef097e496bf552c74366e749/test/currency-test.js#L123)
+ Configurable maxAttempts for transaction submission ([d107092](https://github.com/ripple/ripple-lib/commit/d10709254061e9e4416d2cb78b5cac1ec0d7ffa5))
+ Binformat: added missing TransactionResult options ([6abed8d](https://github.com/ripple/ripple-lib/commit/6abed8dd5311765b2eb70505dadbdf5121439ca8))
+ **Breaking change:** make maxLoops in seed.get_key optional. [Example use in tests](https://github.com/ripple/ripple-lib/blob/23e473b6886c457781949c825b3ff48b3984e51f/test/seed-test.js) ([23e473b](https://github.com/ripple/ripple-lib/commit/23e473b6886c457781949c825b3ff48b3984e51f))
+ Shrinkwrap packages for dependency locking ([2dcd5f9](2dcd5f94fbc71200eb08a5044c76ef94f7971913))
+ Fix: Amount.to_human() precision bugs ([4be209e](https://github.com/ripple/ripple-lib/commit/4be209e286b5b209bec7bcd1212098985e15ff2f) and [7708c64](https://github.com/ripple/ripple-lib/commit/7708c64576e70ce3ac190442daceb30e4446aab7))
+ Fix: change handling of requestLedger options ([57b7030](https://github.com/ripple/ripple-lib/commit/57b70300f5f0c7534ede118ddbb5d8762668a4f8))
##0.8.2
+ Currency: Allow mixed letters and numbers in currencies
+ Deprecate account_tx map/reduce/filterg
+ Fix: correct requestLedger arguments
+ Fix: missing subscription on error events for some server methods
+ Fix: orderbook reset on reconnect
+ Fix: ripple-lib crashing. Add potential missing error handlers
##0.8.1
+ Wallet: Add Wallet class that generates wallets
+ Make npm test runnable in Windows.
+ Fix several stability issues, see merged PR's for details
+ Fix bug in Amount.to_human_full()
+ Fix undefined fee states when connecting to a rippled that is syncing
##0.8.0
+ Orderbook: Added tracking of offer funds for determining when offers are not funded
+ Orderbook: Added tests
+ Orderbook: Update owner funds
+ Transactions: If transaction errs with `tefALREADY`, wait until all possible submissions err with the same before emitting `error`. Fixes a client "Transaction malformed" bug.
+ Transactions: Track submissions, don't bother submitting to unconnected servers
+ Request: `request.request()` now accepts an array of servers as first argument. Servers can be represented with URL, or the server object itself.
+ Request: `request.broadcast()` now returns the number of servers request was sent to
+ Server: Acquire host information from server without additional request
+ Amount: Add a constant for the maximum canonical value that can be expressed as a Ripple value
+ Amount: Make Constants static fields on the class, instead of a seperate export
##0.7.39
+ Improvements to multi-server support. Fixed an issue where a server's score was not reset and connections would keep dropping after being connected for a significant amount of time.
+ Improvements in order book support. Added support for currency pairs with interest bearing currencies. You can request an order book with hex, ISO code or full name for the currency.
+ Fix value parsing for amount/currency order pairs, e.g. `Amount.from_human("XAU 12345.6789")`
+ Improved Amount parsing from human readable string given a hex currency, e.g. `Amount.from_human("10 015841551A748AD2C1F76FF6ECB0CCCD00000000")`
+ Improvements to username normalization in the vault client
+ Add 2-factor authentication support for vault client
+ Removed vestiges of Grunt, switched to Gulp
##0.7.37
+ **Deprecations**
1. Removed humanistic amount detection in `transaction.payment`. Passing `1XRP` as the payment amount no longer works.
2. `remote.setServer` uses full server URL rather than hostname. Example: `remote.setServer('wss://s`.ripple.com:443')`
3. Removed constructors for deprecated transaction types from `transaction.js`.
4. Removed `invoiceID` option from `transaction.payment`. Instead, use the `transaction.invoiceID` method.
5. Removed `transaction.transactionManager` getter.
+ Improved multi-server support. Servers are now ranked dynamically, and transactions are broadcasted to all connected servers.
+ Automatically ping connected servers. Client configuration now should contain `ping: <seconds>` to specify the ping interval.
+ Added `transaction.lastLedger` to specify `LastLedgerSequence`. Setting it this way also ensures that the sequence is not bumped on subsequent requests.
+ Added optional `remote.accountTx` binary parsing.
```js
{
binary: true,
parseBinary: false
}
```
+ Added full currency name support, e.g. `Currency.from_json('XRP').to_human({full_name:'Ripples'})` will return `XRP - Ripples`
+ Improved interest bearing currency support, e.g. `Currency.from_human('USD - US Dollar (2.5%pa)')`
+ Improve test coverage
+ Added blob vault client. The vault client facilitates interaction with ripple's namespace and blob vault or 3rd party blob vaults using ripple's blob vault software (https://github.com/ripple/ripple-blobvault). A list of the available functions can be found at [docs/VAULTCLIENT.md](docs/VAULTCLIENT.md)
##0.7.35
+ `LastLedgerSequence` is set by default on outgoing transactions. This refers to the last valid ledger index (AKA sequence) for a transaction. By default, this index is set to the current index (at submission time) plus 8. In theory, this allows ripple-lib to deterministically fail a transaction whose submission request timed out, but whose associated server continues to emit ledger_closed events.
+ Transactions that err with `telINSUF_FEE_P` will be automatically resubmitted. This error indicates that the `Fee` supplied in the transaction submission request was inadquate. Ideally, the `Fee` is tracked by ripple-lib in real-time, and the resubmitted transaction will most likely succeed.
+ Added Transaction.iff(function(callback) { }). Callback expects first argument to be an Error or null, second argument is a boolean which indicates whether or not to proceed with the transaction submission. If an `iff` function is specified, it will be executed prior to every submission of the transaction (including resubmissions).
+ Transactions will now emit `presubmit` and `postsubmit` events. They will be emitted before and after a transaction is submitted, respectively.
+ Added Transaction.summary(). Returns a summary of a transaction in semi-human-readable form. JSON-stringifiable.
+ Remote.requestAccountTx() with `binary: true` will automatically parse transactions.
+ Added Remote.requestAccountTx filter, map, and reduce.
```js
remote.requestAccountTx({
account: 'retc',
ledger_index_min: -1,
ledger_index_max: -1,
limit: 100,
binary: true,
filter: function(transaction) {
return transaction.tx.TransactionType === 'Payment';
},
map: function(transaction) {
return Number(transaction.tx.Amount);
},
reduce: function(a, b) {
return a + b;
},
pluck: 'transactions'
}, console.log)
```
+ Added persistence hooks.
+ General performance improvements, especially for long-running processes.
Please see the individual HISTORY.md documents in each package for changes.

View File

@@ -1,5 +1,3 @@
ISC License
Copyright (c) 2012-2015 Ripple Labs Inc.
Permission to use, copy, modify, and distribute this software for any

151
README.md
View File

@@ -1,146 +1,37 @@
# xrpl.js
#ripple-lib
A JavaScript/TypeScript library for interacting with the XRP Ledger
A JavaScript API for interacting with Ripple in Node.js
[![NPM](https://nodei.co/npm/xrpl.png)](https://www.npmjs.org/package/xrpl)
![npm bundle size](https://img.shields.io/bundlephobia/min/xrpl)
[![Circle CI](https://circleci.com/gh/ripple/ripple-lib/tree/develop.svg?style=svg)](https://circleci.com/gh/ripple/ripple-lib/tree/develop) [![Coverage Status](https://coveralls.io/repos/ripple/ripple-lib/badge.png?branch=develop)](https://coveralls.io/r/ripple/ripple-lib?branch=develop)
This is the recommended library for integrating a JavaScript/TypeScript app with the XRP Ledger, especially if you intend to use advanced functionality such as IOUs, payment paths, the decentralized exchange, account settings, payment channels, escrows, multi-signing, and more.
[![NPM](https://nodei.co/npm/ripple-lib.png)](https://www.npmjs.org/package/ripple-lib)
## [➡️ Reference Documentation](http://js.xrpl.org)
###Features
See the full reference documentation for all classes, methods, and utilities.
+ Connect to a rippled server in Node.js
+ 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
## [➡️ Applications and Projects](https://github.com/XRPLF/xrpl.js/blob/master/APPLICATIONS.md)
What is `xrpl.js` used for? The applications on the list linked above use `xrpl.js`. Open a PR to add your app or project to the list!
### Features
+ Works in Node.js and in web browsers
+ Helpers for creating requests and parsing responses for the [XRP Ledger APIs](https://xrpl.org/rippled-api.html)
+ Listen to events on the XRP Ledger (transactions, ledger, validations, etc.)
+ Sign and submit transactions to the XRP Ledger
+ Type definitions for TypeScript
### Requirements
+ **[Node.js v14](https://nodejs.org/)** is recommended. We also support v12 and v16. Other versions may work but are not frequently tested.
## Getting Started
In an existing project (with `package.json`), install `xrpl.js`:
##Getting Started
Install `ripple-lib` using npm:
```
$ npm install --save xrpl
$ npm install ripple-lib
```
Or with `yarn`:
Then see the [documentation](https://github.com/ripple/ripple-lib/blob/develop/docs/index.md) and [code samples](https://github.com/ripple/ripple-lib/tree/develop/docs/samples)
```
$ yarn add xrpl
```
##Running tests
Example usage:
1. Clone the repository
2. `cd` into the repository and install dependencies with `npm install`
3. `npm test` or `npm test --coverage` (`istanbul` will create coverage reports in coverage/lcov-report/`)
```js
const xrpl = require("xrpl")
async function main() {
const client = new xrpl.Client("wss://s.altnet.rippletest.net:51233")
await client.connect()
##Generating Documentation
const response = await client.request({
"command": "account_info",
"account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"ledger_index": "validated"
})
console.log(response)
The continuous integration tests require that the documentation stays up-to-date. If you make changes the the JSON schemas, fixtures, or documentation sources, you must update the documentation by running `npm run docgen`.
client.disconnect()
}
main()
```
##More Information
For more examples, see the [documentation](#documentation).
### Using xrpl.js with React Native
If you want to use `xrpl.js` with React Native you will need to install shims for core NodeJS modules. To help with this you can use a module like [rn-nodeify](https://github.com/tradle/rn-nodeify).
1. Install dependencies (you can use `yarn` as well):
```shell
npm install react-native-crypto
npm install xrpl
# install peer deps
npm install react-native-randombytes
# install latest rn-nodeify
npm install rn-nodeify@latest --dev
```
2. After that, run the following command:
```shell
# install node core shims and recursively hack package.json files
# in ./node_modules to add/update the "browser"/"react-native" field with relevant mappings
./node_modules/.bin/rn-nodeify --hack --install
```
3. Enable `crypto`:
`rn-nodeify` will create a `shim.js` file in the project root directory.
Open it and uncomment the line that requires the crypto module:
```javascript
// If using the crypto shim, uncomment the following line to ensure
// crypto is loaded first, so it can populate global.crypto
require('crypto')
```
4. Import `shim` in your project (it must be the first line):
```javascript
import './shim'
...
```
### Using xrpl.js with Deno
Until official support for [Deno](https://deno.land) is added, you can use the following work-around to use `xrpl.js` with Deno:
```javascript
import xrpl from 'https://dev.jspm.io/npm:xrpl';
(async () => {
const api = new (xrpl as any).Client('wss://s.altnet.rippletest.net:51233');
const address = 'rH8NxV12EuV...khfJ5uw9kT';
api.connect().then(() => {
api.getBalances(address).then((balances: any) => {
console.log(JSON.stringify(balances, null, 2));
});
});
})();
```
## Documentation
+ [Get Started in Node.js](https://xrpl.org/get-started-using-node-js.html)
+ [Full Reference Documentation](https://js.xrpl.org)
+ [Code Samples](https://github.com/XRPLF/xrpl.js/tree/develop/packages/xrpl/snippets/src)
### Mailing Lists
We have a low-traffic mailing list for announcements of new `xrpl.js` releases. (About 1 email per week)
+ [Subscribe to xrpl-announce](https://groups.google.com/g/xrpl-announce)
If you're using the XRP Ledger in production, you should run a [rippled server](https://github.com/ripple/rippled) and subscribe to the ripple-server mailing list as well.
+ [Subscribe to ripple-server](https://groups.google.com/g/ripple-server)
## More Information
+ [xrpl-announce mailing list](https://groups.google.com/g/xrpl-announce) - subscribe for release announcements
+ [xrpl.js API Reference](https://js.xrpl.org)
+ [XRP Ledger Dev Portal](https://xrpl.org)
+ [Ripple Dev Portal](https://ripple.com/build/)

View File

@@ -1,30 +0,0 @@
# Security Policy
## Supported Versions
This table shows which versions of xrpl.js are currently supported with security updates:
| Version | Supported |
| ------- | ---------------------- |
| 2.x | :white_check_mark: Yes |
| 1.x | :white_check_mark: Yes |
| 0.x | :x: No |
## Responsible disclosure security policy
The responsible disclosure of vulnerabilities helps to protect users of the project. Vulnerabilities are first triaged in a private manner, and only publicly disclosed after a reasonable time period that allows patching the vulnerability and provides an upgrade path for users.
When contacting us directly via email, we will do our best to respond in a reasonable time to resolve the issue. Do not disclose the vulnerability until it has been patched and users have been given time to upgrade.
We kindly ask you to refrain from malicious acts that put our users, the project, or any of the projects team members at risk.
## Reporting a security issue
Security is a top priority. But no matter how much effort we put into security, there can still be vulnerabilities present.
If you discover a security vulnerability, please use the following means of communications to report it to us:
- Report the security issue to bugs@ripple.com
- [Ripple Bug Bounty](https://ripple.com/bug-bounty/)
Your efforts to responsibly disclose your findings are sincerely appreciated and will be taken into account to acknowledge your contributions.

20
circle.yml Normal file
View File

@@ -0,0 +1,20 @@
machine:
node:
version: 0.12.0
hosts:
testripple.circleci.com: 127.0.0.1
dependencies:
pre:
- npm -g install npm@latest-2
- npm install flow-bin
- wget https://s3-us-west-2.amazonaws.com/ripple-debs/rippled_0.30.1-b11-1.deb
- sudo dpkg -i rippled_0.30.1-b11-1.deb
test:
pre:
- rippled -a --start --conf "$HOME/$CIRCLE_PROJECT_REPONAME/test/integration/rippled.cfg":
background: true
override:
- scripts/ci.sh "$CIRCLE_NODE_INDEX" "$CIRCLE_NODE_TOTAL":
parallel: true
post:
- killall /usr/bin/rippled

3638
docs/index.md Normal file

File diff suppressed because it is too large Load Diff

3
docs/samples/README Normal file
View File

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

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

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

38
docs/samples/cancelall.js Normal file
View File

@@ -0,0 +1,38 @@
'use strict';
const RippleAPI = require('../../dist/npm').RippleAPI; // require('ripple-lib')
const address = 'rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K';
const secret = '';
const api = new RippleAPI({server: 'wss://s1.ripple.com:443'});
const instructions = {maxLedgerVersionOffset: 5};
function fail(message) {
console.error(message);
process.exit(1);
}
function cancelOrder(orderSequence) {
console.log('Cancelling order: ' + orderSequence.toString());
return api.prepareOrderCancellation(address, {orderSequence}, instructions)
.then(prepared => {
const signing = api.sign(prepared.txJSON, secret);
return api.submit(signing.signedTransaction);
});
}
function cancelAllOrders(orderSequences) {
if (orderSequences.length === 0) {
return Promise.resolve();
}
const orderSequence = orderSequences.pop();
return cancelOrder(orderSequence).then(() => cancelAllOrders(orderSequences));
}
api.connect().then(() => {
console.log('Connected...');
return api.getOrders(address).then(orders => {
const orderSequences = orders.map(order => order.properties.sequence);
return cancelAllOrders(orderSequences);
}).then(() => process.exit(0));
}).catch(fail);

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

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

View File

@@ -0,0 +1,55 @@
# Basic Types
## Ripple Address
```json
"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
```
Every Ripple account has an *address*, which is a base58-encoding of a hash of the account's public key. Ripple addresses always start with the lowercase letter `r`.
## Account Sequence Number
Every Ripple account has a *sequence number* that is used to keep transactions in order. Every transaction must have a sequence number. A transaction can only be executed if it has the next sequence number in order, of the account sending it. This prevents one transaction from executing twice and transactions executing out of order. The sequence number starts at `1` and increments for each transaction that the account makes.
## Currency
Currencies are represented as either 3-character currency codes or 40-character uppercase hexadecimal strings. We recommend using uppercase [ISO 4217 Currency Codes](http://www.xe.com/iso4217.php) only. The string "XRP" is disallowed on trustlines because it is reserved for the Ripple native currency. The following characters are permitted: all uppercase and lowercase letters, digits, as well as the symbols `?`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, and `|`.
## Value
A *value* is a quantity of a currency represented as a decimal string. Be careful: JavaScript's native number format does not have sufficient precision to represent all values. XRP has different precision from other currencies.
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
## Amount
Example amount:
```json
{
"currency": "USD",
"counterparty": "rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM",
"value": "100"
}
```
Example XRP amount:
```json
{
"currency": "XRP",
"value": "2000"
}
```
An *amount* is data structure representing a currency, a quantity of that currency, and the counterparty on the trustline that holds the value. For XRP, there is no counterparty.
A *lax amount* allows the counterparty to be omitted for all currencies. If the counterparty is not specified in an amount within a transaction specification, then any counterparty may be used for that amount.
A *lax lax amount* allows either or both the counterparty and value to be omitted.
A *balance* is an amount than can have a negative value.
<%- renderSchema('objects/amount-base.json') %>

View File

@@ -0,0 +1,68 @@
## Boilerplate
Use the following [boilerplate code](https://en.wikipedia.org/wiki/Boilerplate_code) to wrap your custom code using RippleAPI.
```javascript
const {RippleAPI} = require('ripple-lib');
const api = new RippleAPI({
server: 'wss://s1.ripple.com' // Public rippled server hosted by Ripple, Inc.
});
api.on('error', (errorCode, errorMessage) => {
console.log(errorCode + ': ' + errorMessage);
});
api.on('connected', () => {
console.log('connected');
});
api.on('disconnected', (code) => {
// code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
// will be 1000 if this was normal closure
console.log('disconnected, code:', code);
});
api.connect().then(() => {
/* insert code here */
}).then(() => {
return api.disconnect();
}).catch(console.error);
```
RippleAPI is designed to work in [NodeJS](https://nodejs.org) (version `0.12.0` or greater) using [Babel](https://babeljs.io/) for [ECMAScript 6](https://babeljs.io/docs/learn-es2015/) support.
The code samples in this documentation are written in ES6, but `RippleAPI` will work with ES5 also. Regardless of whether you use ES5 or ES6, the methods that return promises will return [ES6-style promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
<aside class="notice">
All the code snippets in this documentation assume that you have surrounded them with this boilerplate.
</aside>
<aside class="notice">
If you omit the "catch" section, errors may not be visible.
</aside>
<aside class="notice">
The "error" event is emitted whenever an error occurs that cannot be associated with a specific request. If the listener is not registered, an exception will be thrown whenever the event is emitted.
</aside>
### Parameters
The RippleAPI constructor optionally takes one argument, an object with the following options:
<%- renderSchema('input/api-options.json') %>
If you omit the `server` parameter, RippleAPI operates [offline](#offline-functionality).
### Installation ###
1. Install [NodeJS](https://nodejs.org) and the Node Package Manager (npm). Most Linux distros have a package for NodeJS, but make sure you have version `0.12.0` or higher.
2. Use npm to install [Babel](https://babeljs.io/) globally:
`npm install -g babel-cli`
3. Use npm to install RippleAPI:
`npm install ripple-lib`
After you have installed ripple-lib, you can create scripts using the [boilerplate](#boilerplate) and run them using babel-node:
`babel-node script.js`
<aside class="notice">
Instead of using babel-node in production, we recommend using Babel to transpile to ECMAScript 5 first.
</aside>

24
docs/src/combine.md.ejs Normal file
View File

@@ -0,0 +1,24 @@
## combine
`combine(signedTransactions: Array<string>): {signedTransaction: string, id: string}`
Combines signed transactions from multiple accounts for a multisignature transaction. The signed transaction must subsequently be [submitted](#submit).
### Parameters
<%- renderSchema("input/combine.json") %>
### Return Value
This method returns an object with the following structure:
<%- renderSchema("output/sign.json") %>
### Example
```javascript
const signedTransactions = <%- importFile('test/fixtures/requests/combine.json') %>;
return api.combine(signedTransactions);
```
<%- renderFixture("responses/combine.json") %>

View File

@@ -0,0 +1,28 @@
## computeLedgerHash
`computeLedgerHash(ledger: Object): string`
Compute the hash of a ledger.
### Parameters
<aside class="notice">
The parameter to this method has the same structure as the return value of getLedger.
</aside>
<%- renderSchema('input/compute-ledger-hash.json') %>
### Return Value
This method returns an uppercase hexadecimal string representing the hash of the ledger.
### Example
```javascript
const ledger = <%- importFile('test/fixtures/requests/compute-ledger-hash.json') %>;
return api.computeLedgerHash(ledger);
```
```json
"F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349"
```

17
docs/src/connect.md.ejs Normal file
View File

@@ -0,0 +1,17 @@
## connect
`connect(): Promise<void>`
Tells the RippleAPI instance to connect to its rippled server.
### Parameters
This method has no parameters.
### Return Value
This method returns a promise that resolves with a void value when a connection is established.
### Example
See [Boilerplate](#boilerplate) for code sample.

View File

@@ -0,0 +1,17 @@
## disconnect
`disconnect(): Promise<void>`
Tells the RippleAPI instance to disconnect from its rippled server.
### Parameters
This method has no parameters.
### Return Value
This method returns a promise that resolves with a void value when a connection is destroyed.
### Example
See [Boilerplate](#boilerplate) for code sample

81
docs/src/events.md.ejs Normal file
View File

@@ -0,0 +1,81 @@
# API Events
## ledger
This event is emitted whenever a new ledger version is validated on the connected server.
### Return Value
<%- renderSchema('output/ledger-event.json') %>
### Example
```javascript
api.on('ledger', ledger => {
console.log(JSON.stringify(ledger, null, 2));
});
```
<%- renderFixture('responses/ledger-event.json') %>
## error
This event is emitted when there is an error on the connection to the server that cannot be associated to a specific request.
### Return Value
The first parameter is a string indicating the error type:
* `badMessage` - rippled returned a malformed message
* `websocket` - the websocket library emitted an error
* one of the error codes found in the [rippled Universal Errors](https://ripple.com/build/rippled-apis/#universal-errors).
The second parameter is a message explaining the error.
The third parameter is:
* the message that caused the error for `badMessage`
* the error object emitted for `websocket`
* the parsed response for rippled errors
### Example
```javascript
api.on('error', (errorCode, errorMessage, data) => {
console.log(errorCode + ': ' + errorMessage);
});
```
```
tooBusy: The server is too busy to help you now.
```
## connected
This event is emitted after connection successfully opened.
### Example
```javascript
api.on('connected', () => {
console.log('Connection is open now.');
});
```
## disconnected
This event is emitted when connection is closed.
### Return Value
The only parameter is a number containing the [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) send by the server.
### Example
```javascript
api.on('disconnected', (code) => {
if (code !== 1000) {
console.log('Connection is closed due to error.');
} else {
console.log('Connection is closed normally.');
}
});
```

View File

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

View File

@@ -0,0 +1,25 @@
## getAccountInfo
`getAccountInfo(address: string, options: Object): Promise<Object>`
Returns information for the specified account. Note: For account data that is modifiable by the user, see [getSettings](#getsettings).
### Parameters
<%- renderSchema('input/get-account-info.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<%- renderSchema('output/get-account-info.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getAccountInfo(address).then(info =>
{/* ... */});
```
<%- renderFixture('responses/get-account-info.json') %>

View File

@@ -0,0 +1,25 @@
## getBalanceSheet
`getBalanceSheet(address: string, options: Object): Promise<Object>`
Returns aggregate balances by currency plus a breakdown of assets and obligations for a specified account.
### Parameters
<%- renderSchema('input/get-balance-sheet.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<%- renderSchema('output/get-balance-sheet.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getBalanceSheet(address).then(balanceSheet =>
{/* ... */});
```
<%- renderFixture('responses/get-balance-sheet.json') %>

View File

@@ -0,0 +1,25 @@
## getBalances
`getBalances(address: string, options: Object): Promise<Array<Object>>`
Returns balances for a specified account.
### Parameters
<%- renderSchema('input/get-balances.json') %>
### Return Value
This method returns a promise that resolves with an array of objects with the following structure:
<%- renderSchema('output/get-balances.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getBalances(address).then(balances =>
{/* ... */});
```
<%- renderFixture('responses/get-balances.json') %>

23
docs/src/getFee.md.ejs Normal file
View File

@@ -0,0 +1,23 @@
## getFee
`getFee(): Promise<number>`
Returns the estimated transaction fee for the rippled server the RippleAPI instance is connected to.
### Parameters
This method has no parameters.
### Return Value
This method returns a promise that resolves with a string encoded floating point value representing the estimated fee to submit a transaction, expressed in XRP.
### Example
```javascript
return api.getFee().then(fee => {/* ... */});
```
```json
"0.012"
```

24
docs/src/getLedger.md.ejs Normal file
View File

@@ -0,0 +1,24 @@
## getLedger
`getLedger(options: Object): Promise<Object>`
Returns header information for the specified ledger (or the most recent validated ledger if no ledger is specified). Optionally, all the transactions that were validated in the ledger or the account state information can be returned with the ledger header.
### Parameters
<%- renderSchema('input/get-ledger.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<%- renderSchema('output/get-ledger.json') %>
### Example
```javascript
return api.getLedger()
.then(ledger => {/* ... */});
```
<%- renderFixture('responses/get-ledger.json') %>

View File

@@ -0,0 +1,26 @@
## getLedgerVersion
`getLedgerVersion(): Promise<number>`
Returns the most recent validated ledger version number known to the connected server.
### Parameters
This method has no parameters.
### Return Value
This method returns a promise that resolves with a positive integer representing the most recent validated ledger version number known to the connected server.
### Example
```javascript
return api.getLedgerVersion().then(ledgerVersion => {
/* ... */
});
```
```json
16869039
```

View File

@@ -0,0 +1,26 @@
## getOrderbook
`getOrderbook(address: string, orderbook: Object, options: Object): Promise<Object>`
Returns open orders for the specified account. Open orders are orders that have not yet been fully executed and are still in the order book.
### Parameters
<%- renderSchema('input/get-orderbook.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure (Note: the structures of `bids` and `asks` are identical):
<%- renderSchema('output/get-orderbook.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const orderbook = <%- importFile('test/fixtures/requests/get-orderbook.json') %>;
return api.getOrderbook(address, orderbook)
.then(orderbook => {/* ... */});
```
<%- renderFixture('responses/get-orderbook.json') %>

25
docs/src/getOrders.md.ejs Normal file
View File

@@ -0,0 +1,25 @@
## getOrders
`getOrders(address: string, options: Object): Promise<Array<Object>>`
Returns open orders for the specified account. Open orders are orders that have not yet been fully executed and are still in the order book.
### Parameters
<%- renderSchema('input/get-orders.json') %>
### Return Value
This method returns a promise that resolves with an array of objects with the following structure:
<%- renderSchema('output/get-orders.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getOrders(address).then(orders =>
{/* ... */});
```
<%- renderFixture('responses/get-orders.json') %>

25
docs/src/getPaths.md.ejs Normal file
View File

@@ -0,0 +1,25 @@
## getPaths
`getPaths(pathfind: Object): Promise<Array<Object>>`
Finds paths to send a payment. Paths are options for how to route a payment.
### Parameters
<%- renderSchema("input/get-paths.json") %>
### Return Value
This method returns a promise that resolves with an array of objects with the following structure:
<%- renderSchema("output/get-paths.json") %>
### Example
```javascript
const pathfind = <%- importFile('test/fixtures/requests/getpaths/normal.json') %>;
return api.getPaths(pathfind)
.then(paths => {/* ... */});
```
<%- renderFixture("responses/get-paths.json") %>

View File

@@ -0,0 +1,23 @@
## getServerInfo
`getServerInfo(): Promise<object>`
Get status information about the server that the RippleAPI instance is connected to.
### Parameters
This method has no parameters.
### Return Value
This method returns a promise that resolves with an object with the following structure:
<%- renderSchema('output/get-server-info.json') %>
### Example
```javascript
return api.getServerInfo().then(info => {/* ... */});
```
<%- renderFixture('responses/get-server-info.json') %>

View File

@@ -0,0 +1,25 @@
## getSettings
`getSettings(address: string, options: Object): Promise<Object>`
Returns settings for the specified account. Note: For account data that is not modifiable by the user, see [getAccountInfo](#getaccountinfo).
### Parameters
<%- renderSchema('input/get-settings.json') %>
### Return Value
This method returns a promise that resolves with an array of objects with the following structure (Note: all fields are optional as they will not be shown if they are set to their default value):
<%- renderSchema('output/get-settings.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getSettings(address).then(settings =>
{/* ... */});
```
<%- renderFixture('responses/get-settings.json') %>

View File

@@ -0,0 +1,26 @@
## getTransaction
`getTransaction(id: string, options: Object): Promise<Object>`
Retrieves a transaction by its [Transaction ID](#transaction-id).
### Parameters
<%- renderSchema('input/get-transaction.json') %>
### Return Value
This method returns a promise that resolves with a transaction object containing the following fields.
<%- renderSchema('output/get-transaction.json') %>
### Example
```javascript
const id = '01CDEAA89BF99D97DFD47F79A0477E1DCC0989D39F70E8AACBFE68CC83BD1E94';
return api.getTransaction(id).then(transaction => {
/* ... */
});
```
<%- renderFixture('responses/get-transaction-payment.json') %>

View File

@@ -0,0 +1,24 @@
## getTransactions
`getTransactions(address: string, options: Object): Promise<Array<Object>>`
Retrieves historical transactions of an account.
### Parameters
<%- renderSchema('input/get-transactions.json') %>
### Return Value
This method returns a promise that resolves with an array of transaction object in the same format as [getTransaction](#gettransaction).
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getTransactions(address).then(transaction => {
/* ... */
});
```
<%- renderFixture('responses/get-transactions.json') %>

View File

@@ -0,0 +1,25 @@
## getTrustlines
`getTrustlines(address: string, options: Object): Promise<Array<Object>>`
Returns trustlines for a specified account.
### Parameters
<%- renderSchema("input/get-trustlines.json") %>
### Return Value
This method returns a promise that resolves with an array of objects with the following structure.
<%- renderSchema("output/get-trustlines.json") %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
return api.getTrustlines(address).then(trustlines =>
{/* ... */});
```
<%- renderFixture("responses/get-trustlines.json") %>

38
docs/src/index.md.ejs Normal file
View File

@@ -0,0 +1,38 @@
<% include introduction.md.ejs %>
<% include boilerplate.md.ejs %>
<% include offline.md.ejs %>
<% include basictypes.md.ejs %>
<% include transactions.md.ejs %>
<% include specifications.md.ejs %>
<% include methods.md.ejs %>
<% include connect.md.ejs %>
<% include disconnect.md.ejs %>
<% include isConnected.md.ejs %>
<% include getServerInfo.md.ejs %>
<% include getFee.md.ejs %>
<% include getLedgerVersion.md.ejs %>
<% include getTransaction.md.ejs %>
<% include getTransactions.md.ejs %>
<% include getTrustlines.md.ejs %>
<% include getBalances.md.ejs %>
<% include getBalanceSheet.md.ejs %>
<% include getPaths.md.ejs %>
<% include getOrders.md.ejs %>
<% include getOrderbook.md.ejs %>
<% include getSettings.md.ejs %>
<% include getAccountInfo.md.ejs %>
<% include getLedger.md.ejs %>
<% include preparePayment.md.ejs %>
<% include prepareTrustline.md.ejs %>
<% include prepareOrder.md.ejs %>
<% include prepareOrderCancellation.md.ejs %>
<% include prepareSettings.md.ejs %>
<% include prepareSuspendedPaymentCreation.md.ejs %>
<% include prepareSuspendedPaymentCancellation.md.ejs %>
<% include prepareSuspendedPaymentExecution.md.ejs %>
<% include sign.md.ejs %>
<% include combine.md.ejs %>
<% include submit.md.ejs %>
<% include generateAddress.md.ejs %>
<% include computeLedgerHash.md.ejs %>
<% include events.md.ejs %>

View File

@@ -0,0 +1,12 @@
# Introduction
RippleAPI is the official client library to the Ripple Consensus Ledger. Currently, RippleAPI is only available in JavaScript.
Using RippleAPI, you can:
* [Query transactions from the network](#gettransaction)
* [Sign](#sign) transactions securely without connecting to any server
* [Submit](#submit) transactions to the Ripple Consensus Ledger, including [Payments](#payment), [Orders](#order), [Settings changes](#settings), and [other types](#transaction-types)
* [Generate a new Ripple Address](#generateaddress)
* ... and [much more](#api-methods).
RippleAPI only provides access to *validated*, *immutable* transaction data.

View File

@@ -0,0 +1,23 @@
## isConnected
`isConnected(): boolean`
Checks if the RippleAPI instance is connected to its rippled server.
### Parameters
This method has no parameters.
### Return Value
This method returns `true` if connected and `false` if not connected.
### Example
```javascript
return api.isConnected();
```
```json
true
```

1
docs/src/methods.md.ejs Normal file
View File

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

27
docs/src/offline.md.ejs Normal file
View File

@@ -0,0 +1,27 @@
## Offline functionality
RippleAPI can also function without internet connectivity. This can be useful in order to generate secrets and sign transactions from a secure, isolated machine.
To instantiate RippleAPI in offline mode, use the following boilerplate code:
```javascript
const {RippleAPI} = require('ripple-lib');
const api = new RippleAPI();
/* insert code here */
```
Methods that depend on the state of the Ripple Consensus Ledger are unavailable in offline mode. To prepare transactions offline, you **must** specify the `fee`, `sequence`, and `maxLedgerVersion` parameters in the [transaction instructions](#transaction-instructions). The following methods should work offline:
* [preparePayment](#preparepayment)
* [prepareTrustline](#preparetrustline)
* [prepareOrder](#prepareorder)
* [prepareOrderCancellation](#prepareordercancellation)
* [prepareSettings](#preparesettings)
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
* [sign](#sign)
* [generateAddress](#generateaddress)
* [computeLedgerHash](#computeledgerhash)

View File

@@ -0,0 +1,30 @@
## prepareOrder
`prepareOrder(address: string, order: Object, instructions: Object): Promise<Object>`
Prepare an order transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
### Parameters
<%- renderSchema('input/prepare-order.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema('output/prepare.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const order = <%- importFile('test/fixtures/requests/prepare-order.json') %>;
return api.prepareOrder(address, order)
.then(prepared => {/* ... */});
```
<%- renderFixture('responses/prepare-order.json') %>

View File

@@ -0,0 +1,30 @@
## prepareOrderCancellation
`prepareOrderCancellation(address: string, orderCancellation: Object, instructions: Object): Promise<Object>`
Prepare an order cancellation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
### Parameters
<%- renderSchema("input/prepare-order-cancellation.json") %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema("output/prepare.json") %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const orderCancellation = {orderSequence: 123};
return api.prepareOrderCancellation(address, orderCancellation)
.then(prepared => {/* ... */});
```
<%- renderFixture("responses/prepare-order-cancellation.json") %>

View File

@@ -0,0 +1,30 @@
## preparePayment
`preparePayment(address: string, payment: Object, instructions: Object): Promise<Object>`
Prepare a payment transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
### Parameters
<%- renderSchema("input/prepare-payment.json") %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema("output/prepare.json") %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const payment = <%- importFile('test/fixtures/requests/prepare-payment.json') %>;
return api.preparePayment(address, payment).then(prepared =>
{/* ... */});
```
<%- renderFixture("responses/prepare-payment.json") %>

View File

@@ -0,0 +1,30 @@
## prepareSettings
`prepareSettings(address: string, settings: Object, instructions: Object): Promise<Object>`
Prepare a settings transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
### Parameters
<%- renderSchema('input/prepare-settings.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema('output/prepare.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const settings = <%- importFile('test/fixtures/requests/prepare-settings.json') %>;
return api.prepareSettings(address, settings)
.then(prepared => {/* ... */});
```
<%- renderFixture('requests/prepare-settings.json') %>

View File

@@ -0,0 +1,32 @@
## prepareSuspendedPaymentCancellation
`prepareSuspendedPaymentCancellation(address: string, suspendedPaymentCancellation: Object, instructions: Object): Promise<Object>`
Prepare a suspended payment cancellation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
### Parameters
<%- renderSchema('input/prepare-suspended-payment-cancellation.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema('output/prepare.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const suspendedPaymentCancellation = <%- importFile('test/fixtures/requests/prepare-suspended-payment-cancellation.json') %>;
return api.prepareSuspendedPaymentCancellation(address, suspendedPaymentCancellation).then(prepared =>
{/* ... */});
```
<%- renderFixture('responses/prepare-suspended-payment-cancellation.json') %>

View File

@@ -0,0 +1,32 @@
## prepareSuspendedPaymentCreation
`prepareSuspendedPaymentCreation(address: string, suspendedPaymentCreation: Object, instructions: Object): Promise<Object>`
Prepare a suspended payment creation transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
### Parameters
<%- renderSchema('input/prepare-suspended-payment-creation.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema('output/prepare.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const suspendedPaymentCreation = <%- importFile('test/fixtures/requests/prepare-suspended-payment-creation.json') %>;
return api.prepareSuspendedPaymentCreation(address, suspendedPaymentCreation).then(prepared =>
{/* ... */});
```
<%- renderFixture('responses/prepare-suspended-payment-creation.json') %>

View File

@@ -0,0 +1,32 @@
## prepareSuspendedPaymentExecution
`prepareSuspendedPaymentExecution(address: string, suspendedPaymentExecution: Object, instructions: Object): Promise<Object>`
Prepare a suspended payment execution transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
**Caution:** Suspended Payments are currently available on the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) only.
### Parameters
<%- renderSchema('input/prepare-suspended-payment-execution.json') %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema('output/prepare.json') %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const suspendedPaymentExecution = <%- importFile('test/fixtures/requests/prepare-suspended-payment-execution.json') %>;
return api.prepareSuspendedPaymentExecution(address, suspendedPaymentExecution).then(prepared =>
{/* ... */});
```
<%- renderFixture('responses/prepare-suspended-payment-execution.json') %>

View File

@@ -0,0 +1,30 @@
## prepareTrustline
`prepareTrustline(address: string, trustline: Object, instructions: Object): Promise<Object>`
Prepare a trustline transaction. The prepared transaction must subsequently be [signed](#sign) and [submitted](#submit).
### Parameters
<%- renderSchema("input/prepare-trustline.json") %>
### Return Value
This method returns a promise that resolves with an object with the following structure:
<aside class="notice">
All "prepare*" methods have the same return type.
</aside>
<%- renderSchema("output/prepare.json") %>
### Example
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const trustline = <%- importFile('test/fixtures/requests/prepare-trustline.json') %>;
return api.prepareTrustline(address, trustline).then(prepared =>
{/* ... */});
```
<%- renderFixture("responses/prepare-trustline.json") %>

25
docs/src/sign.md.ejs Normal file
View File

@@ -0,0 +1,25 @@
## sign
`sign(txJSON: string, secret: string, options: Object): {signedTransaction: string, id: string}`
Sign a prepared transaction. The signed transaction must subsequently be [submitted](#submit).
### Parameters
<%- renderSchema("input/sign.json") %>
### Return Value
This method returns an object with the following structure:
<%- renderSchema("output/sign.json") %>
### Example
```javascript
const txJSON = '{"Flags":2147483648,"TransactionType":"AccountSet","Account":"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59","Domain":"726970706C652E636F6D","LastLedgerSequence":8820051,"Fee":"12","Sequence":23}';
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV';
return api.sign(txJSON, secret);
```
<%- renderFixture("responses/sign.json") %>

View File

@@ -0,0 +1,83 @@
# Transaction Specifications
A *transaction specification* specifies what a transaction should do. Each [Transaction Type](#transaction-types) has its own type of specification.
## Payment
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/payment.json') %>
### Example
<%- renderFixture('requests/prepare-payment.json') %>
## Trustline
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/trustline.json') %>
### Example
<%- renderFixture('requests/prepare-trustline.json') %>
## Order
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/order.json') %>
### Example
<%- renderFixture('requests/prepare-order.json') %>
## Order Cancellation
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/order-cancellation.json') %>
### Example
<%- renderFixture('requests/prepare-order-cancellation.json') %>
## Settings
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('output/get-settings.json') %>
### Example
<%- renderFixture('requests/prepare-settings.json') %>
## Suspended Payment Creation
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/suspended-payment-creation.json') %>
### Example
<%- renderFixture('requests/prepare-suspended-payment-creation.json') %>
## Suspended Payment Cancellation
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/suspended-payment-cancellation.json') %>
### Example
<%- renderFixture('requests/prepare-suspended-payment-cancellation.json') %>
## Suspended Payment Execution
See [Transaction Types](#transaction-types) for a description.
<%- renderSchema('specifications/suspended-payment-execution.json') %>
### Example
<%- renderFixture('requests/prepare-suspended-payment-execution.json') %>

25
docs/src/submit.md.ejs Normal file
View File

@@ -0,0 +1,25 @@
## submit
`submit(signedTransaction: string): Promise<Object>`
Submits a signed transaction. The transaction is not guaranteed to succeed; it must be verified with [getTransaction](#gettransaction).
### Parameters
<%- renderSchema('input/submit.json') %>
### Return Value
This method returns an object with the following structure:
<%- renderSchema('output/submit.json') %>
### Example
```javascript
const signedTransaction = '12000322800000002400000017201B0086955368400000000000000C732102F89EAEC7667B30F33D0687BBA86C3FE2A08CCA40A9186C5BDE2DAA6FA97A37D874473045022100BDE09A1F6670403F341C21A77CF35BA47E45CDE974096E1AA5FC39811D8269E702203D60291B9A27F1DCABA9CF5DED307B4F23223E0B6F156991DB601DFB9C41CE1C770A726970706C652E636F6D81145E7B112523F68D2F5E879DB4EAC51C6698A69304';
return api.submit(signedTransaction)
.then(result => {/* ... */});
```
<%- renderFixture('responses/submit.json') %>

View File

@@ -0,0 +1,65 @@
# Transaction Overview
## Transaction Types
A transaction type is specified by the strings in the first column in the table below.
Type | Description
---- | -----------
[payment](#payment) | A `payment` transaction represents a transfer of value from one account to another. Depending on the [path](https://ripple.com/build/paths/) taken, additional exchanges of value may occur atomically to facilitate the payment.
[order](#order) | An `order` transaction creates a limit order. It defines an intent to exchange currencies, and creates an order in the Ripple Consensus Ledger's order book if not completely fulfilled when placed. Orders can be partially fulfilled.
[orderCancellation](#order-cancellation) | An `orderCancellation` transaction cancels an order in the Ripple Consensus Ledger's order book.
[trustline](#trustline) | A `trustline` transactions creates or modifies a trust line between two accounts.
[settings](#settings) | A `settings` transaction modifies the settings of an account in the Ripple Consensus Ledger.
[suspendedPaymentCreation](#suspended-payment-creation) | A `suspendedPaymentCreation` transaction creates a suspended payment on the ledger, which locks XRP until a cryptographic condition is met or it expires. It is like an escrow service where the Ripple network acts as the escrow agent.
[suspendedPaymentCancellation](#suspended-payment-cancellation) | A `suspendedPaymentCancellation` transaction unlocks the funds in a suspended payment and sends them back to the creator of the suspended payment, but it will only work after the suspended payment expires.
[suspendedPaymentExecution](#suspended-payment-execution) | A `suspendedPaymentExecution` transaction unlocks the funds in a suspended payment and sends them to the destination of the suspended payment, but it will only work if the cryptographic condition is provided.
The three "suspended payment" transaction types are not supported by the production Ripple peer-to-peer network at this time. They are available for testing purposes if you [configure RippleAPI](#boilerplate) to connect to the [Ripple Test Net](https://ripple.com/build/ripple-test-net/) instead.
## Transaction Flow
Executing a transaction with `RippleAPI` requires the following four steps:
1. Prepare - Create an unsigned transaction based on a [specification](#transaction-specifications) and [instructions](#transaction-instructions). There is a method to prepare each type of transaction:
* [preparePayment](#preparepayment)
* [prepareTrustline](#preparetrustline)
* [prepareOrder](#prepareorder)
* [prepareOrderCancellation](#prepareordercancellation)
* [prepareSettings](#preparesettings)
* [prepareSuspendedPaymentCreation](#preparesuspendedpaymentcreation)
* [prepareSuspendedPaymentCancellation](#preparesuspendedpaymentcancellation)
* [prepareSuspendedPaymentExecution](#preparesuspendedpaymentexecution)
2. [Sign](#sign) - Cryptographically sign the transaction locally and save the [transaction ID](#transaction-id). Signing is how the owner of an account authorizes a transaction to take place. For multisignature transactions, the `signedTransaction` fields returned by `sign` must be collected and passed to the [combine](#combine) method.
3. [Submit](#submit) - Submit the transaction to the connected server.
4. Verify - Verify that the transaction got validated by querying with [getTransaction](#gettransaction). This is necessary because transactions may fail even if they were successfully submitted.
## Transaction Fees
Every transaction must destroy a small amount of XRP as a cost to send the transaction. This is also called a *transaction fee*. The transaction cost is designed to increase along with the load on the Ripple network, making it very expensive to deliberately or inadvertently overload the network.
You can choose the size of the fee you want to pay or let a default be used. You can get an estimate of the fee required to be included in the next ledger closing with the [getFee](#getfee) method.
## Transaction Instructions
Transaction instructions indicate how to execute a transaction, complementary with the [transaction specification](#transaction-specifications).
<%- renderSchema("objects/instructions.json") %>
We recommended that you specify a `maxLedgerVersion` so that you can quickly determine that a failed transaction will never succeeed in the future. It is impossible for a transaction to succeed after the network ledger version exceeds the transaction's `maxLedgerVersion`. If you omit `maxLedgerVersion`, the "prepare*" method automatically supplies a `maxLedgerVersion` equal to the current ledger plus 3, which it includes in the return value from the "prepare*" method.
## Transaction ID
```json
"F4AB442A6D4CBB935D66E1DA7309A5FC71C7143ED4049053EC14E3875B0CF9BF"
```
A transaction ID is a 64-bit hexadecimal string that uniquely identifies the transaction. The transaction ID is derived from the transaction instruction and specifications, using a strong hash function.
You can look up a transaction by ID using the [getTransaction](#gettransaction) method.
## Transaction Memos
Every transaction can optionally have an array of memos for user applications. The `memos` field in each [transaction specification](#transaction-specifications) is an array of objects with the following structure:
<%- renderSchema('objects/memos.json') %>

View File

@@ -1,5 +0,0 @@
{
"version": "independent",
"useWorkspaces": true,
"npmClient": "npm"
}

4144
npm-shrinkwrap.json generated Normal file

File diff suppressed because it is too large Load Diff

32277
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,76 +1,90 @@
{
"name": "xrpl.js",
"private": true,
"scripts": {
"test": "lerna run test --stream",
"test:browser": "lerna run test:browser --stream",
"test:integration": "lerna run test:integration --stream",
"lint": "lerna run lint --stream",
"clean": "lerna run clean --stream",
"build": "lerna run build --stream",
"docgen": "lerna run docgen --stream"
"name": "ripple-lib",
"version": "0.17.3",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [
"dist/npm/*",
"bin/*",
"build/*",
"test/*",
"Gulpfile.js"
],
"main": "dist/npm/",
"directories": {
"test": "test"
},
"dependencies": {
"ripple-address-codec": "file:packages/ripple-address-codec",
"ripple-binary-codec": "file:packages/ripple-binary-codec",
"ripple-keypairs": "file:packages/ripple-keypairs",
"xrpl": "file:packages/xrpl"
"ajv": "^4.0.5",
"ajv-i18n": "^1.2.0",
"babel-polyfill": "^6.3.14",
"babel-runtime": "^6.3.19",
"bignumber.js": "^2.0.3",
"https-proxy-agent": "^1.0.0",
"jayson": "^1.2.2",
"lodash": "^3.1.0",
"ripple-address-codec": "^2.0.1",
"ripple-binary-codec": "^0.1.4",
"ripple-hashes": "^0.1.0",
"ripple-keypairs": "^0.10.0",
"ripple-lib-transactionparser": "^0.6.0",
"ws": "^1.0.1"
},
"devDependencies": {
"@types/chai": "^4.2.21",
"@types/lodash": "^4.14.136",
"@types/mocha": "^9.0.0",
"@types/node": "^16.4.3",
"@types/puppeteer": "5.4.4",
"@types/ws": "^8.2.0",
"@typescript-eslint/eslint-plugin": "^4.30.0",
"@typescript-eslint/parser": "^4.0.0",
"@xrplf/eslint-config": "^1.6.0",
"@xrplf/prettier-config": "^1.5.0",
"assert": "^2.0.0",
"buffer": "^6.0.2",
"chai": "^4.3.4",
"crypto-browserify": "^3.12.0",
"ejs": "^3.0.1",
"eslint": "^7.5.0",
"eslint-plugin-array-func": "^3.1.7",
"eslint-plugin-consistent-default-export-name": "^0.0.13",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.24.1",
"eslint-plugin-jsdoc": "^36.0.0",
"eslint-plugin-mocha": "^9.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-tsdoc": "^0.2.14",
"eventemitter2": "^6.0.0",
"https-browserify": "^1.0.0",
"jest": "^26.0.1",
"lerna": "^4.0.0",
"mocha": "^9",
"npm-run-all": "^4.1.5",
"nyc": "^15",
"path-browserify": "1.0.1",
"prettier": "^2.3.2",
"process": "^0.11.10",
"puppeteer": "10.4.0",
"source-map-support": "^0.5.16",
"stream-browserify": "^3.0.0",
"stream-http": "3.2.0",
"ts-jest": "^26.4.4",
"ts-loader": "^9.2.5",
"ts-node": "^10.2.1",
"typedoc": "^0.22.5",
"typescript": "^4.4.2",
"url": "^0.11.0",
"webpack": "^5.6.0",
"webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^4.2.0"
"assert-diff": "^1.0.1",
"babel-cli": "^6.4.0",
"babel-core": "^6.4.0",
"babel-eslint": "^6.0.4",
"babel-loader": "^6.2.1",
"babel-plugin-syntax-flow": "^6.3.13",
"babel-plugin-transform-flow-strip-types": "^6.4.0",
"babel-preset-es2015": "^6.3.13",
"babel-preset-stage-1": "^6.3.13",
"babel-register": "^6.3.13",
"coveralls": "^2.11.9",
"doctoc": "^0.15.0",
"ejs": "^2.3.4",
"eslint": "^2.9.0",
"eventemitter2": "^0.4.14",
"flow-bin": "^0.30.0",
"gulp": "^3.8.10",
"gulp-bump": "^0.1.13",
"gulp-rename": "^1.2.0",
"gulp-uglify": "^1.1.0",
"http-server": "^0.8.5",
"istanbul": "^1.1.0-alpha.1",
"json-loader": "^0.5.2",
"json-schema-to-markdown-table": "^0.4.0",
"mocha": "^2.1.0",
"mocha-in-sauce": "^0.0.1",
"mocha-junit-reporter": "^1.9.1",
"null-loader": "^0.1.1",
"webpack": "^1.5.3",
"yargs": "^1.3.1"
},
"workspaces": [
"packages/*"
],
"scripts": {
"build": "gulp",
"doctoc": "doctoc docs/index.md --title '# RippleAPI Reference' --github --maxlevel 2",
"docgen": "node --harmony scripts/build_docs.js",
"clean": "rm -rf dist/npm && rm -rf build/flow",
"typecheck": "babel --optional runtime --blacklist flow -d build/flow/ src/ && flow check",
"compile": "babel -D --optional runtime -d dist/npm/ src/",
"watch": "babel -w -D --optional runtime -d dist/npm/ src/",
"compile-with-source-maps": "babel -D --optional runtime -s -t -d dist/npm/ src/",
"prepublish": "npm run clean && npm run compile",
"test": "babel-node ./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'parser: babel-eslint' >> eslintrc; fi; eslint -c eslintrc src/",
"perf": "./scripts/perf_test.sh",
"start": "babel-node scripts/http.js",
"sauce": "babel-node scripts/sauce-runner.js"
},
"repository": {
"type": "git",
"url": "git://github.com/ripple/ripple-lib.git"
},
"readmeFilename": "README.md",
"engines": {
"node": ">=10.0.0",
"npm": ">=7.0.0 < 8.0.0"
"node": ">=0.12.0"
}
}

View File

@@ -1,12 +0,0 @@
# Don't ever lint node_modules
node_modules
# Don't lint build output
dist
# don't lint nyc coverage output
coverage
.nyc_output
# Don't lint NYC configuration
nyc.config.js

View File

@@ -1,85 +0,0 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser', // Make ESLint compatible with TypeScript
parserOptions: {
// Enable linting rules with type information from our tsconfig
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
sourceType: 'module', // Allow the use of imports / ES modules
ecmaFeatures: {
impliedStrict: true, // Enable global strict mode
},
},
// Specify global variables that are predefined
env: {
browser: true, // Enable browser global variables
node: true, // Enable node global variables & Node.js scoping
es2020: true, // Add all ECMAScript 2020 globals and automatically set the ecmaVersion parser option to ES2020
},
plugins: [],
extends: ['@xrplf/eslint-config/base'],
rules: {
// ** TODO **
// all of the below are turned off for now during the migration to a
// monorepo. They need to actually be addressed!
// **
'@typescript-eslint/no-for-in-array': 'off',
'@typescript-eslint/consistent-type-assertions': 'off',
'@typescript-eslint/no-unnecessary-condition': 'off',
'@typescript-eslint/prefer-for-of': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-magic-numbers': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/promise-function-async': 'off',
'@typescript-eslint/prefer-nullish-coalescing': 'off',
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/restrict-plus-operands': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
'jsdoc/require-returns': 'off',
'jsdoc/check-param-names': 'off',
'jsdoc/require-throws': 'off',
'jsdoc/require-hyphen-before-param-description': 'off',
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-description-complete-sentence': 'off',
'jsdoc/require-param': 'off',
'jsdoc/no-types': 'off',
'tsdoc/syntax': 'off',
'import/no-commonjs': 'off',
'import/order': 'off',
'no-restricted-syntax': 'off',
'guard-for-in': 'off',
'object-shorthand': 'off',
'no-negated-condition': 'off',
'no-loop-func': 'off',
'id-length': 'off',
'no-inline-comments': 'off',
'max-lines-per-function': 'off',
'max-len': 'off',
'no-nested-ternary': 'off',
'no-param-reassign': 'off',
'no-bitwise': 'off',
'multiline-comment-style': 'off',
'id-blacklist': 'off',
'func-names': 'off',
'max-params': 'off',
'prefer-template': 'off',
'no-else-return': 'off',
},
}

View File

@@ -1,61 +0,0 @@
# .gitignore
# Ignore vim swap files.
*.swp
# Ignore SCons support files.
.sconsign.dblite
# Ignore python compiled files.
*.pyc
# Ignore Macintosh Desktop Services Store files.
.DS_Store
# Ignore backup/temps
*~
# Ignore object files.
*.o
build/
tags
bin/rippled
Debug/*.*
Release/*.*
# Ignore locally installed node_modules
node_modules
!test/node_modules
# Ignore tmp directory.
tmp
# Ignore database directory.
db/*.db
db/*.db-*
# Ignore customized configs
rippled.cfg
validators.txt
test/config.js
# Ignore coverage files
/lib-cov
/src-cov
/coverage.html
/coverage
# Ignore IntelliJ files
.idea
# Ignore npm-debug
npm-debug.log
# Ignore dist folder
dist/
# Ignore flow output directory
out/
# Ignore perf test cache
scripts/cache

View File

@@ -1,64 +0,0 @@
# ripple-address-cod
## 4.1.3 (2021-05-10)
* Update dependencies
* Add `build` script as an alias for `compile`
* Update README
## 4.1.2 (2021-01-11)
* Internal dependencies
* Update jest, ts-jest, typescript, lodash
* Fix potential moderate severity vulnerabilities
* Update @types/node, @types/jest, base-x
* Docs
* Update example for encoding test address
* Document functions (#73)
* xAddressToClassicAddress when there is no tag (#114)
* Add README badges (#120)
* Add LICENSE (#138)
* Cleanup and polish
* Add GitHub CI (#115)
* Fix linting
## 4.1.1 (2020-04-03)
* Require node v10+
* CI: Drop node 6 & 8 and add node 13
* Update dependencies
* Bump @types/node to 13.7.7 (#60)
* Bump jest and ts-jest (#40)
* Bump @types/jest to 25.1.2 (#51)
* Bump ts-jest from 25.0.0 to 25.2.0 (#50)
* Bump typescript from 3.7.5 to 3.8.3 (#61)
* Update all dependencies in yarn.lock
## 4.1.0 (2020-01-22)
* Throwable 'unexpected_payload_length' error: The message has been expanded with ' Ensure that the bytes are a Buffer.'
* Docs (readme): Correct X-address to classic address example (#15) (thanks @RareData)
### New Features
* `encodeAccountPublic` - Encode a public key, as for payment channels
* `decodeAccountPublic` - Decode a public key, as for payment channels
* Internal
* Update dependencies: ts-jest, @types/jest, @types/node, typescript, tslint,
base-x
## 4.0.0 (2019-10-08)
### Breaking Changes
* `decodeAddress` has been renamed to `decodeAccountID`
* `isValidAddress` has been renamed to `isValidClassicAddress`
### New Features
* `classicAddressToXAddress` - Derive X-address from classic address, tag, and network ID
* `encodeXAddress` - Encode account ID, tag, and network ID as an X-address
* `xAddressToClassicAddress` - Decode an X-address to account ID, tag, and network ID
* `decodeXAddress` - Convert X-address to classic address, tag, and network ID
* `isValidXAddress` - Check whether an X-address (X...) is valid

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 Ripple Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,196 +0,0 @@
# ripple-address-codec
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Functions for encoding and decoding XRP Ledger addresses and seeds.
Also includes support for encoding/decoding [rippled validator (node) public keys](https://xrpl.org/run-rippled-as-a-validator.html).
[![NPM](https://nodei.co/npm/ripple-address-codec.png)](https://www.npmjs.org/package/ripple-address-codec)
## X-address Conversion
All tools and apps in the XRP Ledger ecosystem are encouraged to adopt support for the X-address format. The X-address format is a single Base58 string that encodes an 'Account ID', a (destination) tag, and whether the address is intended for a test network. This prevents users from unintentionally omitting the destination tag when sending and receiving payments and other transactions.
## API
### classicAddressToXAddress(classicAddress: string, tag: number | false, test: boolean): string
Convert a classic address and (optional) tag to an X-address. If `tag` is `false`, the returned X-address explicitly indicates that the recipient does not want a tag to be used. If `test` is `true`, consumers of the address will know that the address is intended for use on test network(s) and the address will start with `T`.
```js
> const api = require('ripple-address-codec')
> api.classicAddressToXAddress('rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf', 4294967295)
'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi'
```
Encode a test address e.g. for use with [Testnet or Devnet](https://xrpl.org/xrp-testnet-faucet.html):
```js
> const api = require('ripple-address-codec')
> api.classicAddressToXAddress('r3SVzk8ApofDJuVBPKdmbbLjWGCCXpBQ2g', 123, true)
'T7oKJ3q7s94kDH6tpkBowhetT1JKfcfdSCmAXbS75iATyLD'
```
### xAddressToClassicAddress(xAddress: string): {classicAddress: string, tag: number | false, test: boolean}
Convert an X-address to a classic address and tag. If the X-address did not have a tag, the returned object's `tag` will be `false`. (Since `0` is a valid tag, instead of `if (tag)`, use `if (tag !== false)` if you want to check for a tag.) If the X-address is intended for use on test network(s), `test` will be `true`; if it is intended for use on the main network (mainnet), `test` will be `false`.
```js
> const api = require('ripple-address-codec')
> api.xAddressToClassicAddress('XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi')
{
classicAddress: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
tag: 4294967295,
test: false
}
```
### isValidXAddress(xAddress: string): boolean
Returns `true` if the provided X-address is valid, or `false` otherwise.
```js
> const api = require('ripple-address-codec')
> api.isValidXAddress('XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi')
true
```
Returns `false` for classic addresses (starting with `r`). To validate a classic address, use `isValidClassicAddress`.
### isValidClassicAddress(address: string): boolean
Check whether a classic address (starting with `r`...) is valid.
Returns `false` for X-addresses (extended addresses). To validate an X-address, use `isValidXAddress`.
### encodeSeed(entropy: Buffer, type: 'ed25519' | 'secp256k1'): string
Encode the given entropy as an XRP Ledger seed (secret). The entropy must be exactly 16 bytes (128 bits). The encoding includes which elliptic curve digital signature algorithm (ECDSA) the seed is intended to be used with. The seed is used to produce the private key.
### decodeSeed(seed: string): object
Decode a seed into an object with its version, type, and bytes.
Return object type:
```
{
version: number[],
bytes: Buffer,
type: string | null
}
```
### encodeAccountID(bytes: Buffer): string
Encode bytes as a classic address (starting with `r`...).
### decodeAccountID(accountId: string): Buffer
Decode a classic address (starting with `r`...) to its raw bytes.
### encodeNodePublic(bytes: Buffer): string
Encode bytes to the XRP Ledger "node public key" format (base58).
This is useful for rippled validators.
### decodeNodePublic(base58string: string): Buffer
Decode an XRP Ledger "node public key" (in base58 format) into its raw bytes.
### encodeAccountPublic(bytes: Buffer): string
Encode a public key, as for payment channels.
### decodeAccountPublic(base58string: string): Buffer
Decode a public key, as for payment channels.
### encodeXAddress(accountId: Buffer, tag: number | false, test: boolean): string
Encode account ID, tag, and network ID to X-address.
`accountId` must be 20 bytes because it is a RIPEMD160 hash, which is 160 bits (160 bits = 20 bytes).
At this time, `tag` must be <= MAX_32_BIT_UNSIGNED_INT (4294967295) as the XRP Ledger only supports 32-bit tags.
If `test` is `true`, this address is intended for use with a test network such as Testnet or Devnet.
### decodeXAddress(xAddress: string): {accountId: Buffer, tag: number | false, test: boolean}
Convert an X-address to its classic address, tag, and network ID.
### Other functions
```js
> var api = require('ripple-address-codec');
> api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
{ version: [ 1, 225, 75 ],
bytes: [ 76, 58, 29, 33, 63, 189, 251, 20, 199, 194, 141, 96, 148, 105, 179, 65 ],
type: 'ed25519' }
> api.decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL')
{ version: 33,
bytes: [ 207, 45, 227, 120, 251, 221, 126, 46, 232, 125, 72, 109, 251, 90, 123, 255 ],
type: 'secp256k1' }
> api.decodeAccountID('rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN')
[ 186,
142,
120,
98,
110,
228,
44,
65,
180,
109,
70,
195,
4,
141,
243,
161,
195,
200,
112,
114 ]
```
## Tests
Run unit tests with:
npm test
Use `--watch` to run in watch mode, so that when you modify the tests, they are automatically re-run:
npm test -- --watch
Use `--coverage` to generate and display code coverage information:
npm test -- --coverage
This tells jest to output code coverage info in the `./coverage` directory, in addition to showing it on the command line.
## Releases
Use the [ripple-lib release checklist](https://github.com/ripple/ripple-lib/wiki/Release-Checklist), but just use `master` instead of `develop` as this project does not use a develop branch.
## Acknowledgements
This library references and adopts code and standards from the following sources:
- [XLS-5d Standard for Tagged Addresses](https://github.com/xrp-community/standards-drafts/issues/6) by @nbougalis
- [XRPL Tagged Address Codec](https://github.com/xrp-community/xrpl-tagged-address-codec) by @WietseWind
- [X-Address transaction functions](https://github.com/codetsunami/xrpl-tools/tree/master/xaddress-functions) by @codetsunami
[coveralls-image]: https://badgen.net/coveralls/c/github/ripple/ripple-address-codec/master
[coveralls-url]: https://coveralls.io/r/ripple/ripple-address/codec?branch=master
[npm-downloads-image]: https://badgen.net/npm/dm/ripple-address-codec
[npm-url]: https://npmjs.org/package/ripple-address-codec
[npm-version-image]: https://badgen.net/npm/v/ripple-address-codec
[travis-image]: https://badgen.net/travis/ripple/ripple-address-codec/master
[travis-url]: https://travis-ci.org/github/ripple/ripple-address-codec

View File

@@ -1,10 +0,0 @@
var api = require('../');
var pubVersion = [0x04, 0x88, 0xB2, 0x1E];
var options = {version: pubVersion, alphabet: 'bitcoin'};
var key = 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5e4cp9LB';
var decoded = api.decode(key, options);
var reencoded = api.encode(decoded, options);
console.log(key);
// 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5e4cp9LB'
console.log(reencoded);
// 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5e4cp9LB'

View File

@@ -1,8 +0,0 @@
module.exports = {
"roots": [
"<rootDir>/src"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
}

View File

@@ -1,33 +0,0 @@
{
"name": "ripple-address-codec",
"version": "4.2.0",
"description": "encodes/decodes base58 encoded XRP Ledger identifiers",
"files": [
"dist/*",
"build/*"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "ISC",
"dependencies": {
"base-x": "3.0.9",
"create-hash": "^1.1.2"
},
"repository": {
"type": "git",
"url": "git@github.com:XRPLF/xrpl.js.git"
},
"prepublish": "tsc -b",
"prepublishOnly": "tslint -b ./ && jest",
"scripts": {
"build": "tsc -b",
"test": "jest",
"lint": "eslint . --ext .ts",
"clean": "rm -rf ./dist && rm -rf tsconfig.tsbuildinfo"
},
"prettier": "@xrplf/prettier-config",
"engines": {
"node": ">= 10",
"npm": ">=7.0.0"
}
}

View File

@@ -1,259 +0,0 @@
const {
classicAddressToXAddress,
xAddressToClassicAddress,
isValidXAddress,
encodeXAddress
} = require('./index')
const testCases = [
[
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
false,
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
'T719a5UwUCnEs54UsxG9CJYYDhwmFCqkr7wxCcNcfZ6p5GZ'
],
[
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
1,
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaGZMhc9YTE92ehJ2Fu',
'T719a5UwUCnEs54UsxG9CJYYDhwmFCvbJNZbi37gBGkRkbE'
],
[
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
14,
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaGo2K5VpXpmCqbV2gS',
'T719a5UwUCnEs54UsxG9CJYYDhwmFCvqXVCALUGJGSbNV3x'
],
[
'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59',
11747,
'X7AcgcsBL6XDcUb289X4mJ8djcdyKaLFuhLRuNXPrDeJd9A',
'T719a5UwUCnEs54UsxG9CJYYDhwmFCziiNHtUukubF2Mg6t'
],
[
'rLczgQHxPhWtjkaQqn3Q6UM8AbRbbRvs5K',
false,
'XVZVpQj8YSVpNyiwXYSqvQoQqgBttTxAZwMcuJd4xteQHyt',
'TVVrSWtmQQssgVcmoMBcFQZKKf56QscyWLKnUyiuZW8ALU4'
],
[
'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
false,
'X7YenJqxv3L66CwhBSfd3N8RzGXxYqPopMGMsCcpho79rex',
'T77wVQzA8ntj9wvCTNiQpNYLT5hmhRsFyXDoMLqYC4BzQtV'
],
[
'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
58,
'X7YenJqxv3L66CwhBSfd3N8RzGXxYqV56ZkTCa9UCzgaao1',
'T77wVQzA8ntj9wvCTNiQpNYLT5hmhR9kej6uxm4jGcQD7rZ'
],
[
'rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW',
23480,
'X7d3eHCXzwBeWrZec1yT24iZerQjYL8m8zCJ16ACxu1BrBY',
'T7YChPFWifjCAXLEtg5N74c7fSAYsvSokwcmBPBUZWhxH5P'
],
[
'rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW',
11747,
'X7d3eHCXzwBeWrZec1yT24iZerQjYLo2CJf8oVC5CMWey5m',
'T7YChPFWifjCAXLEtg5N74c7fSAYsvTcc7nEfwuEEvn5Q4w'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
false,
'XVLhHMPHU98es4dbozjVtdWzVrDjtV5fdx1mHp98tDMoQXb',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQn49b3qD26PK7FcGSKE'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
0,
'XVLhHMPHU98es4dbozjVtdWzVrDjtV8AqEL4xcZj5whKbmc',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnSy8RHqGHoGJ59spi2'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
1,
'XVLhHMPHU98es4dbozjVtdWzVrDjtV8xvjGQTYPiAx6gwDC',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnSz1uDimDdPYXzSpyw'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
2,
'XVLhHMPHU98es4dbozjVtdWzVrDjtV8zpDURx7DzBCkrQE7',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnTryP9tG9TW8GeMBmd'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
32,
'XVLhHMPHU98es4dbozjVtdWzVrDjtVoYiC9UvKfjKar4LJe',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnT2oqaCDzMEuCDAj1j'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
276,
'XVLhHMPHU98es4dbozjVtdWzVrDjtVoKj3MnFGMXEFMnvJV',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnTMgJJYfAbsiPsc6Zg'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
65591,
'XVLhHMPHU98es4dbozjVtdWzVrDjtVozpjdhPQVdt3ghaWw',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQn7ryu2W6njw7mT1jmS'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
16781933,
'XVLhHMPHU98es4dbozjVtdWzVrDjtVqrDUk2vDpkTjPsY73',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnVsw45sDtGHhLi27Qa'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
4294967294,
'XVLhHMPHU98es4dbozjVtdWzVrDjtV1kAsixQTdMjbWi39u',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnX8tDFQ53itLNqs6vU'
],
[
'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
4294967295,
'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
'TVE26TYGhfLC7tQDno7G8dGtxSkYQnXoy6kSDh6rZzApc69'
],
[
'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY',
false,
'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD2gYsjNFQLKYW33DzBm',
'TVd2rqMkYL2AyS97NdELcpeiprNBjwLZzuUG5rZnaewsahi'
],
[
'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY',
0,
'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD2m4Er6SnvjVLpMWPjR',
'TVd2rqMkYL2AyS97NdELcpeiprNBjwRQUBetPbyrvXSTuxU'
],
[
'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY',
13371337,
'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD2qwGkhgc48zzcx6Gkr',
'TVd2rqMkYL2AyS97NdELcpeiprNBjwVUDvp3vhpXbNhLwJi'
]
]
;[false, true].forEach(isTestAddress => {
const MAX_32_BIT_UNSIGNED_INT = 4294967295
const network = isTestAddress ? ' (test)' : ' (main)'
for (const i in testCases) {
const testCase = testCases[i]
const classicAddress = testCase[0]
const tag = testCase[1] !== false ? testCase[1] : false
const xAddress = isTestAddress ? testCase[3] : testCase[2]
test(`Converts ${classicAddress}${tag ? ':' + tag : ''} to ${xAddress}${network}`, () => {
expect(classicAddressToXAddress(classicAddress, tag, isTestAddress)).toBe(xAddress)
const myClassicAddress = xAddressToClassicAddress(xAddress)
expect(myClassicAddress).toEqual({
classicAddress,
tag,
test: isTestAddress
})
expect(isValidXAddress(xAddress)).toBe(true)
})
}
{
const classicAddress = 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf'
const tag = MAX_32_BIT_UNSIGNED_INT + 1
test(`Converting ${classicAddress}:${tag}${network} throws`, () => {
expect(() => {
classicAddressToXAddress(classicAddress, tag, isTestAddress)
}).toThrowError(new Error('Invalid tag'))
})
}
{
const classicAddress = 'r'
test(`Invalid classic address: Converting ${classicAddress}${network} throws`, () => {
expect(() => {
classicAddressToXAddress(classicAddress, false, isTestAddress)
}).toThrowError(new Error('invalid_input_size: decoded data must have length >= 5'))
})
}
{
const highAndLowAccounts = [
Buffer.from('00'.repeat(20), 'hex'),
Buffer.from('00'.repeat(19) + '01', 'hex'),
Buffer.from('01'.repeat(20), 'hex'),
Buffer.from('FF'.repeat(20), 'hex')
]
highAndLowAccounts.forEach(accountId => {
[false, 0, 1, MAX_32_BIT_UNSIGNED_INT].forEach(t => {
const tag = (t | false)
const xAddress = encodeXAddress(accountId, tag, isTestAddress)
test(`Encoding ${accountId.toString('hex')}${tag ? ':' + tag : ''} to ${xAddress} has expected length`, () => {
expect(xAddress.length).toBe(47)
})
})
})
}
})
{
const xAddress = 'XVLhHMPHU98es4dbozjVtdWzVrDjtV5fdx1mHp98tDMoQXa'
test(`Invalid X-address (bad checksum): Converting ${xAddress} throws`, () => {
expect(() => {
xAddressToClassicAddress(xAddress)
}).toThrowError(new Error('checksum_invalid'))
})
}
{
const xAddress = 'dGzKGt8CVpWoa8aWL1k18tAdy9Won3PxynvbbpkAqp3V47g'
test(`Invalid X-address (bad prefix): Converting ${xAddress} throws`, () => {
expect(() => {
xAddressToClassicAddress(xAddress)
}).toThrowError(new Error('Invalid X-address: bad prefix'))
})
}
test(`Invalid X-address (64-bit tag) throws`, () => {
expect(() => {
// Encoded from:
// {
// classicAddress: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
// tag: MAX_32_BIT_UNSIGNED_INT + 1
// }
xAddressToClassicAddress('XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8zeUygYrCgrPh')
}).toThrowError('Unsupported X-address')
})
test(`Invalid Account ID throws`, () => {
expect(() => {
encodeXAddress(Buffer.from('00'.repeat(19), 'hex'), false, false)
}).toThrowError('Account ID must be 20 bytes')
})
test(`isValidXAddress returns false for invalid X-address`, () => {
expect(isValidXAddress('XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8zeUygYrCgrPh')).toBe(false)
})
test(`Converts X7AcgcsBL6XDcUb... to r9cZA1mLK5R5A... and tag: false`, () => {
const classicAddress = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59'
const tag = false
const xAddress = 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ'
const isTestAddress = false
expect(classicAddressToXAddress(classicAddress, tag, isTestAddress)).toBe(xAddress)
const myClassicAddress = xAddressToClassicAddress(xAddress)
expect(myClassicAddress).toEqual({
classicAddress,
tag,
test: isTestAddress
})
expect(isValidXAddress(xAddress)).toBe(true)
// Notice that converting an X-address to a classic address has `result.tag === false` (not undefined)
expect(myClassicAddress.tag).toEqual(false)
})

View File

@@ -1,149 +0,0 @@
import {
codec,
encodeSeed,
decodeSeed,
encodeAccountID,
decodeAccountID,
encodeNodePublic,
decodeNodePublic,
encodeAccountPublic,
decodeAccountPublic,
isValidClassicAddress,
} from './xrp-codec'
import * as assert from 'assert'
const PREFIX_BYTES = {
MAIN: Buffer.from([0x05, 0x44]), // 5, 68
TEST: Buffer.from([0x04, 0x93]), // 4, 147
}
function classicAddressToXAddress(
classicAddress: string,
tag: number | false,
test: boolean,
): string {
const accountId = decodeAccountID(classicAddress)
return encodeXAddress(accountId, tag, test)
}
function encodeXAddress(
accountId: Buffer,
tag: number | false,
test: boolean,
): string {
if (accountId.length !== 20) {
// RIPEMD160 is 160 bits = 20 bytes
throw new Error('Account ID must be 20 bytes')
}
const MAX_32_BIT_UNSIGNED_INT = 4294967295
const flag = tag === false ? 0 : tag <= MAX_32_BIT_UNSIGNED_INT ? 1 : 2
if (flag === 2) {
throw new Error('Invalid tag')
}
if (tag === false) {
tag = 0
}
const bytes = Buffer.concat([
test ? PREFIX_BYTES.TEST : PREFIX_BYTES.MAIN,
accountId,
Buffer.from([
flag, // 0x00 if no tag, 0x01 if 32-bit tag
tag & 0xff, // first byte
(tag >> 8) & 0xff, // second byte
(tag >> 16) & 0xff, // third byte
(tag >> 24) & 0xff, // fourth byte
0,
0,
0,
0, // four zero bytes (reserved for 64-bit tags)
]),
])
const xAddress = codec.encodeChecked(bytes)
return xAddress
}
function xAddressToClassicAddress(xAddress: string): {
classicAddress: string
tag: number | false
test: boolean
} {
const { accountId, tag, test } = decodeXAddress(xAddress)
const classicAddress = encodeAccountID(accountId)
return {
classicAddress,
tag,
test,
}
}
function decodeXAddress(xAddress: string): {
accountId: Buffer
tag: number | false
test: boolean
} {
const decoded = codec.decodeChecked(xAddress)
const test = isBufferForTestAddress(decoded)
const accountId = decoded.slice(2, 22)
const tag = tagFromBuffer(decoded)
return {
accountId,
tag,
test,
}
}
function isBufferForTestAddress(buf: Buffer): boolean {
const decodedPrefix = buf.slice(0, 2)
if (PREFIX_BYTES.MAIN.equals(decodedPrefix)) {
return false
} else if (PREFIX_BYTES.TEST.equals(decodedPrefix)) {
return true
} else {
throw new Error('Invalid X-address: bad prefix')
}
}
function tagFromBuffer(buf: Buffer): number | false {
const flag = buf[22]
if (flag >= 2) {
// No support for 64-bit tags at this time
throw new Error('Unsupported X-address')
}
if (flag === 1) {
// Little-endian to big-endian
return buf[23] + buf[24] * 0x100 + buf[25] * 0x10000 + buf[26] * 0x1000000
}
assert.strictEqual(flag, 0, 'flag must be zero to indicate no tag')
assert.ok(
Buffer.from('0000000000000000', 'hex').equals(buf.slice(23, 23 + 8)),
'remaining bytes must be zero',
)
return false
}
function isValidXAddress(xAddress: string): boolean {
try {
decodeXAddress(xAddress)
} catch (e) {
return false
}
return true
}
export {
codec, // Codec with XRP alphabet
encodeSeed, // Encode entropy as a "seed"
decodeSeed, // Decode a seed into an object with its version, type, and bytes
encodeAccountID, // Encode bytes as a classic address (r...)
decodeAccountID, // Decode a classic address to its raw bytes
encodeNodePublic, // Encode bytes to XRP Ledger node public key format
decodeNodePublic, // Decode an XRP Ledger node public key into its raw bytes
encodeAccountPublic, // Encode a public key, as for payment channels
decodeAccountPublic, // Decode a public key, as for payment channels
isValidClassicAddress, // Check whether a classic address (r...) is valid
classicAddressToXAddress, // Derive X-address from classic address, tag, and network ID
encodeXAddress, // Encode account ID, tag, and network ID to X-address
xAddressToClassicAddress, // Decode X-address to account ID, tag, and network ID
decodeXAddress, // Convert X-address to classic address, tag, and network ID
isValidXAddress, // Check whether an X-address (X...) is valid
}

View File

@@ -1,40 +0,0 @@
const {seqEqual, concatArgs} = require('./utils')
test('two sequences are equal', () => {
expect(seqEqual([1, 2, 3], [1, 2, 3])).toBe(true)
})
test('elements must be in the same order', () => {
expect(seqEqual([3, 2, 1], [1, 2, 3])).toBe(false)
})
test('sequences do not need to be the same type', () => {
expect(seqEqual(Buffer.from([1, 2, 3]), [1, 2, 3])).toBe(true)
expect(seqEqual(Buffer.from([1, 2, 3]), new Uint8Array([1, 2, 3]))).toBe(true)
})
test('sequences with a single element', () => {
expect(seqEqual(Buffer.from([1]), [1])).toBe(true)
expect(seqEqual(Buffer.from([1]), new Uint8Array([1]))).toBe(true)
})
test('empty sequences', () => {
expect(seqEqual(Buffer.from([]), [])).toBe(true)
expect(seqEqual(Buffer.from([]), new Uint8Array([]))).toBe(true)
})
test('plain numbers are concatenated', () => {
expect(concatArgs(10, 20, 30, 40)).toStrictEqual([10, 20, 30, 40])
})
test('a variety of values are concatenated', () => {
expect(concatArgs(1, [2, 3], Buffer.from([4,5]), new Uint8Array([6, 7]))).toStrictEqual([1,2,3,4,5,6,7])
})
test('a single value is returned as an array', () => {
expect(concatArgs(Buffer.from([7]))).toStrictEqual([7])
})
test('no arguments returns an empty array', () => {
expect(concatArgs()).toStrictEqual([])
})

View File

@@ -1,54 +0,0 @@
type Sequence = number[] | Buffer | Uint8Array
/**
* Check whether two sequences (e.g. arrays of numbers) are equal.
*
* @param arr1 One of the arrays to compare.
* @param arr2 The other array to compare.
*/
export function seqEqual(arr1: Sequence, arr2: Sequence): boolean {
if (arr1.length !== arr2.length) {
return false
}
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return false
}
}
return true
}
/**
* Check whether a value is a sequence (e.g. array of numbers).
*
* @param val The value to check.
*/
function isSequence(val: Sequence | number): val is Sequence {
return (val as Sequence).length !== undefined
}
/**
* Concatenate all `arguments` into a single array. Each argument can be either
* a single element or a sequence, which has a `length` property and supports
* element retrieval via sequence[ix].
*
* > concatArgs(1, [2, 3], Buffer.from([4,5]), new Uint8Array([6, 7]));
* [1,2,3,4,5,6,7]
*
* @returns {number[]} Array of concatenated arguments
*/
export function concatArgs(...args: (number | Sequence)[]): number[] {
const ret: number[] = []
args.forEach(function (arg) {
if (isSequence(arg)) {
for (let j = 0; j < arg.length; j++) {
ret.push(arg[j])
}
} else {
ret.push(arg)
}
})
return ret
}

View File

@@ -1,246 +0,0 @@
const api = require('./xrp-codec')
function toHex(bytes) {
return Buffer.from(bytes).toString('hex').toUpperCase()
}
function toBytes(hex) {
return Buffer.from(hex, 'hex')
}
/**
* Create a test case for encoding data and a test case for decoding data.
*
* @param encoder Encoder function to test
* @param decoder Decoder function to test
* @param base58 Base58-encoded string to decode
* @param hex Hexadecimal representation of expected decoded data
*/
function makeEncodeDecodeTest(encoder, decoder, base58, hex) {
test(`can translate between ${hex} and ${base58}`, function() {
const actual = encoder(toBytes(hex))
expect(actual).toBe(base58)
})
test(`can translate between ${base58} and ${hex})`, function() {
const buf = decoder(base58)
expect(toHex(buf)).toBe(hex)
})
}
makeEncodeDecodeTest(api.encodeAccountID, api.decodeAccountID, 'rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN',
'BA8E78626EE42C41B46D46C3048DF3A1C3C87072')
makeEncodeDecodeTest(api.encodeNodePublic, api.decodeNodePublic,
'n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH',
'0388E5BA87A000CB807240DF8C848EB0B5FFA5C8E5A521BC8E105C0F0A44217828')
makeEncodeDecodeTest(api.encodeAccountPublic, api.decodeAccountPublic,
'aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3',
'023693F15967AE357D0327974AD46FE3C127113B1110D6044FD41E723689F81CC6')
test('can decode arbitrary seeds', function() {
const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
expect(toHex(decoded.bytes)).toBe('4C3A1D213FBDFB14C7C28D609469B341')
expect(decoded.type).toBe('ed25519')
const decoded2 = api.decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL')
expect(toHex(decoded2.bytes)).toBe('CF2DE378FBDD7E2EE87D486DFB5A7BFF')
expect(decoded2.type).toBe('secp256k1')
})
test('can pass a type as second arg to encodeSeed', function() {
const edSeed = 'sEdTM1uX8pu2do5XvTnutH6HsouMaM2'
const decoded = api.decodeSeed(edSeed)
const type = 'ed25519'
expect(toHex(decoded.bytes)).toBe('4C3A1D213FBDFB14C7C28D609469B341')
expect(decoded.type).toBe(type)
expect(api.encodeSeed(decoded.bytes, type)).toBe(edSeed)
})
test('isValidClassicAddress - secp256k1 address valid', function() {
expect(api.isValidClassicAddress('rU6K7V3Po4snVhBBaU29sesqs2qTQJWDw1')).toBe(true)
})
test('isValidClassicAddress - ed25519 address valid', function() {
expect(api.isValidClassicAddress('rLUEXYuLiQptky37CqLcm9USQpPiz5rkpD')).toBe(true)
})
test('isValidClassicAddress - invalid', function() {
expect(api.isValidClassicAddress('rU6K7V3Po4snVhBBaU29sesqs2qTQJWDw2')).toBe(false)
})
test('isValidClassicAddress - empty', function() {
expect(api.isValidClassicAddress('')).toBe(false)
})
describe('encodeSeed', function() {
it('encodes a secp256k1 seed', function() {
const result = api.encodeSeed(Buffer.from('CF2DE378FBDD7E2EE87D486DFB5A7BFF', 'hex'), 'secp256k1')
expect(result).toBe('sn259rEFXrQrWyx3Q7XneWcwV6dfL')
})
it('encodes low secp256k1 seed', function() {
const result = api.encodeSeed(Buffer.from('00000000000000000000000000000000', 'hex'), 'secp256k1')
expect(result).toBe('sp6JS7f14BuwFY8Mw6bTtLKWauoUs')
})
it('encodes high secp256k1 seed', function() {
const result = api.encodeSeed(Buffer.from('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 'hex'), 'secp256k1')
expect(result).toBe('saGwBRReqUNKuWNLpUAq8i8NkXEPN')
})
it('encodes an ed25519 seed', function() {
const result = api.encodeSeed(Buffer.from('4C3A1D213FBDFB14C7C28D609469B341', 'hex'), 'ed25519')
expect(result).toBe('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
})
it('encodes low ed25519 seed', function() {
const result = api.encodeSeed(Buffer.from('00000000000000000000000000000000', 'hex'), 'ed25519')
expect(result).toBe('sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE')
})
it('encodes high ed25519 seed', function() {
const result = api.encodeSeed(Buffer.from('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 'hex'), 'ed25519')
expect(result).toBe('sEdV19BLfeQeKdEXyYA4NhjPJe6XBfG')
})
test('attempting to encode a seed with less than 16 bytes of entropy throws', function() {
expect(() => {
api.encodeSeed(Buffer.from('CF2DE378FBDD7E2EE87D486DFB5A7B', 'hex'), 'secp256k1')
}).toThrow('entropy must have length 16')
})
test('attempting to encode a seed with more than 16 bytes of entropy throws', function() {
expect(() => {
api.encodeSeed(Buffer.from('CF2DE378FBDD7E2EE87D486DFB5A7BFFFF', 'hex'), 'secp256k1')
}).toThrow('entropy must have length 16')
})
})
describe('decodeSeed', function() {
it('can decode an Ed25519 seed', function() {
const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
expect(toHex(decoded.bytes)).toBe('4C3A1D213FBDFB14C7C28D609469B341')
expect(decoded.type).toBe('ed25519')
})
it('can decode a secp256k1 seed', function() {
const decoded = api.decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL')
expect(toHex(decoded.bytes)).toBe('CF2DE378FBDD7E2EE87D486DFB5A7BFF')
expect(decoded.type).toBe('secp256k1')
})
})
describe('encodeAccountID', function() {
it('can encode an AccountID', function() {
const encoded = api.encodeAccountID(Buffer.from('BA8E78626EE42C41B46D46C3048DF3A1C3C87072', 'hex'))
expect(encoded).toBe('rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN')
})
test('unexpected length should throw', function() {
expect(() => {
api.encodeAccountID(Buffer.from('ABCDEF', 'hex'))
}).toThrow(
'unexpected_payload_length: bytes.length does not match expectedLength'
)
})
})
describe('decodeNodePublic', function() {
it('can decode a NodePublic', function() {
const decoded = api.decodeNodePublic('n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH')
expect(toHex(decoded)).toBe('0388E5BA87A000CB807240DF8C848EB0B5FFA5C8E5A521BC8E105C0F0A44217828')
})
})
test('encodes 123456789 with version byte of 0', () => {
expect(api.codec.encode(Buffer.from('123456789'), {
versions: [0],
expectedLength: 9
})).toBe('rnaC7gW34M77Kneb78s')
})
test('multiple versions with no expected length should throw', () => {
expect(() => {
api.codec.decode('rnaC7gW34M77Kneb78s', {
versions: [0, 1]
})
}).toThrow('expectedLength is required because there are >= 2 possible versions')
})
test('attempting to decode data with length < 5 should throw', () => {
expect(() => {
api.codec.decode('1234', {
versions: [0]
})
}).toThrow('invalid_input_size: decoded data must have length >= 5')
})
test('attempting to decode data with unexpected version should throw', () => {
expect(() => {
api.codec.decode('rnaC7gW34M77Kneb78s', {
versions: [2]
})
}).toThrow('version_invalid: version bytes do not match any of the provided version(s)')
})
test('invalid checksum should throw', () => {
expect(() => {
api.codec.decode('123456789', {
versions: [0, 1]
})
}).toThrow('checksum_invalid')
})
test('empty payload should throw', () => {
expect(() => {
api.codec.decode('', {
versions: [0, 1]
})
}).toThrow('invalid_input_size: decoded data must have length >= 5')
})
test('decode data', () => {
expect(api.codec.decode('rnaC7gW34M77Kneb78s', {
versions: [0]
})).toStrictEqual({
version: [0],
bytes: Buffer.from('123456789'),
type: null
})
})
test('decode data with expected length', function() {
expect(api.codec.decode('rnaC7gW34M77Kneb78s', {
versions: [0],
expectedLength: 9
})
).toStrictEqual({
version: [0],
bytes: Buffer.from('123456789'),
type: null
})
})
test('decode data with wrong expected length should throw', function() {
expect(() => {
api.codec.decode('rnaC7gW34M77Kneb78s', {
versions: [0],
expectedLength: 8
})
}).toThrow(
'version_invalid: version bytes do not match any of the provided version(s)'
)
expect(() => {
api.codec.decode('rnaC7gW34M77Kneb78s', {
versions: [0],
expectedLength: 10
})
}).toThrow(
'version_invalid: version bytes do not match any of the provided version(s)'
)
})

View File

@@ -1,241 +0,0 @@
/**
* Codec class
*/
import * as baseCodec from 'base-x'
import { seqEqual, concatArgs } from './utils'
class Codec {
sha256: (bytes: Uint8Array) => Buffer
alphabet: string
codec: any
base: number
constructor(options: {
sha256: (bytes: Uint8Array) => Buffer
alphabet: string
}) {
this.sha256 = options.sha256
this.alphabet = options.alphabet
this.codec = baseCodec(this.alphabet)
this.base = this.alphabet.length
}
/**
* Encoder.
*
* @param bytes Buffer of data to encode.
* @param opts Options object including the version bytes and the expected length of the data to encode.
*/
encode(
bytes: Buffer,
opts: {
versions: number[]
expectedLength: number
},
): string {
const versions = opts.versions
return this.encodeVersioned(bytes, versions, opts.expectedLength)
}
encodeVersioned(
bytes: Buffer,
versions: number[],
expectedLength: number,
): string {
if (expectedLength && bytes.length !== expectedLength) {
throw new Error(
'unexpected_payload_length: bytes.length does not match expectedLength.' +
' Ensure that the bytes are a Buffer.',
)
}
return this.encodeChecked(Buffer.from(concatArgs(versions, bytes)))
}
encodeChecked(buffer: Buffer): string {
const check = this.sha256(this.sha256(buffer)).slice(0, 4)
return this.encodeRaw(Buffer.from(concatArgs(buffer, check)))
}
encodeRaw(bytes: Buffer): string {
return this.codec.encode(bytes)
}
/**
* Decoder.
*
* @param base58string Base58Check-encoded string to decode.
* @param opts Options object including the version byte(s) and the expected length of the data after decoding.
*/
decode(
base58string: string,
opts: {
versions: (number | number[])[]
expectedLength?: number
versionTypes?: ['ed25519', 'secp256k1']
},
): {
version: number[]
bytes: Buffer
type: string | null
} {
const versions = opts.versions
const types = opts.versionTypes
const withoutSum = this.decodeChecked(base58string)
if (versions.length > 1 && !opts.expectedLength) {
throw new Error(
'expectedLength is required because there are >= 2 possible versions',
)
}
const versionLengthGuess =
typeof versions[0] === 'number' ? 1 : (versions[0] as number[]).length
const payloadLength =
opts.expectedLength || withoutSum.length - versionLengthGuess
const versionBytes = withoutSum.slice(0, -payloadLength)
const payload = withoutSum.slice(-payloadLength)
for (let i = 0; i < versions.length; i++) {
const version: number[] = Array.isArray(versions[i])
? (versions[i] as number[])
: [versions[i] as number]
if (seqEqual(versionBytes, version)) {
return {
version,
bytes: payload,
type: types ? types[i] : null,
}
}
}
throw new Error(
'version_invalid: version bytes do not match any of the provided version(s)',
)
}
decodeChecked(base58string: string): Buffer {
const buffer = this.decodeRaw(base58string)
if (buffer.length < 5) {
throw new Error('invalid_input_size: decoded data must have length >= 5')
}
if (!this.verifyCheckSum(buffer)) {
throw new Error('checksum_invalid')
}
return buffer.slice(0, -4)
}
decodeRaw(base58string: string): Buffer {
return this.codec.decode(base58string)
}
verifyCheckSum(bytes: Buffer): boolean {
const computed = this.sha256(this.sha256(bytes.slice(0, -4))).slice(0, 4)
const checksum = bytes.slice(-4)
return seqEqual(computed, checksum)
}
}
/**
* XRP codec
*/
// Pure JavaScript hash functions in the browser, native hash functions in Node.js
const createHash = require('create-hash')
// base58 encodings: https://xrpl.org/base58-encodings.html
const ACCOUNT_ID = 0 // Account address (20 bytes)
const ACCOUNT_PUBLIC_KEY = 0x23 // Account public key (33 bytes)
const FAMILY_SEED = 0x21 // 33; Seed value (for secret keys) (16 bytes)
const NODE_PUBLIC = 0x1c // 28; Validation public key (33 bytes)
const ED25519_SEED = [0x01, 0xe1, 0x4b] // [1, 225, 75]
const codecOptions = {
sha256: function (bytes: Uint8Array) {
return createHash('sha256').update(Buffer.from(bytes)).digest()
},
alphabet: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
}
const codecWithXrpAlphabet = new Codec(codecOptions)
export const codec = codecWithXrpAlphabet
// entropy is a Buffer of size 16
// type is 'ed25519' or 'secp256k1'
export function encodeSeed(
entropy: Buffer,
type: 'ed25519' | 'secp256k1',
): string {
if (entropy.length !== 16) {
throw new Error('entropy must have length 16')
}
const opts = {
expectedLength: 16,
// for secp256k1, use `FAMILY_SEED`
versions: type === 'ed25519' ? ED25519_SEED : [FAMILY_SEED],
}
// prefixes entropy with version bytes
return codecWithXrpAlphabet.encode(entropy, opts)
}
export function decodeSeed(
seed: string,
opts: {
versionTypes: ['ed25519', 'secp256k1']
versions: (number | number[])[]
expectedLength: number
} = {
versionTypes: ['ed25519', 'secp256k1'],
versions: [ED25519_SEED, FAMILY_SEED],
expectedLength: 16,
},
) {
return codecWithXrpAlphabet.decode(seed, opts)
}
export function encodeAccountID(bytes: Buffer): string {
const opts = { versions: [ACCOUNT_ID], expectedLength: 20 }
return codecWithXrpAlphabet.encode(bytes, opts)
}
export const encodeAddress = encodeAccountID
export function decodeAccountID(accountId: string): Buffer {
const opts = { versions: [ACCOUNT_ID], expectedLength: 20 }
return codecWithXrpAlphabet.decode(accountId, opts).bytes
}
export const decodeAddress = decodeAccountID
export function decodeNodePublic(base58string: string): Buffer {
const opts = { versions: [NODE_PUBLIC], expectedLength: 33 }
return codecWithXrpAlphabet.decode(base58string, opts).bytes
}
export function encodeNodePublic(bytes: Buffer): string {
const opts = { versions: [NODE_PUBLIC], expectedLength: 33 }
return codecWithXrpAlphabet.encode(bytes, opts)
}
export function encodeAccountPublic(bytes: Buffer): string {
const opts = { versions: [ACCOUNT_PUBLIC_KEY], expectedLength: 33 }
return codecWithXrpAlphabet.encode(bytes, opts)
}
export function decodeAccountPublic(base58string: string): Buffer {
const opts = { versions: [ACCOUNT_PUBLIC_KEY], expectedLength: 33 }
return codecWithXrpAlphabet.decode(base58string, opts).bytes
}
export function isValidClassicAddress(address: string): boolean {
try {
decodeAccountID(address)
} catch (e) {
return false
}
return true
}

View File

@@ -1,19 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "es6",
"lib": [
"es2017"
],
"rootDir": "./src",
"outDir": "./dist",
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": false,
"preserveConstEnums": false,
"suppressImplicitAnyIndexErrors": false,
"skipLibCheck": true,
"declaration": true
},
"include": ["src/**/*.ts"]
}

View File

@@ -1,4 +0,0 @@
node_modules
dist
.github
coverage

View File

@@ -1,124 +0,0 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser', // Make ESLint compatible with TypeScript
parserOptions: {
// Enable linting rules with type information from our tsconfig
tsconfigRootDir: __dirname,
project: ['./tsconfig.eslint.json'],
sourceType: 'module', // Allow the use of imports / ES modules
ecmaFeatures: {
impliedStrict: true, // Enable global strict mode
},
},
// Specify global variables that are predefined
env: {
browser: true, // Enable browser global variables
node: true, // Enable node global variables & Node.js scoping
es2020: true, // Add all ECMAScript 2020 globals and automatically set the ecmaVersion parser option to ES2020
jest: true, // Add Mocha testing global variables
},
plugins: [],
extends: ['@xrplf/eslint-config/base'],
rules: {
// ** TODO **
// all of the below are turned off for now during the migration to a
// monorepo. They need to actually be addressed!
// **
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/prefer-readonly': 'off',
'@typescript-eslint/no-parameter-properties': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/restrict-plus-operands': 'off',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-base-to-string': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/promise-function-async': 'off',
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/no-magic-numbers': 'off',
'@typescript-eslint/no-useless-constructor': 'off',
'@typescript-eslint/no-unnecessary-condition': 'off',
'@typescript-eslint/consistent-type-assertions': 'off',
'@typescript-eslint/prefer-for-of': 'off',
'@typescript-eslint/prefer-nullish-coalescing': 'off',
'@typescript-eslint/require-array-sort-compare': 'off',
'@typescript-eslint/prefer-includes': 'off',
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/no-type-alias': 'off',
'@typescript-eslint/member-ordering': 'off',
'@typescript-eslint/prefer-string-starts-ends-with': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-extraneous-class': 'off',
'@typescript-eslint/consistent-type-assertions': 'off',
'import/unambiguous': 'off',
'import/extensions': 'off',
'import/prefer-default-export': 'off',
'import/no-useless-path-segments': 'off',
'import/no-unused-modules': 'off',
'import/no-cycle': 'off',
'import/order': 'off',
'import/no-commonjs': 'off',
'import/newline-after-import': 'off',
'node/global-require': 'off',
'consistent-default-export-name/default-import-match-filename': 'off',
'jsdoc/require-throws': 'off',
'jsdoc/require-description-complete-sentence': 'off',
'jsdoc/require-jsdoc': 'off',
'jsdoc/check-tag-names': 'off',
'jsdoc/require-returns': 'off',
'jsdoc/require-hyphen-before-param-description': 'off',
'jsdoc/require-description': 'off',
'jsdoc/require-param': 'off',
'jsdoc/check-param-names': 'off',
'jsdoc/newline-after-description': 'off',
'jsdoc/require-returns-check': 'off',
'tsdoc/syntax': 'off',
'eslint-comments/require-description': 'off',
'eslint-comments/no-unused-disable': 'off',
'prefer-const': 'off',
'global-require': 'off',
'id-length': 'off',
'no-shadow': 'off',
'no-bitwise': 'off',
'spaced-comment': 'off',
'prefer-template': 'off',
'prefer-object-spread': 'off',
'no-inline-comments': 'off',
'no-plusplus': 'off',
'new-cap': 'off',
'id-blacklist': 'off',
'max-lines-per-function': 'off',
'require-unicode-regexp': 'off',
'no-undef-init': 'off',
'curly': 'off',
'eqeqeq': 'off',
'no-console': 'off',
'max-classes-per-file': 'off',
'operator-assignment': 'off',
'class-methods-use-this': 'off',
'no-else-return': 'off',
'yoda': 'off',
'max-depth': 'off',
'multiline-comment-style': 'off',
'one-var': 'off',
'no-negated-condition': 'off',
'radix': 'off',
'no-nested-ternary': 'off',
'no-useless-concat': 'off',
'object-shorthand': 'off',
'no-param-reassign': 'off',
},
}

View File

@@ -1,64 +0,0 @@
# .gitignore
# Ignore vim swap files.
*.swp
# Ignore SCons support files.
.sconsign.dblite
# Ignore python compiled files.
*.pyc
# Ignore Macintosh Desktop Services Store files.
.DS_Store
# Ignore backup/temps
*~
# Ignore object files.
*.o
build/
distrib/
tags
bin/rippled
Debug/*.*
Release/*.*
# Ignore locally installed node_modules
node_modules
!test/node_modules
# Ignore tmp directory.
tmp
# Ignore database directory.
db/*.db
db/*.db-*
# Ignore customized configs
rippled.cfg
validators.txt
test/config.js
# Ignore coverage files
/lib-cov
/src-cov
/coverage.html
/coverage
# Ignore IntelliJ files
.idea
# Ignore npm-debug
npm-debug.log
# Ignore dist folder, build for bower
dist/
# Ignore flow output directory
out/
# Ignore perf test cache
scripts/cache
eslintrc

View File

@@ -1 +0,0 @@
10.22.0

View File

@@ -1,90 +0,0 @@
# ripple-binary-codec Release History
## 1.1.3 (2021-06-11)
- Fix for case UInt64.from string allowing lowercase hex (#135)
- Fix for `ValidatorToReEnable` field code (#130)
## 1.1.2 (2021-03-10)
- Fix for case UInt64.from string '0' due to changes in rippled 1.7.0
## 1.1.1 (2021-02-12)
- PathSet.toJSON() does not return undefined values
- Add support for X-Addresses in Issued Currency Amounts
- Fix STArray error message
## 1.1.0 (2020-12-03)
- Add support for Tickets (TicketBatch amendment)
- Fix web browser compatibility
## 1.0.2 (2020-09-11)
- Allow currencies to be encoded from any 3 character ASCII code
## 1.0.1 (2020-09-08)
- Filter out fields with undefined values
## 1.0.0 (2020-08-17)
- Migrate to TypeScript
- Javascript classes used
- Generics for constructing core types
- Reduced dependencies
- Dependent on create-hash, decimal.js, ripple-address-codec
- Migrate testing to Jest and added tests
- Tests for pseudo-transactions
- Added support for NegativeUNL pseudo-transactions
## 0.2.6 (2019-12-31)
- Update dependencies
- decimal.js, fs-extra, mocha, handlebars, bn.js, babel-eslint, ripple-address-codec
## 0.2.5 (2019-12-14)
- Add support for AccountDelete (#37)
## 0.2.4 (2019-09-04)
- Update ripple-address-codec to 3.0.4
## 0.2.3 (2019-08-29)
- Expand node version compatibility (#32, #33)
## 0.2.2 (2019-07-26)
- Input validation - Amount and Fee should not allow fractional XRP drops ([#31](https://github.com/ripple/ripple-binary-codec/issues/31))
- Fix lint errors
- Update dependencies (including lodash and mocha)
- Require node 10 (.nvmrc)
- Remove assert-diff
- Remove codecov.io as it did not appear to work. The `package.json` script was:
- `"codecov": "cat ./coverage/coverage.json | ./node_modules/codecov.io/bin/codecov.io.js"`
## 0.2.1
- Add tecKILLED from amendment fix1578 (PR #27 fixes #25)
## 0.2.0
- Add DepositPreauth fields
- https://developers.ripple.com/depositauth.html
## 0.1.14
- Skip amount validation when deserializing f72c115
## 0.1.13
- Add Check, CheckCreate, CheckCash, CheckCancel
## 0.1.11
- Add ledger header decode function
## 0.1.8
## 0.1.7
## 0.1.6
## 0.1.3

View File

@@ -1,13 +0,0 @@
Copyright (c) 2015 Ripple Labs Inc.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -1,107 +0,0 @@
# ripple-binary-codec [![NPM](https://img.shields.io/npm/v/ripple-binary-codec.svg)](https://npmjs.org/package/ripple-binary-codec)
Functions to encode/decode to/from the ripple [binary serialization format](https://xrpl.org/serialization.html)
[![NPM](https://nodei.co/npm/ripple-binary-codec.png)](https://www.npmjs.org/package/ripple-binary-codec)
## API
```js
> const api = require('ripple-binary-codec')
```
### decode(binary: string): object
Decode a hex-string into a transaction object.
```js
> api.decode('1100612200000000240000000125000000072D0000000055DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF6240000002540BE4008114D0F5430B66E06498D4CEEC816C7B3337F9982337')
{
LedgerEntryType: 'AccountRoot',
Flags: 0,
Sequence: 1,
PreviousTxnLgrSeq: 7,
OwnerCount: 0,
PreviousTxnID: 'DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF',
Balance: '10000000000',
Account: 'rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv'
}
```
### encode(json: object): string
Encode a transaction object into a hex-string. Note that encode filters out fields with undefined values.
```js
> api.encode({
LedgerEntryType: 'AccountRoot',
Flags: 0,
Sequence: 1,
PreviousTxnLgrSeq: 7,
OwnerCount: 0,
PreviousTxnID: 'DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF',
Balance: '10000000000',
Account: 'rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv'
})
'1100612200000000240000000125000000072D0000000055DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF6240000002540BE4008114D0F5430B66E06498D4CEEC816C7B3337F9982337'
```
#### X-Address Compatibility
* ripple-binary-codec handles X-addresses by looking for a few specific files (Account/SourceTag, Destination/DestinationTag).
* If other fields (in the future) must to support X-addresses with tags, this library will need to be updated.
* When decoding rippled binary, the output will always output classic address + tag, with no X-addresses. X-address support only applies when encoding to binary.
#### Encoding Currency Codes
* The standard format for currency codes is a three-letter string such as `USD`. This is intended for use with ISO 4217 Currency Codes.
* Currency codes must be exactly 3 ASCII characters in length and there are [a few other rules](https://xrpl.org/currency-formats.html#currency-codes).
* ripple-binary-codec allows any 3-character ASCII string to be encoded as a currency code, although rippled may enforce tighter restrictions.
* When _decoding_, if a currency code is three uppercase letters or numbers (`/^[A-Z0-9]{3}$/`), then it will be decoded into that string. For example,`0000000000000000000000004142430000000000` decodes as `ABC`.
* When decoding, if a currency code is does not match the regex, then it is not considered to be an ISO 4217 or pseudo-ISO currency. ripple-binary-codec will return a 160-bit hex-string (40 hex characters). For example, `0000000000000000000000006142430000000000` (`aBC`) decodes as `0000000000000000000000006142430000000000` because it contains a lowercase letter.
### encodeForSigning(json: object): string
Encode the transaction object for signing.
### encodeForSigningClaim(json: object): string
Encode the transaction object for payment channel claim.
### encodeForMultisigning(json: object, signer: string): string
Encode the transaction object for multi-signing.
### encodeQuality(value: string): string
```js
> api.encodeQuality('195796912.5171664')
'5D06F4C3362FE1D0'
```
### decodeQuality(value: string): string
```js
> api.decodeQuality('5D06F4C3362FE1D0')
'195796912.5171664'
```
### decodeLedgerData(binary: string): object
```js
> api.decodeLedgerData("01E91435016340767BF1C4A3EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F873B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D521276CDE21276CE60A00")
{
ledger_index: 32052277,
total_coins: '99994494362043555',
parent_hash: 'EACEB081770D8ADE216C85445DD6FB002C6B5A2930F2DECE006DA18150CB18F6',
transaction_hash: 'DD33F6F0990754C962A7CCE62F332FF9C13939B03B864117F0BDA86B6E9B4F87',
account_hash: '3B5C3E520634D343EF5D9D9A4246643D64DAD278BA95DC0EAC6EB5350CF970D5',
parent_close_time: 556231902,
close_time: 556231910,
close_time_resolution: 10,
close_flags: 0
}
```
## Tests
Run unit tests with:
npm test
Use `--coverage` to generate and display code coverage information:
npm test --coverage
This tells jest to output code coverage info in the `./coverage` directory, in addition to showing it on the command line.

View File

@@ -1,44 +0,0 @@
{
"name": "ripple-binary-codec",
"version": "1.2.0",
"description": "XRP Ledger binary codec",
"files": [
"dist/*",
"bin/*",
"test/*"
],
"main": "dist/",
"directories": {
"test": "test"
},
"dependencies": {
"assert": "^2.0.0",
"big-integer": "^1.6.48",
"buffer": "5.6.0",
"create-hash": "^1.2.0",
"decimal.js": "^10.2.0",
"ripple-address-codec": "^4.2.0"
},
"scripts": {
"build": "tsc -b && cp ./src/enums/definitions.json ./dist/enums",
"clean": "rm -rf ./dist && rm -rf tsconfig.tsbuildinfo",
"prepare": "npm run build && npm test",
"test": "jest",
"lint": "eslint . --ext .ts --ext .test.js"
},
"repository": {
"type": "git",
"url": "git@github.com:XRPLF/xrpl.js.git"
},
"bugs": {
"url": "https://github.com/XRPLF/xrpl.js/issues"
},
"homepage": "https://github.com/XRPLF/xrpl.js/packages/ripple-binary-codec#readme",
"license": "ISC",
"readmeFilename": "README.md",
"prettier": "@xrplf/prettier-config",
"engines": {
"node": ">=10.22.0",
"npm": ">=7.0.0"
}
}

View File

@@ -1,3 +0,0 @@
# ripple-binary-codec
Serialize and deserialize transactions according to the XRP Ledger protocol.

View File

@@ -1,154 +0,0 @@
/* eslint-disable func-style */
import { coreTypes } from './types'
import { BinaryParser } from './serdes/binary-parser'
import { AccountID } from './types/account-id'
import { HashPrefix } from './hash-prefixes'
import { BinarySerializer, BytesList } from './serdes/binary-serializer'
import { sha512Half, transactionID } from './hashes'
import { FieldInstance } from './enums'
import { STObject } from './types/st-object'
import { JsonObject } from './types/serialized-type'
import { Buffer } from 'buffer/'
import * as bigInt from 'big-integer'
/**
* Construct a BinaryParser
*
* @param bytes hex-string to construct BinaryParser from
* @returns A BinaryParser
*/
const makeParser = (bytes: string): BinaryParser => new BinaryParser(bytes)
/**
* Parse BinaryParser into JSON
*
* @param parser BinaryParser object
* @returns JSON for the bytes in the BinaryParser
*/
const readJSON = (parser: BinaryParser): JsonObject =>
(parser.readType(coreTypes.STObject) as STObject).toJSON()
/**
* Parse a hex-string into its JSON interpretation
*
* @param bytes hex-string to parse into JSON
* @returns JSON
*/
const binaryToJSON = (bytes: string): JsonObject => readJSON(makeParser(bytes))
/**
* Interface for passing parameters to SerializeObject
*
* @field set signingFieldOnly to true if you want to serialize only signing fields
*/
interface OptionObject {
prefix?: Buffer
suffix?: Buffer
signingFieldsOnly?: boolean
}
/**
* Function to serialize JSON object representing a transaction
*
* @param object JSON object to serialize
* @param opts options for serializing, including optional prefix, suffix, and signingFieldOnly
* @returns A Buffer containing the serialized object
*/
function serializeObject(object: JsonObject, opts: OptionObject = {}): Buffer {
const { prefix, suffix, signingFieldsOnly = false } = opts
const bytesList = new BytesList()
if (prefix) {
bytesList.put(prefix)
}
const filter = signingFieldsOnly
? (f: FieldInstance): boolean => f.isSigningField
: undefined
coreTypes.STObject.from(object, filter).toBytesSink(bytesList)
if (suffix) {
bytesList.put(suffix)
}
return bytesList.toBytes()
}
/**
* Serialize an object for signing
*
* @param transaction Transaction to serialize
* @param prefix Prefix bytes to put before the serialized object
* @returns A Buffer with the serialized object
*/
function signingData(
transaction: JsonObject,
prefix: Buffer = HashPrefix.transactionSig,
): Buffer {
return serializeObject(transaction, { prefix, signingFieldsOnly: true })
}
/**
* Interface describing fields required for a Claim
*/
interface ClaimObject extends JsonObject {
channel: string
amount: string | number
}
/**
* Serialize a signingClaim
*
* @param claim A claim object to serialize
* @returns the serialized object with appropriate prefix
*/
function signingClaimData(claim: ClaimObject): Buffer {
const num = bigInt(String(claim.amount))
const prefix = HashPrefix.paymentChannelClaim
const channel = coreTypes.Hash256.from(claim.channel).toBytes()
const amount = coreTypes.UInt64.from(num).toBytes()
const bytesList = new BytesList()
bytesList.put(prefix)
bytesList.put(channel)
bytesList.put(amount)
return bytesList.toBytes()
}
/**
* Serialize a transaction object for multiSigning
*
* @param transaction transaction to serialize
* @param signingAccount Account to sign the transaction with
* @returns serialized transaction with appropriate prefix and suffix
*/
function multiSigningData(
transaction: JsonObject,
signingAccount: string | AccountID,
): Buffer {
const prefix = HashPrefix.transactionMultiSig
const suffix = coreTypes.AccountID.from(signingAccount).toBytes()
return serializeObject(transaction, {
prefix,
suffix,
signingFieldsOnly: true,
})
}
export {
BinaryParser,
BinarySerializer,
BytesList,
ClaimObject,
makeParser,
serializeObject,
readJSON,
multiSigningData,
signingData,
signingClaimData,
binaryToJSON,
sha512Half,
transactionID,
}

View File

@@ -1,29 +0,0 @@
import {
Field,
TransactionType,
LedgerEntryType,
Type,
TransactionResult,
} from './enums'
import * as types from './types'
import * as binary from './binary'
import { ShaMap } from './shamap'
import * as ledgerHashes from './ledger-hashes'
import * as hashes from './hashes'
import { quality } from './quality'
import { HashPrefix } from './hash-prefixes'
export {
hashes,
binary,
ledgerHashes,
Field,
TransactionType,
LedgerEntryType,
Type,
TransactionResult,
quality,
HashPrefix,
ShaMap,
types,
}

View File

@@ -1,60 +0,0 @@
# Definitions
## Types
These are the [types](https://xrpl.org/serialization.html#type-list) associated with a given Serialization Field. Each type has an arbitrary [type_code](https://xrpl.org/serialization.html#type-codes), with lower codes sorting first.
## Ledger Entry Types
Each ledger's state tree contain [ledger objects](https://xrpl.org/ledger-object-types.html), which represent all settings, balances, and relationships in the shared ledger.
## Fields
These are Serialization Fields (`sf`) [defined in rippled's SField.cpp](https://github.com/ripple/rippled/blob/develop/src/ripple/protocol/impl/SField.cpp). Fields with undefined values are omitted before encoding.
### Key
The key is the string defined in the rippled source code, such as "LedgerEntry", "Transaction", etc.
### nth
`nth` is the sort code, meaning "nth of type." It is is combined with the type code in order to construct the Field ID of this field. The Field ID is only used for sorting the fields. Since there are multiple fields with the same data type, the `nth` is used to deterministically order each field among other fields of the same data type.
Each field has a Field ID, which is used to sort fields that have the same type as one another with lower codes sorting first.
- [Field definitions](https://github.com/ripple/rippled/blob/72e6005f562a8f0818bc94803d222ac9345e1e40/src/ripple/protocol/impl/SField.cpp#L72-L266)
- [Constructing the `SField` field codes](https://github.com/ripple/rippled/blob/eaff9a0e6aec0ad077f118501791c7684debcfd5/src/ripple/protocol/SField.h#L95-L98)
For example, the `Account` field has sort code (nth) `1`, so it comes before the `Destination` field which has sort code `3`.
Sort code numbers are reused for fields of different types, but different fields of the same type never have the same sort code. When you combine the type code with the sort code, you get the field's unique _Field ID_.
The unique [Field ID](https://xrpl.org/serialization.html#field-ids) is prefixed before the field in the final serialized blob. The size of the Field ID is one to three bytes depending on the type code and the field codes it combines.
### isVLEncoded
If true, the field is Variable Length encoded and [length-prefixed](https://xrpl.org/serialization.html#length-prefixing). The variable-length encoded fields are `STI_VL`/`Blob`, `STI_ACCOUNT`/`AccountID`, and `STI_VECTOR256`/`Vector256`.
### isSerialized
Fields are serialized if they are not [one of these](https://github.com/ripple/rippled/blob/eaff9a0e6aec0ad077f118501791c7684debcfd5/src/ripple/protocol/impl/SField.cpp#L71-L78) or if they are not an SField.
- https://github.com/ripple/ripple-binary-codec/blob/14e76e68ead7e4bcd83c942dbdc9064d5a66869b/src/enums/definitions.json#L832
- https://github.com/ripple/rippled/search?utf8=%E2%9C%93&q=taker_gets_funded&type=
### isSigningField
True unless the field is [specified with `SField::notSigning`](https://github.com/ripple/rippled/blob/eaff9a0e6aec0ad077f118501791c7684debcfd5/src/ripple/protocol/impl/SField.cpp#L198).
## Transaction Results
See:
- https://github.com/ripple/rippled/blob/develop/src/ripple/protocol/TER.h
- https://xrpl.org/transaction-results.html
TODO: Write a script to read rippled's source file and generate the necessary mapping.
## Transaction Types
See https://github.com/ripple/rippled/blob/develop/src/ripple/protocol/TxFormats.h

File diff suppressed because it is too large Load Diff

View File

@@ -1,156 +0,0 @@
import * as enums from './definitions.json'
import { SerializedType } from '../types/serialized-type'
import { Buffer } from 'buffer/'
const TYPE_WIDTH = 2
const LEDGER_ENTRY_WIDTH = 2
const TRANSACTION_TYPE_WIDTH = 2
const TRANSACTION_RESULT_WIDTH = 1
/*
* @brief: Serialize a field based on type_code and Field.nth
*/
function fieldHeader(type: number, nth: number): Buffer {
const header: Array<number> = []
if (type < 16) {
if (nth < 16) {
header.push((type << 4) | nth)
} else {
header.push(type << 4, nth)
}
} else if (nth < 16) {
header.push(nth, type)
} else {
header.push(0, type, nth)
}
return Buffer.from(header)
}
/*
* @brief: Bytes, name, and ordinal representing one type, ledger_type, transaction type, or result
*/
class Bytes {
readonly bytes: Uint8Array
constructor(
readonly name: string,
readonly ordinal: number,
readonly ordinalWidth: number,
) {
this.bytes = Buffer.alloc(ordinalWidth)
for (let i = 0; i < ordinalWidth; i++) {
this.bytes[ordinalWidth - i - 1] = (ordinal >>> (i * 8)) & 0xff
}
}
toJSON(): string {
return this.name
}
toBytesSink(sink): void {
sink.put(this.bytes)
}
toBytes(): Uint8Array {
return this.bytes
}
}
/*
* @brief: Collection of Bytes objects, mapping bidirectionally
*/
class BytesLookup {
constructor(types: Record<string, number>, readonly ordinalWidth: number) {
Object.entries(types).forEach(([k, v]) => {
this[k] = new Bytes(k, v, ordinalWidth)
this[v.toString()] = this[k]
})
}
from(value: Bytes | string): Bytes {
return value instanceof Bytes ? value : (this[value] as Bytes)
}
fromParser(parser): Bytes {
return this.from(parser.readUIntN(this.ordinalWidth).toString())
}
}
/*
* type FieldInfo is the type of the objects containing information about each field in definitions.json
*/
interface FieldInfo {
nth: number
isVLEncoded: boolean
isSerialized: boolean
isSigningField: boolean
type: string
}
interface FieldInstance {
readonly nth: number
readonly isVariableLengthEncoded: boolean
readonly isSerialized: boolean
readonly isSigningField: boolean
readonly type: Bytes
readonly ordinal: number
readonly name: string
readonly header: Buffer
readonly associatedType: typeof SerializedType
}
function buildField([name, info]: [string, FieldInfo]): FieldInstance {
const typeOrdinal = enums.TYPES[info.type]
const field = fieldHeader(typeOrdinal, info.nth)
return {
name: name,
nth: info.nth,
isVariableLengthEncoded: info.isVLEncoded,
isSerialized: info.isSerialized,
isSigningField: info.isSigningField,
ordinal: (typeOrdinal << 16) | info.nth,
type: new Bytes(info.type, typeOrdinal, TYPE_WIDTH),
header: field,
associatedType: SerializedType, // For later assignment in ./types/index.js
}
}
/*
* @brief: The collection of all fields as defined in definitions.json
*/
class FieldLookup {
constructor(fields: Array<[string, FieldInfo]>) {
fields.forEach(([k, v]) => {
this[k] = buildField([k, v])
this[this[k].ordinal.toString()] = this[k]
})
}
fromString(value: string): FieldInstance {
return this[value] as FieldInstance
}
}
const Type = new BytesLookup(enums.TYPES, TYPE_WIDTH)
const LedgerEntryType = new BytesLookup(
enums.LEDGER_ENTRY_TYPES,
LEDGER_ENTRY_WIDTH,
)
const TransactionType = new BytesLookup(
enums.TRANSACTION_TYPES,
TRANSACTION_TYPE_WIDTH,
)
const TransactionResult = new BytesLookup(
enums.TRANSACTION_RESULTS,
TRANSACTION_RESULT_WIDTH,
)
const Field = new FieldLookup(enums.FIELDS as Array<[string, FieldInfo]>)
export {
Field,
FieldInstance,
Type,
LedgerEntryType,
TransactionResult,
TransactionType,
}

View File

@@ -1,134 +0,0 @@
/**
* Quick script to re-number values
*/
const input = {
temBAD_SEND_XRP_PATHS: -283,
temBAD_SEQUENCE: -282,
temBAD_SIGNATURE: -281,
temBAD_SRC_ACCOUNT: -280,
temBAD_TRANSFER_RATE: -279,
temDST_IS_SRC: -278,
temDST_NEEDED: -277,
temINVALID: -276,
temINVALID_FLAG: -275,
temREDUNDANT: -274,
temRIPPLE_EMPTY: -273,
temDISABLED: -272,
temBAD_SIGNER: -271,
temBAD_QUORUM: -270,
temBAD_WEIGHT: -269,
temBAD_TICK_SIZE: -268,
temINVALID_ACCOUNT_ID: -267,
temCANNOT_PREAUTH_SELF: -266,
temUNCERTAIN: -265,
temUNKNOWN: -264,
tefFAILURE: -199,
tefALREADY: -198,
tefBAD_ADD_AUTH: -197,
tefBAD_AUTH: -196,
tefBAD_LEDGER: -195,
tefCREATED: -194,
tefEXCEPTION: -193,
tefINTERNAL: -192,
tefNO_AUTH_REQUIRED: -191,
tefPAST_SEQ: -190,
tefWRONG_PRIOR: -189,
tefMASTER_DISABLED: -188,
tefMAX_LEDGER: -187,
tefBAD_SIGNATURE: -186,
tefBAD_QUORUM: -185,
tefNOT_MULTI_SIGNING: -184,
tefBAD_AUTH_MASTER: -183,
tefINVARIANT_FAILED: -182,
tefTOO_BIG: -181,
terRETRY: -99,
terFUNDS_SPENT: -98,
terINSUF_FEE_B: -97,
terNO_ACCOUNT: -96,
terNO_AUTH: -95,
terNO_LINE: -94,
terOWNERS: -93,
terPRE_SEQ: -92,
terLAST: -91,
terNO_RIPPLE: -90,
terQUEUED: -89,
tesSUCCESS: 0,
tecCLAIM: 100,
tecPATH_PARTIAL: 101,
tecUNFUNDED_ADD: 102,
tecUNFUNDED_OFFER: 103,
tecUNFUNDED_PAYMENT: 104,
tecFAILED_PROCESSING: 105,
tecDIR_FULL: 121,
tecINSUF_RESERVE_LINE: 122,
tecINSUF_RESERVE_OFFER: 123,
tecNO_DST: 124,
tecNO_DST_INSUF_XRP: 125,
tecNO_LINE_INSUF_RESERVE: 126,
tecNO_LINE_REDUNDANT: 127,
tecPATH_DRY: 128,
tecUNFUNDED: 129,
tecNO_ALTERNATIVE_KEY: 130,
tecNO_REGULAR_KEY: 131,
tecOWNERS: 132,
tecNO_ISSUER: 133,
tecNO_AUTH: 134,
tecNO_LINE: 135,
tecINSUFF_FEE: 136,
tecFROZEN: 137,
tecNO_TARGET: 138,
tecNO_PERMISSION: 139,
tecNO_ENTRY: 140,
tecINSUFFICIENT_RESERVE: 141,
tecNEED_MASTER_KEY: 142,
tecDST_TAG_NEEDED: 143,
tecINTERNAL: 144,
tecOVERSIZE: 145,
tecCRYPTOCONDITION_ERROR: 146,
tecINVARIANT_FAILED: 147,
tecEXPIRED: 148,
tecDUPLICATE: 149,
tecKILLED: 150,
tecHAS_OBLIGATIONS: 151,
tecTOO_SOON: 152,
}
let startingFromTemBADSENDXRPPATHS = -284
let startingFromTefFAILURE = -199
let startingFromTerRETRY = -99
const tesSUCCESS = 0
let startingFromTecCLAIM = 100
const startingFromTecDIRFULL = 121
let previousKey = 'tem'
Object.keys(input).forEach((key) => {
if (key.substring(0, 3) !== previousKey.substring(0, 3)) {
console.log()
previousKey = key
}
if (key.substring(0, 3) === 'tem') {
console.log(` "${key}": ${startingFromTemBADSENDXRPPATHS++},`)
} else if (key.substring(0, 3) === 'tef') {
console.log(` "${key}": ${startingFromTefFAILURE++},`)
} else if (key.substring(0, 3) === 'ter') {
console.log(` "${key}": ${startingFromTerRETRY++},`)
} else if (key.substring(0, 3) === 'tes') {
console.log(` "${key}": ${tesSUCCESS},`)
} else if (key.substring(0, 3) === 'tec') {
if (key === 'tecDIR_FULL') {
startingFromTecCLAIM = startingFromTecDIRFULL
}
console.log(` "${key}": ${startingFromTecCLAIM++},`)
}
})

View File

@@ -1,40 +0,0 @@
import { Buffer } from 'buffer/'
/**
* Write a 32 bit integer to a Buffer
*
* @param uint32 32 bit integer to write to buffer
* @returns a buffer with the bytes representation of uint32
*/
function bytes(uint32: number): Buffer {
const result = Buffer.alloc(4)
result.writeUInt32BE(uint32, 0)
return result
}
/**
* Maps HashPrefix names to their byte representation
*/
const HashPrefix: Record<string, Buffer> = {
transactionID: bytes(0x54584e00),
// transaction plus metadata
transaction: bytes(0x534e4400),
// account state
accountStateEntry: bytes(0x4d4c4e00),
// inner node in tree
innerNode: bytes(0x4d494e00),
// ledger master data for signing
ledgerHeader: bytes(0x4c575200),
// inner transaction to sign
transactionSig: bytes(0x53545800),
// inner transaction to sign
transactionMultiSig: bytes(0x534d5400),
// validation for signing
validation: bytes(0x56414c00),
// proposal for signing
proposal: bytes(0x50525000),
// payment channel claim
paymentChannelClaim: bytes(0x434c4d00),
}
export { HashPrefix }

View File

@@ -1,77 +0,0 @@
import { HashPrefix } from './hash-prefixes'
import * as createHash from 'create-hash'
import { Hash256 } from './types/hash-256'
import { BytesList } from './serdes/binary-serializer'
import { Buffer } from 'buffer/'
/**
* Class for hashing with SHA512
* @extends BytesList So SerializedTypes can write bytes to a Sha512Half
*/
class Sha512Half extends BytesList {
private hash: createHash = createHash('sha512')
/**
* Construct a new Sha512Hash and write bytes this.hash
*
* @param bytes bytes to write to this.hash
* @returns the new Sha512Hash object
*/
static put(bytes: Buffer): Sha512Half {
return new Sha512Half().put(bytes)
}
/**
* Write bytes to an existing Sha512Hash
*
* @param bytes bytes to write to object
* @returns the Sha512 object
*/
put(bytes: Buffer): Sha512Half {
this.hash.update(bytes)
return this
}
/**
* Compute SHA512 hash and slice in half
*
* @returns half of a SHA512 hash
*/
finish256(): Buffer {
const bytes: Buffer = this.hash.digest()
return bytes.slice(0, 32)
}
/**
* Constructs a Hash256 from the Sha512Half object
*
* @returns a Hash256 object
*/
finish(): Hash256 {
return new Hash256(this.finish256())
}
}
/**
* compute SHA512 hash of a list of bytes
*
* @param args zero or more arguments to hash
* @returns the sha512half hash of the arguments.
*/
function sha512Half(...args: Buffer[]): Buffer {
const hash = new Sha512Half()
args.forEach((a) => hash.put(a))
return hash.finish256()
}
/**
* Construct a transactionID from a Serialized Transaction
*
* @param serialized bytes to hash
* @returns a Hash256 object
*/
function transactionID(serialized: Buffer): Hash256 {
return new Hash256(sha512Half(HashPrefix.transactionID, serialized))
}
export { Sha512Half, sha512Half, transactionID }

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